mirror of
https://github.com/reactos/reactos.git
synced 2025-05-21 01:54:21 +00:00
3042 lines
56 KiB
C
3042 lines
56 KiB
C
/*
|
||
* FFS File System Driver for Windows
|
||
*
|
||
* ffs.c
|
||
*
|
||
* 2004.5.6 ~
|
||
*
|
||
* Lee Jae-Hong, http://www.pyrasis.com
|
||
*
|
||
* See License.txt
|
||
*
|
||
*/
|
||
|
||
#include "ntifs.h"
|
||
#include "ffsdrv.h"
|
||
|
||
|
||
/* Globals */
|
||
extern PFFS_GLOBAL FFSGlobal;
|
||
|
||
|
||
/* Definitions */
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, FFSLoadSuper)
|
||
#pragma alloc_text(PAGE, FFSSaveSuper)
|
||
|
||
#pragma alloc_text(PAGE, FFSLoadGroup)
|
||
#pragma alloc_text(PAGE, FFSSaveGroup)
|
||
|
||
#pragma alloc_text(PAGE, FFSv1GetInodeLba)
|
||
#pragma alloc_text(PAGE, FFSv2GetInodeLba)
|
||
#pragma alloc_text(PAGE, FFSv1LoadInode)
|
||
#pragma alloc_text(PAGE, FFSv2LoadInode)
|
||
#pragma alloc_text(PAGE, FFSv1SaveInode)
|
||
#pragma alloc_text(PAGE, FFSv2SaveInode)
|
||
|
||
#pragma alloc_text(PAGE, FFSv1LoadBlock)
|
||
#pragma alloc_text(PAGE, FFSv2LoadBlock)
|
||
#pragma alloc_text(PAGE, FFSSaveBlock)
|
||
|
||
#pragma alloc_text(PAGE, FFSSaveBuffer)
|
||
|
||
#pragma alloc_text(PAGE, FFSv1GetBlock)
|
||
#pragma alloc_text(PAGE, FFSv2GetBlock)
|
||
#pragma alloc_text(PAGE, FFSv1BlockMap)
|
||
#pragma alloc_text(PAGE, FFSv2BlockMap)
|
||
|
||
#pragma alloc_text(PAGE, FFSv1BuildBDL)
|
||
#pragma alloc_text(PAGE, FFSv2BuildBDL)
|
||
|
||
#pragma alloc_text(PAGE, FFSNewBlock)
|
||
#pragma alloc_text(PAGE, FFSFreeBlock)
|
||
|
||
#pragma alloc_text(PAGE, FFSExpandBlock)
|
||
#pragma alloc_text(PAGE, FFSExpandInode)
|
||
|
||
#pragma alloc_text(PAGE, FFSNewInode)
|
||
#pragma alloc_text(PAGE, FFSFreeInode)
|
||
|
||
#pragma alloc_text(PAGE, FFSAddEntry)
|
||
#pragma alloc_text(PAGE, FFSRemoveEntry)
|
||
|
||
#pragma alloc_text(PAGE, FFSTruncateBlock)
|
||
#pragma alloc_text(PAGE, FFSTruncateInode)
|
||
|
||
#pragma alloc_text(PAGE, FFSAddMcbEntry)
|
||
#pragma alloc_text(PAGE, FFSRemoveMcbEntry)
|
||
#pragma alloc_text(PAGE, FFSLookupMcbEntry)
|
||
|
||
#endif
|
||
|
||
|
||
PFFS_SUPER_BLOCK
|
||
FFSLoadSuper(
|
||
IN PFFS_VCB Vcb,
|
||
IN BOOLEAN bVerify,
|
||
IN ULONGLONG SuperBlockOffset)
|
||
{
|
||
NTSTATUS Status;
|
||
PFFS_SUPER_BLOCK FFSSb = NULL;
|
||
|
||
PAGED_CODE();
|
||
|
||
FFSSb = (PFFS_SUPER_BLOCK)ExAllocatePoolWithTag(PagedPool, SUPER_BLOCK_SIZE, FFS_POOL_TAG);
|
||
if (!FFSSb)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
Status = FFSReadDisk(Vcb,
|
||
SuperBlockOffset,
|
||
SUPER_BLOCK_SIZE,
|
||
(PVOID)FFSSb,
|
||
bVerify);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSLoadSuper: Read Block Device error.\n"));
|
||
|
||
ExFreePool(FFSSb);
|
||
return NULL;
|
||
}
|
||
|
||
return FFSSb;
|
||
}
|
||
|
||
#if !FFS_READ_ONLY
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
BOOLEAN
|
||
FFSSaveSuper(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb)
|
||
{
|
||
LONGLONG Offset;
|
||
BOOLEAN bRet;
|
||
|
||
PAGED_CODE();
|
||
|
||
Offset = (LONGLONG) SUPER_BLOCK_OFFSET;
|
||
|
||
bRet = FFSSaveBuffer(IrpContext,
|
||
Vcb,
|
||
Offset,
|
||
SUPER_BLOCK_SIZE,
|
||
Vcb->ffs_super_block);
|
||
|
||
if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK))
|
||
{
|
||
FFSStartFloppyFlushDpc(Vcb, NULL, NULL);
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
#endif // !FFS_READ_ONLY
|
||
|
||
#if 0
|
||
BOOLEAN
|
||
FFSLoadGroup(
|
||
IN PFFS_VCB Vcb)
|
||
{
|
||
ULONG Size;
|
||
PVOID Buffer;
|
||
LONGLONG Lba;
|
||
NTSTATUS Status;
|
||
|
||
PFFS_SUPER_BLOCK FFSSb;
|
||
|
||
PAGED_CODE();
|
||
|
||
FFSSb = Vcb->ffs_super_block;
|
||
|
||
Vcb->BlockSize = FFSSb->fs_bsize;
|
||
Vcb->SectorBits = FFSLog2(SECTOR_SIZE);
|
||
ASSERT(BLOCK_BITS == FFSLog2(BLOCK_SIZE));
|
||
|
||
Vcb->ffs_groups = (FFSSb->s_blocks_count - FFSSb->s_first_data_block +
|
||
FFSSb->s_blocks_per_group - 1) / FFSSb->s_blocks_per_group;
|
||
|
||
Size = sizeof(FFS_GROUP_DESC) * Vcb->ffs_groups;
|
||
|
||
if (Vcb->BlockSize == MINBSIZE)
|
||
{
|
||
Lba = (LONGLONG)2 * Vcb->BlockSize;
|
||
}
|
||
|
||
if (Vcb->BlockSize > MINBSIZE)
|
||
{
|
||
Lba = (LONGLONG)(Vcb->BlockSize);
|
||
}
|
||
|
||
if (Lba == 0)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
Buffer = ExAllocatePoolWithTag(PagedPool, Size, FFS_POOL_TAG);
|
||
if (!Buffer)
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSLoadSuper: no enough memory.\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
FFSPrint((DBG_INFO, "FFSLoadGroup: Lba=%I64xh Size=%xh\n", Lba, Size));
|
||
|
||
Status = FFSReadDisk(Vcb,
|
||
Lba,
|
||
Size,
|
||
Buffer,
|
||
FALSE);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
ExFreePool(Buffer);
|
||
Buffer = NULL;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
Vcb->ffs_group_desc = (PFFS_GROUP_DESC) Buffer;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FFSSaveGroup(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb)
|
||
{
|
||
LONGLONG Offset;
|
||
ULONG Len;
|
||
BOOLEAN bRet;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (Vcb->BlockSize == FFS_MIN_BLOCK) {
|
||
|
||
Offset = (LONGLONG)(2 * Vcb->BlockSize);
|
||
|
||
} else {
|
||
|
||
Offset = (LONGLONG)(Vcb->BlockSize);
|
||
}
|
||
|
||
Len = (ULONG)(sizeof(struct ffs_group_desc) * Vcb->ffs_groups);
|
||
|
||
bRet = FFSSaveBuffer(IrpContext, Vcb, Offset,
|
||
Len, Vcb->ffs_group_desc);
|
||
|
||
if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK))
|
||
{
|
||
FFSStartFloppyFlushDpc(Vcb, NULL, NULL);
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
#endif
|
||
|
||
|
||
BOOLEAN
|
||
FFSv1GetInodeLba(
|
||
IN PFFS_VCB Vcb,
|
||
IN ULONG inode,
|
||
OUT PLONGLONG offset)
|
||
{
|
||
LONGLONG loc;
|
||
|
||
PAGED_CODE();
|
||
|
||
#if 0
|
||
if (inode < 1 || inode > INODES_COUNT)
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSv1GetInodeLba: Inode value %xh is invalid.\n",inode));
|
||
*offset = 0;
|
||
return FALSE;
|
||
}
|
||
#endif
|
||
|
||
loc = cgimin(Vcb->ffs_super_block, ino_to_cg(Vcb->ffs_super_block, inode))
|
||
* Vcb->ffs_super_block->fs_fsize + ((inode % Vcb->ffs_super_block->fs_ipg) * 128);
|
||
|
||
*offset = loc;
|
||
KdPrint(("FFSv1GetInodeLba() inode : %d, loc : %x, offset : %x\n", inode, loc, offset));
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FFSv2GetInodeLba(
|
||
IN PFFS_VCB Vcb,
|
||
IN ULONG inode,
|
||
OUT PLONGLONG offset)
|
||
{
|
||
LONGLONG loc;
|
||
|
||
PAGED_CODE();
|
||
|
||
#if 0
|
||
if (inode < 1 || inode > INODES_COUNT)
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSv2GetInodeLba: Inode value %xh is invalid.\n",inode));
|
||
*offset = 0;
|
||
return FALSE;
|
||
}
|
||
#endif
|
||
|
||
loc = cgimin(Vcb->ffs_super_block, ino_to_cg(Vcb->ffs_super_block, inode))
|
||
* Vcb->ffs_super_block->fs_fsize + ((inode % Vcb->ffs_super_block->fs_ipg) * 256);
|
||
|
||
*offset = loc;
|
||
//KdPrint(("FFSv2GetInodeLba() inode : %d, loc : %x, offset : %x\n", inode, loc, offset));
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FFSv1LoadInode(
|
||
IN PFFS_VCB Vcb,
|
||
IN ULONG inode,
|
||
IN PFFSv1_INODE dinode1)
|
||
{
|
||
IO_STATUS_BLOCK IoStatus;
|
||
LONGLONG Offset;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (!FFSv1GetInodeLba(Vcb, inode, &Offset))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSv1LoadInode: error get inode(%xh)'s addr.\n", inode));
|
||
return FALSE;
|
||
}
|
||
|
||
if (!FFSCopyRead(
|
||
Vcb->StreamObj,
|
||
(PLARGE_INTEGER)&Offset,
|
||
DINODE1_SIZE,
|
||
PIN_WAIT,
|
||
(PVOID)dinode1,
|
||
&IoStatus));
|
||
|
||
if (!NT_SUCCESS(IoStatus.Status))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FFSv2LoadInode(
|
||
IN PFFS_VCB Vcb,
|
||
IN ULONG inode,
|
||
IN PFFSv2_INODE dinode2)
|
||
{
|
||
IO_STATUS_BLOCK IoStatus;
|
||
LONGLONG Offset;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (!FFSv2GetInodeLba(Vcb, inode, &Offset))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSv2LoadInode: error get inode(%xh)'s addr.\n", inode));
|
||
return FALSE;
|
||
}
|
||
|
||
Offset += (LONGLONG)Vcb->FSOffset[Vcb->PartitionNumber];
|
||
|
||
if (!FFSCopyRead(
|
||
Vcb->StreamObj,
|
||
(PLARGE_INTEGER)&Offset,
|
||
DINODE2_SIZE,
|
||
PIN_WAIT,
|
||
(PVOID)dinode2,
|
||
&IoStatus));
|
||
|
||
if (!NT_SUCCESS(IoStatus.Status))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/*
|
||
BOOLEAN
|
||
FFSSaveInode(
|
||
IN PFFS_VCB Vcb,
|
||
IN ULONG inode,
|
||
IN struct dinode *dinode)
|
||
{
|
||
ULONG lba;
|
||
ULONG offset;
|
||
NTSTATUS Status;
|
||
|
||
if (!FFSGetInodeLba(Vcb, inode, &lba, &offset))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSLoadInode: error get inode(%xh)'s addr.\n", inode));
|
||
return FALSE;
|
||
}
|
||
|
||
Status = FFSWriteDisk(Vcb->TargetDeviceObject,
|
||
lba,
|
||
offset,
|
||
sizeof(FFS_INODE),
|
||
(PVOID)dinode);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
*/
|
||
|
||
#if !FFS_READ_ONLY
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
BOOLEAN
|
||
FFSv1SaveInode(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb,
|
||
IN ULONG Inode,
|
||
IN PFFSv1_INODE dinode1)
|
||
{
|
||
LONGLONG Offset = 0;
|
||
LARGE_INTEGER CurrentTime;
|
||
BOOLEAN bRet;
|
||
|
||
PAGED_CODE();
|
||
|
||
KeQuerySystemTime(&CurrentTime);
|
||
dinode1->di_mtime = dinode1->di_atime =
|
||
(ULONG)(FFSInodeTime(CurrentTime));
|
||
|
||
FFSPrint((DBG_INFO, "FFSv1SaveInode: Saving Inode %xh: Mode=%xh Size=%xh\n",
|
||
Inode, dinode1->di_mode, dinode1->di_size));
|
||
|
||
if (!FFSv1GetInodeLba(Vcb, Inode, &Offset))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSv1SaveInode: error get inode(%xh)'s addr.\n", Inode));
|
||
return FALSE;
|
||
}
|
||
|
||
bRet = FFSSaveBuffer(IrpContext, Vcb, Offset, DINODE1_SIZE, dinode1);
|
||
|
||
if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK))
|
||
{
|
||
FFSStartFloppyFlushDpc(Vcb, NULL, NULL);
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
BOOLEAN
|
||
FFSv2SaveInode(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb,
|
||
IN ULONG Inode,
|
||
IN PFFSv2_INODE dinode2)
|
||
{
|
||
PAGED_CODE();
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
#endif // !FFS_READ_ONLY
|
||
|
||
BOOLEAN
|
||
FFSv1LoadBlock(
|
||
IN PFFS_VCB Vcb,
|
||
IN ULONG dwBlk,
|
||
IN PVOID Buffer)
|
||
{
|
||
IO_STATUS_BLOCK IoStatus;
|
||
LONGLONG Offset;
|
||
|
||
PAGED_CODE();
|
||
|
||
Offset = (LONGLONG) dwBlk;
|
||
Offset = Offset * SUPER_BLOCK->fs_fsize; // fragment size
|
||
|
||
if (!FFSCopyRead(
|
||
Vcb->StreamObj,
|
||
(PLARGE_INTEGER)&Offset,
|
||
Vcb->BlockSize,
|
||
PIN_WAIT,
|
||
Buffer,
|
||
&IoStatus));
|
||
|
||
if (!NT_SUCCESS(IoStatus.Status))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FFSv2LoadBlock(
|
||
IN PFFS_VCB Vcb,
|
||
IN ULONGLONG dwBlk,
|
||
IN PVOID Buffer)
|
||
{
|
||
IO_STATUS_BLOCK IoStatus;
|
||
LONGLONG Offset;
|
||
|
||
PAGED_CODE();
|
||
|
||
Offset = (LONGLONG)dwBlk;
|
||
Offset = Offset * SUPER_BLOCK->fs_fsize; // fragment size
|
||
|
||
Offset += Vcb->FSOffset[Vcb->PartitionNumber];
|
||
|
||
if (!FFSCopyRead(
|
||
Vcb->StreamObj,
|
||
(PLARGE_INTEGER)&Offset,
|
||
Vcb->BlockSize,
|
||
PIN_WAIT,
|
||
Buffer,
|
||
&IoStatus));
|
||
|
||
if (!NT_SUCCESS(IoStatus.Status))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
#if !FFS_READ_ONLY
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
BOOLEAN
|
||
FFSSaveBlock(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb,
|
||
IN ULONG dwBlk,
|
||
IN PVOID Buf)
|
||
{
|
||
LONGLONG Offset;
|
||
BOOLEAN bRet;
|
||
|
||
PAGED_CODE();
|
||
|
||
Offset = (LONGLONG)dwBlk;
|
||
Offset = Offset * Vcb->BlockSize;
|
||
|
||
bRet = FFSSaveBuffer(IrpContext, Vcb, Offset, Vcb->BlockSize, Buf);
|
||
|
||
if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK))
|
||
{
|
||
FFSStartFloppyFlushDpc(Vcb, NULL, NULL);
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
BOOLEAN
|
||
FFSSaveBuffer(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb,
|
||
IN LONGLONG Offset,
|
||
IN ULONG Size,
|
||
IN PVOID Buf)
|
||
{
|
||
PBCB Bcb;
|
||
PVOID Buffer;
|
||
|
||
PAGED_CODE();
|
||
|
||
if(!CcPinRead(Vcb->StreamObj,
|
||
(PLARGE_INTEGER) (&Offset),
|
||
Size,
|
||
PIN_WAIT,
|
||
&Bcb,
|
||
&Buffer))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSSaveBuffer: PinReading error ...\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
/*FFSPrint((DBG_INFO, "FFSSaveBuffer: Off=%I64xh Len=%xh Bcb=%xh\n",
|
||
Offset, Size, (ULONG)Bcb));*/
|
||
|
||
RtlCopyMemory(Buffer, Buf, Size);
|
||
CcSetDirtyPinnedData(Bcb, NULL);
|
||
|
||
FFSRepinBcb(IrpContext, Bcb);
|
||
|
||
CcUnpinData(Bcb);
|
||
|
||
SetFlag(Vcb->StreamObj->Flags, FO_FILE_MODIFIED);
|
||
|
||
FFSAddMcbEntry(Vcb, Offset, (LONGLONG)Size);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
#endif // !FFS_READ_ONLY
|
||
|
||
ULONG
|
||
FFSv1GetBlock(
|
||
IN PFFS_VCB Vcb,
|
||
ULONG dwContent,
|
||
ULONG Index,
|
||
int layer)
|
||
{
|
||
ULONG *pData = NULL;
|
||
ULONG i = 0, j = 0, temp = 1;
|
||
ULONG dwBlk = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (layer == 0)
|
||
{
|
||
dwBlk = dwContent;
|
||
}
|
||
else if (layer <= 3)
|
||
{
|
||
pData = (ULONG *)ExAllocatePoolWithTag(PagedPool,
|
||
Vcb->BlockSize, FFS_POOL_TAG);
|
||
if (!pData)
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSGetBlock: no enough memory.\n"));
|
||
return dwBlk;
|
||
}
|
||
|
||
KdPrint(("FFSGetBlock Index : %d, dwContent : %x, layer : %d\n", Index, dwContent, layer));
|
||
|
||
if (!FFSv1LoadBlock(Vcb, dwContent, pData))
|
||
{
|
||
ExFreePool(pData);
|
||
return 0;
|
||
}
|
||
|
||
temp = 1 << ((BLOCK_BITS - 2) * (layer - 1));
|
||
|
||
i = Index / temp;
|
||
j = Index % temp;
|
||
|
||
dwBlk = pData[i];
|
||
|
||
ExFreePool(pData);
|
||
|
||
dwBlk = FFSv1GetBlock(Vcb, dwBlk, j, layer - 1);
|
||
}
|
||
|
||
return dwBlk;
|
||
}
|
||
|
||
|
||
ULONGLONG
|
||
FFSv2GetBlock(
|
||
IN PFFS_VCB Vcb,
|
||
ULONGLONG dwContent,
|
||
ULONG Index,
|
||
int layer)
|
||
{
|
||
ULONGLONG *pData = NULL;
|
||
ULONG i = 0, j = 0, temp = 1;
|
||
ULONGLONG dwBlk = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (layer == 0)
|
||
{
|
||
dwBlk = dwContent;
|
||
}
|
||
else if (layer <= 3)
|
||
{
|
||
pData = (ULONGLONG *)ExAllocatePoolWithTag(PagedPool,
|
||
Vcb->BlockSize, FFS_POOL_TAG);
|
||
if (!pData)
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSv2GetBlock: no enough memory.\n"));
|
||
return dwBlk;
|
||
}
|
||
|
||
KdPrint(("FFSv2GetBlock Index : %d, dwContent : %x, layer : %d\n", Index, dwContent, layer));
|
||
|
||
if (!FFSv2LoadBlock(Vcb, dwContent, pData))
|
||
{
|
||
ExFreePool(pData);
|
||
return 0;
|
||
}
|
||
|
||
if (Index >= (Vcb->BlockSize / 8) && layer == 2)
|
||
temp = 1 << ((BLOCK_BITS - 3) * (layer - 1));
|
||
else
|
||
temp = 1 << ((BLOCK_BITS - 2) * (layer - 1));
|
||
|
||
i = Index / temp;
|
||
j = Index % temp;
|
||
|
||
dwBlk = pData[i];
|
||
|
||
ExFreePool(pData);
|
||
|
||
dwBlk = FFSv2GetBlock(Vcb, dwBlk, j, layer - 1);
|
||
}
|
||
|
||
return dwBlk;
|
||
}
|
||
|
||
|
||
ULONG
|
||
FFSv1BlockMap(
|
||
IN PFFS_VCB Vcb,
|
||
IN PFFSv1_INODE dinode1,
|
||
IN ULONG Index)
|
||
{
|
||
ULONG dwSizes[FFS_BLOCK_TYPES];
|
||
int i;
|
||
ULONG dwBlk;
|
||
ULONG Totalblocks;
|
||
|
||
PAGED_CODE();
|
||
|
||
for (i = 0; i < FFS_BLOCK_TYPES; i++)
|
||
{
|
||
dwSizes[i] = Vcb->dwData[i];
|
||
}
|
||
|
||
Totalblocks = (dinode1->di_blocks);
|
||
|
||
if (Index >= FFSDataBlocks(Vcb, Totalblocks))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSv1BlockMap: error input paramters.\n"));
|
||
|
||
FFSBreakPoint();
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* <20><><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD>, 2<><32> <20><><EFBFBD><EFBFBD> ó<><C3B3> */
|
||
for (i = 0; i < FFS_BLOCK_TYPES; i++)
|
||
{
|
||
if (Index < dwSizes[i])
|
||
{
|
||
if (i == 0)
|
||
dwBlk = dinode1->di_db[Index]; /* <20><><EFBFBD><EFBFBD> */
|
||
else
|
||
dwBlk = dinode1->di_ib[i - 1]; /* <20><><EFBFBD><EFBFBD> */
|
||
#if DBG
|
||
{
|
||
ULONG dwRet = FFSv1GetBlock(Vcb, dwBlk, Index , i);
|
||
|
||
KdPrint(("FFSv1BlockMap: i : %d, Index : %d, dwBlk : %x, Data Block : %X\n", i, Index, dwRet, (dwRet * 0x400)));
|
||
|
||
return dwRet;
|
||
}
|
||
#else
|
||
return FFSv1GetBlock(Vcb, dwBlk, Index , i);
|
||
#endif
|
||
}
|
||
|
||
Index -= dwSizes[i];
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
ULONGLONG
|
||
FFSv2BlockMap(
|
||
IN PFFS_VCB Vcb,
|
||
IN PFFSv2_INODE dinode2,
|
||
IN ULONG Index)
|
||
{
|
||
ULONG dwSizes[FFS_BLOCK_TYPES];
|
||
int i;
|
||
ULONGLONG dwBlk;
|
||
ULONG Totalblocks;
|
||
|
||
PAGED_CODE();
|
||
|
||
for (i = 0; i < FFS_BLOCK_TYPES; i++)
|
||
{
|
||
dwSizes[i] = Vcb->dwData[i];
|
||
}
|
||
|
||
Totalblocks = (ULONG)(dinode2->di_blocks);
|
||
|
||
if (Index >= FFSDataBlocks(Vcb, Totalblocks))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSv2BlockMap: error input paramters.\n"));
|
||
|
||
FFSBreakPoint();
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* <20><><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD>, 2<><32> <20><><EFBFBD><EFBFBD> ó<><C3B3> */
|
||
for (i = 0; i < FFS_BLOCK_TYPES; i++)
|
||
{
|
||
if (Index < dwSizes[i])
|
||
{
|
||
if (i == 0)
|
||
dwBlk = (ULONGLONG)dinode2->di_db[Index]; /* <20><><EFBFBD><EFBFBD> */
|
||
else
|
||
dwBlk = (ULONGLONG)dinode2->di_ib[i - 1]; /* <20><><EFBFBD><EFBFBD> */
|
||
#if 0
|
||
{
|
||
ULONGLONG dwRet = FFSv2GetBlock(Vcb, dwBlk, Index , i);
|
||
|
||
KdPrint(("FFSv2BlockMap: i : %d, Index : %d, dwBlk : %x, Data Block : %X\n", i, Index, dwRet, (dwRet * 0x400)));
|
||
|
||
return dwRet;
|
||
}
|
||
#else
|
||
return FFSv2GetBlock(Vcb, dwBlk, Index , i);
|
||
#endif
|
||
}
|
||
|
||
Index -= dwSizes[i];
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
ULONG
|
||
FFSv1BuildBDL(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb,
|
||
IN PFFSv1_INODE dinode1,
|
||
IN ULONGLONG Offset,
|
||
IN ULONG Size,
|
||
OUT PFFS_BDL *ffs_bdl)
|
||
{
|
||
ULONG nBeg, nEnd, nBlocks;
|
||
ULONG dwBlk, i;
|
||
ULONG dwBytes = 0;
|
||
LONGLONG Lba;
|
||
LONGLONG AllocSize;
|
||
ULONG Totalblocks;
|
||
|
||
PFFS_BDL ffsbdl;
|
||
|
||
PAGED_CODE();
|
||
|
||
*ffs_bdl = NULL;
|
||
|
||
|
||
Totalblocks = (dinode1->di_blocks);
|
||
AllocSize = FFSDataBlocks(Vcb, Totalblocks);
|
||
AllocSize = (AllocSize << BLOCK_BITS);
|
||
|
||
if ((LONGLONG)Offset >= AllocSize)
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSv1BuildBDL: beyond the file range.\n"));
|
||
return 0;
|
||
}
|
||
|
||
if ((LONGLONG)(Offset + Size) > AllocSize)
|
||
{
|
||
Size = (ULONG)(AllocSize - Offset);
|
||
}
|
||
|
||
nBeg = (ULONG)(Offset >> BLOCK_BITS);
|
||
nEnd = (ULONG)((Size + Offset + Vcb->BlockSize - 1) >> BLOCK_BITS);
|
||
|
||
#if DBG
|
||
KdPrint(("FFSv1BuildBDL() Offset : %x\n", Offset));
|
||
KdPrint(("FFSv1BuildBDL() Size : %x\n", Size));
|
||
KdPrint(("FFSv1BuildBDL() nBeg : %d, nEnd : %d\n", nBeg, nEnd));
|
||
#endif
|
||
|
||
nBlocks = 0;
|
||
|
||
if ((nEnd - nBeg) > 0)
|
||
{
|
||
ffsbdl = ExAllocatePoolWithTag(PagedPool, sizeof(FFS_BDL) * (nEnd - nBeg), FFS_POOL_TAG);
|
||
|
||
if (ffsbdl)
|
||
{
|
||
RtlZeroMemory(ffsbdl, sizeof(FFS_BDL) * (nEnd - nBeg));
|
||
|
||
for (i = nBeg; i < nEnd; i++)
|
||
{
|
||
dwBlk = FFSv1BlockMap(Vcb, dinode1, i);
|
||
|
||
if (dwBlk > 0)
|
||
{
|
||
Lba = (LONGLONG)dwBlk;
|
||
Lba = Lba * SUPER_BLOCK->fs_fsize; // fragment size
|
||
|
||
if (nBeg == nEnd - 1) // ie. (nBeg == nEnd - 1)
|
||
{
|
||
dwBytes = Size;
|
||
ffsbdl[nBlocks].Lba = Lba + (LONGLONG)(Offset % (Vcb->BlockSize));
|
||
ffsbdl[nBlocks].Length = dwBytes;
|
||
ffsbdl[nBlocks].Offset = 0;
|
||
|
||
nBlocks++;
|
||
}
|
||
else
|
||
{
|
||
if (i == nBeg)
|
||
{
|
||
dwBytes = Vcb->BlockSize - (ULONG)(Offset % (Vcb->BlockSize));
|
||
ffsbdl[nBlocks].Lba = Lba + (LONGLONG)(Offset % (Vcb->BlockSize));
|
||
ffsbdl[nBlocks].Length = dwBytes;
|
||
ffsbdl[nBlocks].Offset = 0;
|
||
|
||
nBlocks++;
|
||
}
|
||
else if (i == nEnd - 1)
|
||
{
|
||
if (ffsbdl[nBlocks - 1].Lba + ffsbdl[nBlocks - 1].Length == Lba)
|
||
{
|
||
ffsbdl[nBlocks - 1].Length += Size - dwBytes;
|
||
}
|
||
else
|
||
{
|
||
ffsbdl[nBlocks].Lba = Lba;
|
||
ffsbdl[nBlocks].Length = Size - dwBytes;
|
||
ffsbdl[nBlocks].Offset = dwBytes;
|
||
nBlocks++;
|
||
}
|
||
|
||
dwBytes = Size;
|
||
|
||
}
|
||
else
|
||
{
|
||
if (ffsbdl[nBlocks - 1].Lba + ffsbdl[nBlocks - 1].Length == Lba)
|
||
{
|
||
ffsbdl[nBlocks - 1].Length += Vcb->BlockSize;
|
||
}
|
||
else
|
||
{
|
||
ffsbdl[nBlocks].Lba = Lba;
|
||
ffsbdl[nBlocks].Length = Vcb->BlockSize;
|
||
ffsbdl[nBlocks].Offset = dwBytes;
|
||
nBlocks++;
|
||
}
|
||
|
||
dwBytes += Vcb->BlockSize;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
*ffs_bdl = ffsbdl;
|
||
return nBlocks;
|
||
}
|
||
}
|
||
|
||
// Error
|
||
return 0;
|
||
}
|
||
|
||
|
||
ULONG
|
||
FFSv2BuildBDL(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb,
|
||
IN PFFSv2_INODE dinode2,
|
||
IN ULONGLONG Offset,
|
||
IN ULONG Size,
|
||
OUT PFFS_BDL *ffs_bdl)
|
||
{
|
||
ULONG nBeg, nEnd, nBlocks;
|
||
ULONGLONG dwBlk;
|
||
ULONG dwBytes = 0, i;
|
||
LONGLONG Lba;
|
||
LONGLONG AllocSize;
|
||
ULONG Totalblocks;
|
||
|
||
PFFS_BDL ffsbdl;
|
||
|
||
PAGED_CODE();
|
||
|
||
*ffs_bdl = NULL;
|
||
|
||
|
||
Totalblocks = (ULONG)(dinode2->di_blocks);
|
||
AllocSize = FFSDataBlocks(Vcb, Totalblocks);
|
||
AllocSize = (AllocSize << BLOCK_BITS);
|
||
|
||
if ((LONGLONG)Offset >= AllocSize)
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSv2BuildBDL: beyond the file range.\n"));
|
||
return 0;
|
||
}
|
||
|
||
if ((LONGLONG)(Offset + Size) > AllocSize)
|
||
{
|
||
Size = (ULONG)(AllocSize - Offset);
|
||
}
|
||
|
||
nBeg = (ULONG)(Offset >> BLOCK_BITS);
|
||
nEnd = (ULONG)((Size + Offset + Vcb->BlockSize - 1) >> BLOCK_BITS);
|
||
|
||
#if 0
|
||
KdPrint(("FFSv2BuildBDL() Offset : %x\n", Offset));
|
||
KdPrint(("FFSv2BuildBDL() Size : %x\n", Size));
|
||
KdPrint(("FFSv2BuildBDL() nBeg : %d, nEnd : %d\n", nBeg, nEnd));
|
||
#endif
|
||
|
||
nBlocks = 0;
|
||
|
||
if ((nEnd - nBeg) > 0)
|
||
{
|
||
ffsbdl = ExAllocatePoolWithTag(PagedPool, sizeof(FFS_BDL) * (nEnd - nBeg), FFS_POOL_TAG);
|
||
|
||
if (ffsbdl)
|
||
{
|
||
|
||
RtlZeroMemory(ffsbdl, sizeof(FFS_BDL) * (nEnd - nBeg));
|
||
|
||
for (i = nBeg; i < nEnd; i++)
|
||
{
|
||
dwBlk = FFSv2BlockMap(Vcb, dinode2, i);
|
||
|
||
if (dwBlk > 0)
|
||
{
|
||
Lba = (LONGLONG)dwBlk;
|
||
Lba = Lba * SUPER_BLOCK->fs_fsize; // fragment size
|
||
Lba += Vcb->FSOffset[Vcb->PartitionNumber];
|
||
|
||
if (nBeg == nEnd - 1) // ie. (nBeg == nEnd - 1)
|
||
{
|
||
dwBytes = Size;
|
||
ffsbdl[nBlocks].Lba = Lba + (LONGLONG)(Offset % (Vcb->BlockSize));
|
||
ffsbdl[nBlocks].Length = dwBytes;
|
||
ffsbdl[nBlocks].Offset = 0;
|
||
|
||
nBlocks++;
|
||
}
|
||
else
|
||
{
|
||
if (i == nBeg)
|
||
{
|
||
dwBytes = Vcb->BlockSize - (ULONG)(Offset % (Vcb->BlockSize));
|
||
ffsbdl[nBlocks].Lba = Lba + (LONGLONG)(Offset % (Vcb->BlockSize));
|
||
ffsbdl[nBlocks].Length = dwBytes;
|
||
ffsbdl[nBlocks].Offset = 0;
|
||
|
||
nBlocks++;
|
||
}
|
||
else if (i == nEnd - 1)
|
||
{
|
||
if (ffsbdl[nBlocks - 1].Lba + ffsbdl[nBlocks - 1].Length == Lba)
|
||
{
|
||
ffsbdl[nBlocks - 1].Length += Size - dwBytes;
|
||
}
|
||
else
|
||
{
|
||
ffsbdl[nBlocks].Lba = Lba;
|
||
ffsbdl[nBlocks].Length = Size - dwBytes;
|
||
ffsbdl[nBlocks].Offset = dwBytes;
|
||
nBlocks++;
|
||
}
|
||
|
||
dwBytes = Size;
|
||
|
||
}
|
||
else
|
||
{
|
||
if (ffsbdl[nBlocks - 1].Lba + ffsbdl[nBlocks - 1].Length == Lba)
|
||
{
|
||
ffsbdl[nBlocks - 1].Length += Vcb->BlockSize;
|
||
}
|
||
else
|
||
{
|
||
ffsbdl[nBlocks].Lba = Lba;
|
||
ffsbdl[nBlocks].Length = Vcb->BlockSize;
|
||
ffsbdl[nBlocks].Offset = dwBytes;
|
||
nBlocks++;
|
||
}
|
||
|
||
dwBytes += Vcb->BlockSize;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
*ffs_bdl = ffsbdl;
|
||
return nBlocks;
|
||
}
|
||
}
|
||
|
||
// Error
|
||
return 0;
|
||
}
|
||
|
||
#if !FFS_READ_ONLY
|
||
|
||
BOOLEAN
|
||
FFSNewBlock(
|
||
PFFS_IRP_CONTEXT IrpContext,
|
||
PFFS_VCB Vcb,
|
||
ULONG GroupHint,
|
||
ULONG BlockHint,
|
||
PULONG dwRet)
|
||
{
|
||
RTL_BITMAP BlockBitmap;
|
||
LARGE_INTEGER Offset;
|
||
ULONG Length;
|
||
|
||
PBCB BitmapBcb;
|
||
PVOID BitmapCache;
|
||
|
||
ULONG Group = 0, dwBlk, dwHint = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
#if 0
|
||
*dwRet = 0;
|
||
dwBlk = 0XFFFFFFFF;
|
||
|
||
if (GroupHint > Vcb->ffs_groups)
|
||
GroupHint = Vcb->ffs_groups - 1;
|
||
|
||
if (BlockHint != 0)
|
||
{
|
||
GroupHint = (BlockHint - FFS_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
|
||
dwHint = (BlockHint - FFS_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
|
||
}
|
||
|
||
ScanBitmap:
|
||
|
||
// Perform Prefered Group
|
||
if (Vcb->ffs_group_desc[GroupHint].bg_free_blocks_count)
|
||
{
|
||
Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
|
||
Offset.QuadPart = Offset.QuadPart *
|
||
Vcb->ffs_group_desc[GroupHint].bg_block_bitmap;
|
||
|
||
if (GroupHint == Vcb->ffs_groups - 1)
|
||
{
|
||
Length = TOTAL_BLOCKS % BLOCKS_PER_GROUP;
|
||
|
||
/* s_blocks_count is integer multiple of s_blocks_per_group */
|
||
if (Length == 0)
|
||
{
|
||
Length = BLOCKS_PER_GROUP;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Length = BLOCKS_PER_GROUP;
|
||
}
|
||
|
||
if (!CcPinRead(Vcb->StreamObj,
|
||
&Offset,
|
||
Vcb->BlockSize,
|
||
PIN_WAIT,
|
||
&BitmapBcb,
|
||
&BitmapCache))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSNewBlock: PinReading error ...\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
RtlInitializeBitMap(&BlockBitmap,
|
||
BitmapCache,
|
||
Length);
|
||
|
||
Group = GroupHint;
|
||
|
||
if (RtlCheckBit(&BlockBitmap, dwHint) == 0)
|
||
{
|
||
dwBlk = dwHint;
|
||
}
|
||
else
|
||
{
|
||
dwBlk = RtlFindClearBits(&BlockBitmap, 1, dwHint);
|
||
}
|
||
|
||
// We could not get new block in the prefered group.
|
||
if (dwBlk == 0xFFFFFFFF)
|
||
{
|
||
CcUnpinData(BitmapBcb);
|
||
BitmapBcb = NULL;
|
||
BitmapCache = NULL;
|
||
|
||
RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
|
||
}
|
||
}
|
||
|
||
if (dwBlk == 0xFFFFFFFF)
|
||
{
|
||
for(Group = 0; Group < Vcb->ffs_groups; Group++)
|
||
if (Vcb->ffs_group_desc[Group].bg_free_blocks_count)
|
||
{
|
||
|
||
if (Group == GroupHint)
|
||
continue;
|
||
|
||
Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
|
||
Offset.QuadPart = Offset.QuadPart * Vcb->ffs_group_desc[Group].bg_block_bitmap;
|
||
|
||
if (Vcb->ffs_groups == 1)
|
||
{
|
||
Length = TOTAL_BLOCKS;
|
||
}
|
||
else
|
||
{
|
||
if (Group == Vcb->ffs_groups - 1)
|
||
{
|
||
Length = TOTAL_BLOCKS % BLOCKS_PER_GROUP;
|
||
|
||
/* s_blocks_count is integer multiple of s_blocks_per_group */
|
||
if (Length == 0)
|
||
{
|
||
Length = BLOCKS_PER_GROUP;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Length = BLOCKS_PER_GROUP;
|
||
}
|
||
}
|
||
|
||
if (!CcPinRead(Vcb->StreamObj,
|
||
&Offset,
|
||
Vcb->BlockSize,
|
||
PIN_WAIT,
|
||
&BitmapBcb,
|
||
&BitmapCache))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSNewBlock: PinReading error ...\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
RtlInitializeBitMap(&BlockBitmap,
|
||
BitmapCache,
|
||
Length);
|
||
|
||
dwBlk = RtlFindClearBits(&BlockBitmap, 1, 0);
|
||
|
||
if (dwBlk != 0xFFFFFFFF)
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
CcUnpinData(BitmapBcb);
|
||
BitmapBcb = NULL;
|
||
BitmapCache = NULL;
|
||
|
||
RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
|
||
}
|
||
}
|
||
}
|
||
|
||
if (dwBlk < Length)
|
||
{
|
||
RtlSetBits(&BlockBitmap, dwBlk, 1);
|
||
|
||
CcSetDirtyPinnedData(BitmapBcb, NULL);
|
||
|
||
FFSRepinBcb(IrpContext, BitmapBcb);
|
||
|
||
CcUnpinData(BitmapBcb);
|
||
|
||
FFSAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
|
||
|
||
*dwRet = dwBlk + FFS_FIRST_DATA_BLOCK + Group * BLOCKS_PER_GROUP;
|
||
|
||
//Updating Group Desc / Superblock
|
||
Vcb->ffs_group_desc[Group].bg_free_blocks_count--;
|
||
FFSSaveGroup(IrpContext, Vcb);
|
||
|
||
Vcb->ffs_super_block->s_free_blocks_count--;
|
||
FFSSaveSuper(IrpContext, Vcb);
|
||
|
||
{
|
||
ULONG i = 0;
|
||
for (i = 0; i < Vcb->ffs_groups; i++)
|
||
{
|
||
if ((Vcb->ffs_group_desc[i].bg_block_bitmap == *dwRet) ||
|
||
(Vcb->ffs_group_desc[i].bg_inode_bitmap == *dwRet) ||
|
||
(Vcb->ffs_group_desc[i].bg_inode_table == *dwRet))
|
||
{
|
||
FFSBreakPoint();
|
||
GroupHint = Group;
|
||
goto ScanBitmap;
|
||
}
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
#endif
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FFSFreeBlock(
|
||
PFFS_IRP_CONTEXT IrpContext,
|
||
PFFS_VCB Vcb,
|
||
ULONG Block)
|
||
{
|
||
RTL_BITMAP BlockBitmap;
|
||
LARGE_INTEGER Offset;
|
||
ULONG Length;
|
||
|
||
PBCB BitmapBcb;
|
||
PVOID BitmapCache;
|
||
|
||
ULONG Group, dwBlk;
|
||
BOOLEAN bModified = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
#if 0
|
||
if (Block < FFS_FIRST_DATA_BLOCK || Block > (BLOCKS_PER_GROUP * Vcb->ffs_groups))
|
||
{
|
||
FFSBreakPoint();
|
||
return TRUE;
|
||
}
|
||
|
||
FFSPrint((DBG_INFO, "FFSFreeBlock: Block %xh to be freed.\n", Block));
|
||
|
||
Group = (Block - FFS_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
|
||
|
||
dwBlk = (Block - FFS_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
|
||
|
||
{
|
||
Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
|
||
Offset.QuadPart = Offset.QuadPart * Vcb->ffs_group_desc[Group].bg_block_bitmap;
|
||
|
||
if (Group == Vcb->ffs_groups - 1)
|
||
{
|
||
Length = TOTAL_BLOCKS % BLOCKS_PER_GROUP;
|
||
|
||
/* s_blocks_count is integer multiple of s_blocks_per_group */
|
||
if (Length == 0)
|
||
{
|
||
Length = BLOCKS_PER_GROUP;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Length = BLOCKS_PER_GROUP;
|
||
}
|
||
|
||
if (!CcPinRead(Vcb->StreamObj,
|
||
&Offset,
|
||
Vcb->BlockSize,
|
||
PIN_WAIT,
|
||
&BitmapBcb,
|
||
&BitmapCache))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSDeleteBlock: PinReading error ...\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
RtlInitializeBitMap(&BlockBitmap,
|
||
BitmapCache,
|
||
Length);
|
||
|
||
if (RtlCheckBit(&BlockBitmap, dwBlk) == 0)
|
||
{
|
||
|
||
}
|
||
else
|
||
{
|
||
RtlClearBits(&BlockBitmap, dwBlk, 1);
|
||
bModified = TRUE;
|
||
}
|
||
|
||
if (!bModified)
|
||
{
|
||
CcUnpinData(BitmapBcb);
|
||
BitmapBcb = NULL;
|
||
BitmapCache = NULL;
|
||
|
||
RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
|
||
}
|
||
}
|
||
|
||
if (bModified)
|
||
{
|
||
CcSetDirtyPinnedData(BitmapBcb, NULL);
|
||
|
||
FFSRepinBcb(IrpContext, BitmapBcb);
|
||
|
||
CcUnpinData(BitmapBcb);
|
||
|
||
FFSAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
|
||
|
||
//Updating Group Desc / Superblock
|
||
Vcb->ffs_group_desc[Group].bg_free_blocks_count++;
|
||
FFSSaveGroup(IrpContext, Vcb);
|
||
|
||
Vcb->ffs_super_block->s_free_blocks_count++;
|
||
FFSSaveSuper(IrpContext, Vcb);
|
||
|
||
return TRUE;
|
||
}
|
||
#endif
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
BOOLEAN
|
||
FFSExpandBlock(
|
||
PFFS_IRP_CONTEXT IrpContext,
|
||
PFFS_VCB Vcb,
|
||
PFFS_FCB Fcb,
|
||
ULONG dwContent,
|
||
ULONG Index,
|
||
ULONG layer,
|
||
BOOLEAN bNew,
|
||
ULONG *dwRet)
|
||
{
|
||
ULONG *pData = NULL;
|
||
ULONG i = 0, j = 0, temp = 1;
|
||
ULONG dwNewBlk = 0, dwBlk = 0;
|
||
BOOLEAN bDirty = FALSE;
|
||
BOOLEAN bRet = TRUE;
|
||
|
||
PFFSv1_INODE dinode1 = Fcb->dinode1;
|
||
PFFS_SUPER_BLOCK FFSSb = Vcb->ffs_super_block;
|
||
|
||
PAGED_CODE();
|
||
|
||
pData = (ULONG *)ExAllocatePoolWithTag(PagedPool, Vcb->BlockSize, FFS_POOL_TAG);
|
||
|
||
if (!pData)
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
RtlZeroMemory(pData, Vcb->BlockSize);
|
||
|
||
if (bNew)
|
||
{
|
||
if (layer == 0)
|
||
{
|
||
if (IsDirectory(Fcb))
|
||
{
|
||
PFFS_DIR_ENTRY pEntry;
|
||
|
||
pEntry = (PFFS_DIR_ENTRY) pData;
|
||
pEntry->d_reclen = (USHORT)(Vcb->BlockSize);
|
||
|
||
if (!FFSSaveBlock(IrpContext, Vcb, dwContent, (PVOID)pData))
|
||
{
|
||
bRet = FALSE;
|
||
goto errorout;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
LARGE_INTEGER Offset;
|
||
|
||
Offset.QuadPart = (LONGLONG)dwContent;
|
||
Offset.QuadPart = Offset.QuadPart * Vcb->BlockSize;
|
||
|
||
FFSRemoveMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!FFSSaveBlock(IrpContext, Vcb, dwContent, (PVOID)pData))
|
||
{
|
||
bRet = FALSE;
|
||
goto errorout;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (layer == 0)
|
||
{
|
||
dwNewBlk = dwContent;
|
||
}
|
||
else if (layer <= 3)
|
||
{
|
||
if (!bNew)
|
||
{
|
||
bRet = FFSv1LoadBlock(Vcb, dwContent, (void *)pData);
|
||
if (!bRet) goto errorout;
|
||
}
|
||
|
||
temp = 1 << ((BLOCK_BITS - 2) * (layer - 1));
|
||
|
||
i = Index / temp;
|
||
j = Index % temp;
|
||
|
||
dwBlk = pData[i];
|
||
|
||
if (dwBlk == 0)
|
||
{
|
||
if (!FFSNewBlock(IrpContext,
|
||
Vcb, 0,
|
||
dwContent,
|
||
&dwBlk))
|
||
{
|
||
bRet = FALSE;
|
||
FFSPrint((DBG_ERROR, "FFSExpandBlock: get new block error.\n"));
|
||
goto errorout;
|
||
}
|
||
|
||
dinode1->di_blocks += (Vcb->BlockSize / SECTOR_SIZE);
|
||
|
||
pData[i] = dwBlk;
|
||
bDirty = TRUE;
|
||
}
|
||
|
||
if (!FFSExpandBlock(IrpContext,
|
||
Vcb, Fcb,
|
||
dwBlk, j,
|
||
layer - 1,
|
||
bDirty,
|
||
&dwNewBlk))
|
||
{
|
||
bRet = FALSE;
|
||
FFSPrint((DBG_ERROR, "FFSExpandBlockk: ... error recuise...\n"));
|
||
goto errorout;
|
||
}
|
||
|
||
if (bDirty)
|
||
{
|
||
bRet = FFSSaveBlock(IrpContext,
|
||
Vcb, dwContent,
|
||
(void *)pData);
|
||
}
|
||
}
|
||
|
||
errorout:
|
||
|
||
if (pData)
|
||
ExFreePool(pData);
|
||
|
||
if (bRet && dwRet)
|
||
*dwRet = dwNewBlk;
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FFSExpandInode(
|
||
PFFS_IRP_CONTEXT IrpContext,
|
||
PFFS_VCB Vcb,
|
||
PFFS_FCB Fcb,
|
||
ULONG *dwRet)
|
||
{
|
||
ULONG dwSizes[FFS_BLOCK_TYPES];
|
||
ULONG Index = 0;
|
||
ULONG dwTotal = 0;
|
||
ULONG dwBlk = 0, dwNewBlk = 0;
|
||
ULONG i;
|
||
BOOLEAN bRet = FALSE;
|
||
BOOLEAN bNewBlock = FALSE;
|
||
|
||
PFFSv1_INODE dinode1 = Fcb->dinode1;
|
||
|
||
PAGED_CODE();
|
||
|
||
Index = (ULONG)(Fcb->Header.AllocationSize.QuadPart >> BLOCK_BITS);
|
||
|
||
for (i = 0; i < FFS_BLOCK_TYPES; i++)
|
||
{
|
||
dwSizes[i] = Vcb->dwData[i];
|
||
dwTotal += dwSizes[i];
|
||
}
|
||
|
||
if (Index >= dwTotal)
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSExpandInode: beyond the maxinum size of an inode.\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
for (i = 0; i < FFS_BLOCK_TYPES; i++)
|
||
{
|
||
if (Index < dwSizes[i])
|
||
{
|
||
dwBlk = dinode1->di_db[i == 0 ? (Index) : (i + NDADDR - 1)];
|
||
if (dwBlk == 0)
|
||
{
|
||
if (!FFSNewBlock(IrpContext,
|
||
Vcb,
|
||
Fcb->BlkHint ? 0 : ((Fcb->FFSMcb->Inode - 1) / INODES_PER_GROUP),
|
||
Fcb->BlkHint,
|
||
&dwBlk))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSExpandInode: get new block error.\n"));
|
||
break;
|
||
}
|
||
|
||
dinode1->di_ib[i == 0 ? (Index):(i + NDADDR - 1)] = dwBlk;
|
||
|
||
dinode1->di_blocks += (Vcb->BlockSize / SECTOR_SIZE);
|
||
|
||
bNewBlock = TRUE;
|
||
}
|
||
|
||
bRet = FFSExpandBlock(IrpContext,
|
||
Vcb, Fcb,
|
||
dwBlk, Index,
|
||
i, bNewBlock,
|
||
&dwNewBlk);
|
||
|
||
if (bRet)
|
||
{
|
||
Fcb->Header.AllocationSize.QuadPart += Vcb->BlockSize;
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
Index -= dwSizes[i];
|
||
}
|
||
|
||
{
|
||
ASSERT(FFSDataBlocks(Vcb, (ULONG)(dinode1->di_blocks / (BLOCK_SIZE / SECTOR_SIZE)))
|
||
== (Fcb->Header.AllocationSize.QuadPart / BLOCK_SIZE));
|
||
|
||
ASSERT(FFSTotalBlocks(Vcb, (ULONG)(Fcb->Header.AllocationSize.QuadPart / BLOCK_SIZE))
|
||
== (dinode1->di_blocks / (BLOCK_SIZE / SECTOR_SIZE)));
|
||
}
|
||
|
||
|
||
FFSv1SaveInode(IrpContext, Vcb, Fcb->FFSMcb->Inode, dinode1);
|
||
|
||
if (bRet && dwNewBlk)
|
||
{
|
||
if (dwRet)
|
||
{
|
||
Fcb->BlkHint = dwNewBlk+1;
|
||
*dwRet = dwNewBlk;
|
||
|
||
FFSPrint((DBG_INFO, "FFSExpandInode: %S (%xh) i=%2.2xh Index=%8.8xh New Block=%8.8xh\n", Fcb->FFSMcb->ShortName.Buffer, Fcb->FFSMcb->Inode, i, Index, dwNewBlk));
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FFSNewInode(
|
||
PFFS_IRP_CONTEXT IrpContext,
|
||
PFFS_VCB Vcb,
|
||
ULONG GroupHint,
|
||
ULONG Type,
|
||
PULONG Inode)
|
||
{
|
||
RTL_BITMAP InodeBitmap;
|
||
PVOID BitmapCache;
|
||
PBCB BitmapBcb;
|
||
|
||
ULONG Group, i, j;
|
||
ULONG Average, Length;
|
||
LARGE_INTEGER Offset;
|
||
|
||
ULONG dwInode;
|
||
|
||
PAGED_CODE();
|
||
|
||
#if 0
|
||
*Inode = dwInode = 0XFFFFFFFF;
|
||
|
||
repeat:
|
||
|
||
Group = i = 0;
|
||
|
||
if (Type == DT_DIR)
|
||
{
|
||
Average = Vcb->ffs_super_block->s_free_inodes_count / Vcb->ffs_groups;
|
||
|
||
for (j = 0; j < Vcb->ffs_groups; j++)
|
||
{
|
||
i = (j + GroupHint) % (Vcb->ffs_groups);
|
||
|
||
if ((Vcb->ffs_group_desc[i].bg_used_dirs_count << 8) <
|
||
Vcb->ffs_group_desc[i].bg_free_inodes_count)
|
||
{
|
||
Group = i + 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!Group)
|
||
{
|
||
for (j = 0; j < Vcb->ffs_groups; j++)
|
||
{
|
||
if (Vcb->ffs_group_desc[j].bg_free_inodes_count >= Average)
|
||
{
|
||
if (!Group || (Vcb->ffs_group_desc[j].bg_free_blocks_count > Vcb->ffs_group_desc[Group].bg_free_blocks_count))
|
||
Group = j + 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* Try to place the inode in its parent directory (GroupHint)
|
||
*/
|
||
if (Vcb->ffs_group_desc[GroupHint].bg_free_inodes_count)
|
||
{
|
||
Group = GroupHint + 1;
|
||
}
|
||
else
|
||
{
|
||
i = GroupHint;
|
||
|
||
/*
|
||
* Use a quadratic hash to find a group with a
|
||
* free inode
|
||
*/
|
||
for (j = 1; j < Vcb->ffs_groups; j <<= 1)
|
||
{
|
||
|
||
i += j;
|
||
if (i > Vcb->ffs_groups)
|
||
i -= Vcb->ffs_groups;
|
||
|
||
if (Vcb->ffs_group_desc[i].bg_free_inodes_count)
|
||
{
|
||
Group = i + 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!Group) {
|
||
/*
|
||
* That failed: try linear search for a free inode
|
||
*/
|
||
i = GroupHint + 1;
|
||
for (j = 2; j < Vcb->ffs_groups; j++)
|
||
{
|
||
if (++i >= Vcb->ffs_groups) i = 0;
|
||
|
||
if (Vcb->ffs_group_desc[i].bg_free_inodes_count)
|
||
{
|
||
Group = i + 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Could not find a proper group.
|
||
if (!Group)
|
||
{
|
||
return STATUS_DISK_FULL;
|
||
}
|
||
else
|
||
{
|
||
Group--;
|
||
|
||
Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
|
||
Offset.QuadPart = Offset.QuadPart * Vcb->ffs_group_desc[Group].bg_inode_bitmap;
|
||
|
||
if (Vcb->ffs_groups == 1)
|
||
{
|
||
Length = INODES_COUNT;
|
||
}
|
||
else
|
||
{
|
||
if (Group == Vcb->ffs_groups - 1)
|
||
{
|
||
Length = INODES_COUNT % INODES_PER_GROUP;
|
||
if (!Length)
|
||
{
|
||
/* INODES_COUNT is integer multiple of INODES_PER_GROUP */
|
||
Length = INODES_PER_GROUP;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Length = INODES_PER_GROUP;
|
||
}
|
||
}
|
||
|
||
if (!CcPinRead(Vcb->StreamObj,
|
||
&Offset,
|
||
Vcb->BlockSize,
|
||
PIN_WAIT,
|
||
&BitmapBcb,
|
||
&BitmapCache))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSNewInode: PinReading error ...\n"));
|
||
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
RtlInitializeBitMap(&InodeBitmap,
|
||
BitmapCache,
|
||
Length);
|
||
|
||
dwInode = RtlFindClearBits(&InodeBitmap, 1, 0);
|
||
|
||
if (dwInode == 0xFFFFFFFF)
|
||
{
|
||
CcUnpinData(BitmapBcb);
|
||
BitmapBcb = NULL;
|
||
BitmapCache = NULL;
|
||
|
||
RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
|
||
}
|
||
}
|
||
|
||
if (dwInode == 0xFFFFFFFF || dwInode >= Length)
|
||
{
|
||
if (Vcb->ffs_group_desc[Group].bg_free_inodes_count != 0)
|
||
{
|
||
Vcb->ffs_group_desc[Group].bg_free_inodes_count = 0;
|
||
|
||
FFSSaveGroup(IrpContext, Vcb);
|
||
}
|
||
|
||
goto repeat;
|
||
}
|
||
else
|
||
{
|
||
RtlSetBits(&InodeBitmap, dwInode, 1);
|
||
|
||
CcSetDirtyPinnedData(BitmapBcb, NULL);
|
||
|
||
FFSRepinBcb(IrpContext, BitmapBcb);
|
||
|
||
CcUnpinData(BitmapBcb);
|
||
|
||
FFSAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
|
||
|
||
*Inode = dwInode + 1 + Group * INODES_PER_GROUP;
|
||
|
||
//Updating Group Desc / Superblock
|
||
Vcb->ffs_group_desc[Group].bg_free_inodes_count--;
|
||
if (Type == FFS_FT_DIR)
|
||
{
|
||
Vcb->ffs_group_desc[Group].bg_used_dirs_count++;
|
||
}
|
||
|
||
FFSSaveGroup(IrpContext, Vcb);
|
||
|
||
Vcb->ffs_super_block->s_free_inodes_count--;
|
||
FFSSaveSuper(IrpContext, Vcb);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
return STATUS_DISK_FULL;
|
||
#endif
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FFSFreeInode(
|
||
PFFS_IRP_CONTEXT IrpContext,
|
||
PFFS_VCB Vcb,
|
||
ULONG Inode,
|
||
ULONG Type)
|
||
{
|
||
RTL_BITMAP InodeBitmap;
|
||
PVOID BitmapCache;
|
||
PBCB BitmapBcb;
|
||
|
||
ULONG Group;
|
||
ULONG Length;
|
||
LARGE_INTEGER Offset;
|
||
|
||
ULONG dwIno;
|
||
BOOLEAN bModified = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
#if 0
|
||
Group = (Inode - 1) / INODES_PER_GROUP;
|
||
dwIno = (Inode - 1) % INODES_PER_GROUP;
|
||
|
||
FFSPrint((DBG_INFO, "FFSFreeInode: Inode: %xh (Group/Off = %xh/%xh)\n",
|
||
Inode, Group, dwIno));
|
||
|
||
{
|
||
Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
|
||
Offset.QuadPart = Offset.QuadPart * Vcb->ffs_group_desc[Group].bg_inode_bitmap;
|
||
if (Group == Vcb->ffs_groups - 1)
|
||
{
|
||
Length = INODES_COUNT % INODES_PER_GROUP;
|
||
if (!Length)
|
||
{ /* s_inodes_count is integer multiple of s_inodes_per_group */
|
||
Length = INODES_PER_GROUP;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Length = INODES_PER_GROUP;
|
||
}
|
||
|
||
if (!CcPinRead(Vcb->StreamObj,
|
||
&Offset,
|
||
Vcb->BlockSize,
|
||
PIN_WAIT,
|
||
&BitmapBcb,
|
||
&BitmapCache))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSFreeInode: PinReading error ...\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
RtlInitializeBitMap(&InodeBitmap,
|
||
BitmapCache,
|
||
Length);
|
||
|
||
if (RtlCheckBit(&InodeBitmap, dwIno) == 0)
|
||
{
|
||
|
||
}
|
||
else
|
||
{
|
||
RtlClearBits(&InodeBitmap, dwIno, 1);
|
||
bModified = TRUE;
|
||
}
|
||
|
||
if (!bModified)
|
||
{
|
||
CcUnpinData(BitmapBcb);
|
||
BitmapBcb = NULL;
|
||
BitmapCache = NULL;
|
||
|
||
RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
|
||
}
|
||
}
|
||
|
||
if (bModified)
|
||
{
|
||
CcSetDirtyPinnedData(BitmapBcb, NULL);
|
||
|
||
FFSRepinBcb(IrpContext, BitmapBcb);
|
||
|
||
CcUnpinData(BitmapBcb);
|
||
|
||
FFSAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
|
||
|
||
//Updating Group Desc / Superblock
|
||
if (Type == DT_DIR)
|
||
{
|
||
Vcb->ffs_group_desc[Group].bg_used_dirs_count--;
|
||
}
|
||
|
||
Vcb->ffs_group_desc[Group].bg_free_inodes_count++;
|
||
FFSSaveGroup(IrpContext, Vcb);
|
||
|
||
Vcb->ffs_super_block->s_free_inodes_count++;
|
||
FFSSaveSuper(IrpContext, Vcb);
|
||
|
||
return TRUE;
|
||
}
|
||
#endif
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
NTSTATUS
|
||
FFSAddEntry(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb,
|
||
IN PFFS_FCB Dcb,
|
||
IN ULONG FileType,
|
||
IN ULONG Inode,
|
||
IN PUNICODE_STRING FileName)
|
||
{
|
||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||
|
||
PFFS_DIR_ENTRY pDir = NULL;
|
||
PFFS_DIR_ENTRY pNewDir = NULL;
|
||
PFFS_DIR_ENTRY pTarget = NULL;
|
||
|
||
ULONG Length = 0;
|
||
ULONG dwBytes = 0;
|
||
|
||
BOOLEAN bFound = FALSE;
|
||
BOOLEAN bAdding = FALSE;
|
||
|
||
BOOLEAN MainResourceAcquired = FALSE;
|
||
|
||
ULONG dwRet;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (!IsDirectory(Dcb))
|
||
{
|
||
FFSBreakPoint();
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
return Status;
|
||
}
|
||
|
||
MainResourceAcquired = ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
|
||
|
||
_SEH2_TRY
|
||
{
|
||
Dcb->ReferenceCount++;
|
||
|
||
pDir = (PFFS_DIR_ENTRY)ExAllocatePoolWithTag(PagedPool,
|
||
FFS_DIR_REC_LEN(FFS_NAME_LEN), FFS_POOL_TAG);
|
||
if (!pDir)
|
||
{
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
_SEH2_LEAVE;
|
||
}
|
||
|
||
pTarget = (PFFS_DIR_ENTRY)ExAllocatePoolWithTag(PagedPool,
|
||
2 * FFS_DIR_REC_LEN(FFS_NAME_LEN), FFS_POOL_TAG);
|
||
if (!pTarget)
|
||
{
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
_SEH2_LEAVE;
|
||
}
|
||
|
||
#if 0
|
||
if (IsFlagOn(SUPER_BLOCK->s_feature_incompat,
|
||
FFS_FEATURE_INCOMPAT_FILETYPE))
|
||
{
|
||
pDir->d_type = (UCHAR)FileType;
|
||
}
|
||
else
|
||
#endif
|
||
{
|
||
pDir->d_type = 0;
|
||
}
|
||
|
||
{
|
||
OEM_STRING OemName;
|
||
OemName.Buffer = pDir->d_name;
|
||
OemName.MaximumLength = FFS_NAME_LEN;
|
||
OemName.Length = 0;
|
||
|
||
Status = FFSUnicodeToOEM(&OemName, FileName);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
_SEH2_LEAVE;
|
||
}
|
||
|
||
pDir->d_namlen = (CCHAR)OemName.Length;
|
||
}
|
||
|
||
pDir->d_ino = Inode;
|
||
pDir->d_reclen = (USHORT)(FFS_DIR_REC_LEN(pDir->d_namlen));
|
||
|
||
dwBytes = 0;
|
||
|
||
Repeat:
|
||
|
||
while ((LONGLONG)dwBytes < Dcb->Header.AllocationSize.QuadPart)
|
||
{
|
||
RtlZeroMemory(pTarget, FFS_DIR_REC_LEN(FFS_NAME_LEN));
|
||
|
||
// Reading the DCB contents
|
||
Status = FFSv1ReadInode(
|
||
NULL,
|
||
Vcb,
|
||
Dcb->dinode1,
|
||
dwBytes,
|
||
(PVOID)pTarget,
|
||
FFS_DIR_REC_LEN(FFS_NAME_LEN),
|
||
&dwRet);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSAddDirectory: Reading Directory Content error.\n"));
|
||
_SEH2_LEAVE;
|
||
}
|
||
|
||
if (((pTarget->d_ino == 0) && pTarget->d_reclen >= pDir->d_reclen) ||
|
||
(pTarget->d_reclen >= FFS_DIR_REC_LEN(pTarget->d_namlen) + pDir->d_reclen))
|
||
{
|
||
if (pTarget->d_ino)
|
||
{
|
||
RtlZeroMemory(pTarget, 2 * FFS_DIR_REC_LEN(FFS_NAME_LEN));
|
||
|
||
// Reading the DCB contents
|
||
Status = FFSv1ReadInode(
|
||
NULL,
|
||
Vcb,
|
||
Dcb->dinode1,
|
||
dwBytes,
|
||
(PVOID)pTarget,
|
||
2 * FFS_DIR_REC_LEN(FFS_NAME_LEN),
|
||
&dwRet);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSAddDirectory: Reading Directory Content error.\n"));
|
||
_SEH2_LEAVE;
|
||
}
|
||
|
||
Length = FFS_DIR_REC_LEN(pTarget->d_namlen);
|
||
|
||
pNewDir = (PFFS_DIR_ENTRY) ((PUCHAR)pTarget + FFS_DIR_REC_LEN(pTarget->d_namlen));
|
||
|
||
pNewDir->d_reclen = pTarget->d_reclen - FFS_DIR_REC_LEN(pTarget->d_namlen);
|
||
|
||
pTarget->d_reclen = FFS_DIR_REC_LEN(pTarget->d_namlen);
|
||
}
|
||
else
|
||
{
|
||
pNewDir = pTarget;
|
||
pNewDir->d_reclen = (USHORT)((ULONG)(Dcb->Header.AllocationSize.QuadPart) - dwBytes);
|
||
}
|
||
|
||
pNewDir->d_type = pDir->d_type;
|
||
pNewDir->d_ino = pDir->d_ino;
|
||
pNewDir->d_namlen = pDir->d_namlen;
|
||
memcpy(pNewDir->d_name, pDir->d_name, pDir->d_namlen);
|
||
Length += FFS_DIR_REC_LEN(pDir->d_namlen);
|
||
|
||
bFound = TRUE;
|
||
break;
|
||
}
|
||
|
||
dwBytes += pTarget->d_reclen;
|
||
}
|
||
|
||
if (bFound)
|
||
{
|
||
ULONG dwRet;
|
||
|
||
if (FileType == DT_DIR)
|
||
{
|
||
if(((pDir->d_namlen == 1) && (pDir->d_name[0] == '.')) ||
|
||
((pDir->d_namlen == 2) && (pDir->d_name[0] == '.') && (pDir->d_name[1] == '.')))
|
||
{
|
||
}
|
||
else
|
||
{
|
||
Dcb->dinode1->di_nlink++;
|
||
}
|
||
}
|
||
|
||
Status = FFSv1WriteInode(IrpContext, Vcb, Dcb->dinode1, dwBytes, pTarget, Length, FALSE, &dwRet);
|
||
}
|
||
else
|
||
{
|
||
// We should expand the size of the dir inode
|
||
if (!bAdding)
|
||
{
|
||
ULONG dwRet;
|
||
|
||
bAdding = FFSExpandInode(IrpContext, Vcb, Dcb, &dwRet);
|
||
|
||
if (bAdding)
|
||
{
|
||
|
||
Dcb->dinode1->di_size = Dcb->Header.AllocationSize.LowPart;
|
||
|
||
FFSv1SaveInode(IrpContext, Vcb, Dcb->FFSMcb->Inode, Dcb->dinode1);
|
||
|
||
Dcb->Header.FileSize = Dcb->Header.AllocationSize;
|
||
|
||
goto Repeat;
|
||
}
|
||
|
||
_SEH2_LEAVE;
|
||
|
||
}
|
||
else // Something must be error!
|
||
{
|
||
_SEH2_LEAVE;
|
||
}
|
||
}
|
||
}
|
||
|
||
_SEH2_FINALLY
|
||
{
|
||
|
||
Dcb->ReferenceCount--;
|
||
|
||
if(MainResourceAcquired)
|
||
{
|
||
ExReleaseResourceForThreadLite(
|
||
&Dcb->MainResource,
|
||
ExGetCurrentResourceThread());
|
||
}
|
||
|
||
if (pTarget != NULL)
|
||
{
|
||
ExFreePool(pTarget);
|
||
}
|
||
|
||
if (pDir)
|
||
{
|
||
ExFreePool(pDir);
|
||
}
|
||
} _SEH2_END;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
NTSTATUS
|
||
FFSRemoveEntry(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb,
|
||
IN PFFS_FCB Dcb,
|
||
IN ULONG FileType,
|
||
IN ULONG Inode)
|
||
{
|
||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||
|
||
PFFS_DIR_ENTRY pTarget = NULL;
|
||
PFFS_DIR_ENTRY pPrevDir = NULL;
|
||
|
||
USHORT PrevRecLen = 0;
|
||
|
||
ULONG Length = 0;
|
||
ULONG dwBytes = 0;
|
||
|
||
BOOLEAN bRet = FALSE;
|
||
BOOLEAN MainResourceAcquired = FALSE;
|
||
|
||
ULONG dwRet;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (!IsDirectory(Dcb))
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
MainResourceAcquired =
|
||
ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
|
||
|
||
_SEH2_TRY
|
||
{
|
||
|
||
Dcb->ReferenceCount++;
|
||
|
||
pTarget = (PFFS_DIR_ENTRY)ExAllocatePoolWithTag(PagedPool,
|
||
FFS_DIR_REC_LEN(FFS_NAME_LEN), FFS_POOL_TAG);
|
||
if (!pTarget)
|
||
{
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
_SEH2_LEAVE;
|
||
}
|
||
|
||
pPrevDir = (PFFS_DIR_ENTRY)ExAllocatePoolWithTag(PagedPool,
|
||
FFS_DIR_REC_LEN(FFS_NAME_LEN), FFS_POOL_TAG);
|
||
if (!pPrevDir)
|
||
{
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
_SEH2_LEAVE;
|
||
}
|
||
|
||
dwBytes = 0;
|
||
|
||
while ((LONGLONG)dwBytes < Dcb->Header.AllocationSize.QuadPart)
|
||
{
|
||
RtlZeroMemory(pTarget, FFS_DIR_REC_LEN(FFS_NAME_LEN));
|
||
|
||
Status = FFSv1ReadInode(
|
||
NULL,
|
||
Vcb,
|
||
Dcb->dinode1,
|
||
dwBytes,
|
||
(PVOID)pTarget,
|
||
FFS_DIR_REC_LEN(FFS_NAME_LEN),
|
||
&dwRet);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSRemoveEntry: Reading Directory Content error.\n"));
|
||
_SEH2_LEAVE;
|
||
}
|
||
|
||
if (pTarget->d_ino == Inode)
|
||
{
|
||
ULONG dwRet;
|
||
ULONG RecLen;
|
||
|
||
if ((PrevRecLen + pTarget->d_reclen) < MAXIMUM_RECORD_LENGTH)
|
||
{
|
||
pPrevDir->d_reclen += pTarget->d_reclen;
|
||
RecLen = FFS_DIR_REC_LEN(pTarget->d_namlen);
|
||
|
||
RtlZeroMemory(pTarget, RecLen);
|
||
|
||
FFSv1WriteInode(IrpContext, Vcb, Dcb->dinode1, dwBytes - PrevRecLen, pPrevDir, 8, FALSE, &dwRet);
|
||
FFSv1WriteInode(IrpContext, Vcb, Dcb->dinode1, dwBytes, pTarget, RecLen, FALSE, &dwRet);
|
||
}
|
||
else
|
||
{
|
||
RecLen = (ULONG)pTarget->d_reclen;
|
||
if (RecLen > FFS_DIR_REC_LEN(FFS_NAME_LEN))
|
||
{
|
||
RtlZeroMemory(pTarget, FFS_DIR_REC_LEN(FFS_NAME_LEN));
|
||
}
|
||
else
|
||
{
|
||
RtlZeroMemory(pTarget, RecLen);
|
||
}
|
||
|
||
pTarget->d_reclen = (USHORT)RecLen;
|
||
|
||
FFSv1WriteInode(IrpContext, Vcb, Dcb->dinode1, dwBytes, pTarget, RecLen, FALSE, &dwRet);
|
||
}
|
||
|
||
if (FileType == DT_DIR)
|
||
{
|
||
if(((pTarget->d_namlen == 1) && (pTarget->d_name[0] == '.')) ||
|
||
((pTarget->d_namlen == 2) && (pTarget->d_name[0] == '.') && (pTarget->d_name[1] == '.')))
|
||
{
|
||
FFSBreakPoint();
|
||
}
|
||
else
|
||
{
|
||
Dcb->dinode1->di_nlink--;
|
||
}
|
||
}
|
||
|
||
/* Update at least mtime/atime if !FFS_FT_DIR. */
|
||
FFSv1SaveInode(IrpContext, Vcb, Dcb->FFSMcb->Inode, Dcb->dinode1);
|
||
|
||
bRet = TRUE;
|
||
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
RtlCopyMemory(pPrevDir, pTarget, FFS_DIR_REC_LEN(FFS_NAME_LEN));
|
||
PrevRecLen = pTarget->d_reclen;
|
||
}
|
||
|
||
dwBytes += pTarget->d_reclen;
|
||
}
|
||
}
|
||
|
||
_SEH2_FINALLY
|
||
{
|
||
|
||
Dcb->ReferenceCount--;
|
||
|
||
if(MainResourceAcquired)
|
||
ExReleaseResourceForThreadLite(
|
||
&Dcb->MainResource,
|
||
ExGetCurrentResourceThread());
|
||
|
||
if (pTarget != NULL)
|
||
{
|
||
ExFreePool(pTarget);
|
||
}
|
||
|
||
if (pPrevDir != NULL)
|
||
{
|
||
ExFreePool(pPrevDir);
|
||
}
|
||
} _SEH2_END;
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
NTSTATUS
|
||
FFSSetParentEntry(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb,
|
||
IN PFFS_FCB Dcb,
|
||
IN ULONG OldParent,
|
||
IN ULONG NewParent)
|
||
{
|
||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||
|
||
PFFS_DIR_ENTRY pSelf = NULL;
|
||
PFFS_DIR_ENTRY pParent = NULL;
|
||
|
||
ULONG dwBytes = 0;
|
||
|
||
BOOLEAN MainResourceAcquired = FALSE;
|
||
|
||
ULONG Offset = 0;
|
||
|
||
if (!IsDirectory(Dcb))
|
||
{
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
return Status;
|
||
}
|
||
|
||
MainResourceAcquired =
|
||
ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
|
||
|
||
_SEH2_TRY
|
||
{
|
||
Dcb->ReferenceCount++;
|
||
|
||
pSelf = (PFFS_DIR_ENTRY)ExAllocatePoolWithTag(PagedPool,
|
||
FFS_DIR_REC_LEN(1) + FFS_DIR_REC_LEN(2), FFS_POOL_TAG);
|
||
if (!pSelf)
|
||
{
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
_SEH2_LEAVE;
|
||
}
|
||
|
||
dwBytes = 0;
|
||
|
||
// Reading the DCB contents
|
||
Status = FFSv1ReadInode(
|
||
NULL,
|
||
Vcb,
|
||
Dcb->dinode1,
|
||
Offset,
|
||
(PVOID)pSelf,
|
||
FFS_DIR_REC_LEN(1) + FFS_DIR_REC_LEN(2),
|
||
&dwBytes);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSSetParentEntry: Reading Directory Content error.\n"));
|
||
_SEH2_LEAVE;
|
||
}
|
||
|
||
ASSERT(dwBytes == FFS_DIR_REC_LEN(1) + FFS_DIR_REC_LEN(2));
|
||
|
||
pParent = (PFFS_DIR_ENTRY)((PUCHAR)pSelf + pSelf->d_reclen);
|
||
|
||
if (pParent->d_ino != OldParent)
|
||
{
|
||
FFSBreakPoint();
|
||
}
|
||
|
||
pParent->d_ino = NewParent;
|
||
|
||
Status = FFSv1WriteInode(IrpContext,
|
||
Vcb,
|
||
Dcb->dinode1,
|
||
Offset,
|
||
pSelf,
|
||
dwBytes,
|
||
FALSE,
|
||
&dwBytes);
|
||
}
|
||
|
||
_SEH2_FINALLY
|
||
{
|
||
Dcb->ReferenceCount--;
|
||
|
||
if(MainResourceAcquired)
|
||
{
|
||
ExReleaseResourceForThreadLite(
|
||
&Dcb->MainResource,
|
||
ExGetCurrentResourceThread());
|
||
}
|
||
|
||
if (pSelf)
|
||
{
|
||
ExFreePool(pSelf);
|
||
}
|
||
} _SEH2_END;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
BOOLEAN
|
||
FFSTruncateBlock(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb,
|
||
IN PFFS_FCB Fcb,
|
||
IN ULONG dwContent,
|
||
IN ULONG Index,
|
||
IN ULONG layer,
|
||
OUT BOOLEAN *bFreed)
|
||
{
|
||
ULONG *pData = NULL;
|
||
ULONG i = 0, j = 0, temp = 1;
|
||
BOOLEAN bDirty = FALSE;
|
||
BOOLEAN bRet = FALSE;
|
||
ULONG dwBlk;
|
||
|
||
LONGLONG Offset;
|
||
|
||
PBCB Bcb;
|
||
|
||
PFFSv1_INODE dinode1 = Fcb->dinode1;
|
||
|
||
PAGED_CODE();
|
||
|
||
*bFreed = FALSE;
|
||
|
||
if (layer == 0)
|
||
{
|
||
//if (dwContent > 0 && dwContent < (BLOCKS_PER_GROUP * Vcb->ffs_groups))
|
||
if (dwContent > 0)
|
||
{
|
||
bRet = FFSFreeBlock(IrpContext, Vcb, dwContent);
|
||
|
||
if (bRet)
|
||
{
|
||
ASSERT(dinode1->di_blocks >= (Vcb->BlockSize / SECTOR_SIZE));
|
||
dinode1->di_blocks -= (Vcb->BlockSize / SECTOR_SIZE);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
FFSBreakPoint();
|
||
bRet = FALSE;
|
||
}
|
||
|
||
*bFreed = bRet;
|
||
}
|
||
else if (layer <= 3)
|
||
{
|
||
Offset = (LONGLONG)dwContent;
|
||
Offset = Offset * Vcb->BlockSize;
|
||
|
||
if(!CcPinRead(Vcb->StreamObj,
|
||
(PLARGE_INTEGER)(&Offset),
|
||
Vcb->BlockSize,
|
||
PIN_WAIT,
|
||
&Bcb,
|
||
&pData))
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSSaveBuffer: PinReading error ...\n"));
|
||
goto errorout;
|
||
}
|
||
|
||
temp = 1 << ((BLOCK_BITS - 2) * (layer - 1));
|
||
|
||
i = Index / temp;
|
||
j = Index % temp;
|
||
|
||
dwBlk = pData[i];
|
||
|
||
if(!FFSTruncateBlock(IrpContext, Vcb, Fcb, dwBlk, j, layer - 1, &bDirty))
|
||
{
|
||
goto errorout;
|
||
}
|
||
|
||
if (bDirty)
|
||
{
|
||
pData[i] = 0;
|
||
}
|
||
|
||
if (i == 0 && j == 0)
|
||
{
|
||
CcUnpinData(Bcb);
|
||
pData = NULL;
|
||
|
||
*bFreed = TRUE;
|
||
bRet = FFSFreeBlock(IrpContext, Vcb, dwContent);
|
||
|
||
if (bRet)
|
||
{
|
||
ASSERT(dinode1->di_blocks >= (Vcb->BlockSize / SECTOR_SIZE));
|
||
dinode1->di_blocks -= (Vcb->BlockSize / SECTOR_SIZE);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
CcSetDirtyPinnedData(Bcb, NULL);
|
||
FFSRepinBcb(IrpContext, Bcb);
|
||
|
||
FFSAddMcbEntry(Vcb, Offset, (LONGLONG)Vcb->BlockSize);
|
||
|
||
bRet = TRUE;
|
||
*bFreed = FALSE;
|
||
}
|
||
}
|
||
|
||
errorout:
|
||
|
||
if (pData)
|
||
{
|
||
CcUnpinData(Bcb);
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
FFSTruncateInode(
|
||
IN PFFS_IRP_CONTEXT IrpContext,
|
||
IN PFFS_VCB Vcb,
|
||
IN PFFS_FCB Fcb)
|
||
{
|
||
ULONG dwSizes[FFS_BLOCK_TYPES];
|
||
ULONG Index = 0;
|
||
ULONG dwTotal = 0;
|
||
ULONG dwBlk = 0;
|
||
|
||
ULONG i;
|
||
BOOLEAN bRet = FALSE;
|
||
BOOLEAN bFreed = FALSE;
|
||
|
||
PFFSv1_INODE dinode1 = Fcb->dinode1;
|
||
|
||
PAGED_CODE();
|
||
|
||
Index = (ULONG)(Fcb->Header.AllocationSize.QuadPart >> BLOCK_BITS);
|
||
|
||
if (Index > 0)
|
||
{
|
||
Index--;
|
||
}
|
||
else
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
for (i = 0; i < FFS_BLOCK_TYPES; i++)
|
||
{
|
||
dwSizes[i] = Vcb->dwData[i];
|
||
dwTotal += dwSizes[i];
|
||
}
|
||
|
||
if (Index >= dwTotal)
|
||
{
|
||
FFSPrint((DBG_ERROR, "FFSTruncateInode: beyond the maxinum size of an inode.\n"));
|
||
return TRUE;
|
||
}
|
||
|
||
for (i = 0; i < FFS_BLOCK_TYPES; i++)
|
||
{
|
||
#if 0
|
||
if (Index < dwSizes[i])
|
||
{
|
||
dwBlk = Inode->i_block[i == 0 ? (Index) : (i + NDADDR - 1)];
|
||
|
||
bRet = FFSTruncateBlock(IrpContext, Vcb, Fcb, dwBlk, Index , i, &bFreed);
|
||
|
||
if (bRet)
|
||
{
|
||
Fcb->Header.AllocationSize.QuadPart -= Vcb->BlockSize;
|
||
|
||
if (bFreed)
|
||
{
|
||
Inode->i_block[i == 0 ? (Index) : (i + NDADDR - 1)] = 0;
|
||
}
|
||
}
|
||
|
||
break;
|
||
}
|
||
#endif
|
||
Index -= dwSizes[i];
|
||
}
|
||
|
||
{
|
||
ASSERT(FFSDataBlocks(Vcb, (ULONG)(dinode1->di_blocks / (BLOCK_SIZE / SECTOR_SIZE)))
|
||
== (Fcb->Header.AllocationSize.QuadPart / BLOCK_SIZE));
|
||
|
||
ASSERT(FFSTotalBlocks(Vcb, (ULONG)(Fcb->Header.AllocationSize.QuadPart / BLOCK_SIZE))
|
||
== (dinode1->di_blocks / (BLOCK_SIZE / SECTOR_SIZE)));
|
||
|
||
}
|
||
|
||
//
|
||
// Inode struct saving is done externally.
|
||
//
|
||
|
||
FFSv1SaveInode(IrpContext, Vcb, Fcb->FFSMcb->Inode, dinode1);
|
||
|
||
|
||
return bRet;
|
||
}
|
||
|
||
#endif // !FFS_READ_ONLY
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
BOOLEAN
|
||
FFSAddMcbEntry(
|
||
IN PFFS_VCB Vcb,
|
||
IN LONGLONG Lba,
|
||
IN LONGLONG Length)
|
||
{
|
||
BOOLEAN bRet = FALSE;
|
||
|
||
LONGLONG Offset;
|
||
|
||
#if DBG
|
||
LONGLONG DirtyLba;
|
||
LONGLONG DirtyLen;
|
||
#endif
|
||
|
||
PAGED_CODE();
|
||
|
||
Offset = Lba & (~((LONGLONG)BLOCK_SIZE - 1));
|
||
|
||
Length = (Length + Lba - Offset + BLOCK_SIZE - 1) &
|
||
(~((LONGLONG)BLOCK_SIZE - 1));
|
||
|
||
ASSERT ((Offset & (BLOCK_SIZE - 1)) == 0);
|
||
ASSERT ((Length & (BLOCK_SIZE - 1)) == 0);
|
||
|
||
Offset = (Offset >> BLOCK_BITS) + 1;
|
||
Length = (Length >>BLOCK_BITS);
|
||
|
||
ExAcquireResourceExclusiveLite(
|
||
&(Vcb->McbResource),
|
||
TRUE);
|
||
|
||
FFSPrint((DBG_INFO, "FFSAddMcbEntry: Lba=%I64xh Length=%I64xh\n",
|
||
Offset, Length));
|
||
|
||
#if DBG
|
||
bRet = FsRtlLookupLargeMcbEntry(
|
||
&(Vcb->DirtyMcbs),
|
||
Offset,
|
||
&DirtyLba,
|
||
&DirtyLen,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
|
||
if (bRet && DirtyLba == Offset && DirtyLen >= Length)
|
||
{
|
||
FFSPrint((DBG_INFO, "FFSAddMcbEntry: this run already exists.\n"));
|
||
}
|
||
#endif
|
||
|
||
_SEH2_TRY
|
||
{
|
||
bRet = FsRtlAddLargeMcbEntry(
|
||
&(Vcb->DirtyMcbs),
|
||
Offset, Offset,
|
||
Length);
|
||
|
||
}
|
||
_SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
FFSBreakPoint();
|
||
bRet = FALSE;
|
||
} _SEH2_END;
|
||
|
||
#if DBG
|
||
if (bRet)
|
||
{
|
||
BOOLEAN bFound = FALSE;
|
||
LONGLONG RunStart;
|
||
LONGLONG RunLength;
|
||
ULONG Index;
|
||
|
||
bFound = FsRtlLookupLargeMcbEntry(
|
||
&(Vcb->DirtyMcbs),
|
||
Offset,
|
||
&DirtyLba,
|
||
&DirtyLen,
|
||
&RunStart,
|
||
&RunLength,
|
||
&Index);
|
||
|
||
if ((!bFound) || (DirtyLba == -1) ||
|
||
(DirtyLba != Offset) || (DirtyLen < Length))
|
||
{
|
||
LONGLONG DirtyVba;
|
||
LONGLONG DirtyLba;
|
||
LONGLONG DirtyLength;
|
||
|
||
FFSBreakPoint();
|
||
|
||
for (Index = 0;
|
||
FsRtlGetNextLargeMcbEntry(&(Vcb->DirtyMcbs),
|
||
Index,
|
||
&DirtyVba,
|
||
&DirtyLba,
|
||
&DirtyLength);
|
||
Index++)
|
||
{
|
||
FFSPrint((DBG_INFO, "Index = %xh\n", Index));
|
||
FFSPrint((DBG_INFO, "DirtyVba = %I64xh\n", DirtyVba));
|
||
FFSPrint((DBG_INFO, "DirtyLba = %I64xh\n", DirtyLba));
|
||
FFSPrint((DBG_INFO, "DirtyLen = %I64xh\n\n", DirtyLength));
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
ExReleaseResourceForThreadLite(
|
||
&(Vcb->McbResource),
|
||
ExGetCurrentResourceThread());
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
VOID
|
||
FFSRemoveMcbEntry(
|
||
IN PFFS_VCB Vcb,
|
||
IN LONGLONG Lba,
|
||
IN LONGLONG Length)
|
||
{
|
||
LONGLONG Offset;
|
||
|
||
PAGED_CODE();
|
||
|
||
Offset = Lba & (~((LONGLONG)BLOCK_SIZE - 1));
|
||
|
||
Length = (Length + Lba - Offset + BLOCK_SIZE - 1) &
|
||
(~((LONGLONG)BLOCK_SIZE - 1));
|
||
|
||
ASSERT(Offset == Lba);
|
||
|
||
ASSERT ((Offset & (BLOCK_SIZE - 1)) == 0);
|
||
ASSERT ((Length & (BLOCK_SIZE - 1)) == 0);
|
||
|
||
Offset = (Offset >> BLOCK_BITS) + 1;
|
||
Length = (Length >> BLOCK_BITS);
|
||
|
||
FFSPrint((DBG_INFO, "FFSRemoveMcbEntry: Lba=%I64xh Length=%I64xh\n",
|
||
Offset, Length));
|
||
|
||
ExAcquireResourceExclusiveLite(
|
||
&(Vcb->McbResource),
|
||
TRUE);
|
||
|
||
_SEH2_TRY
|
||
{
|
||
FsRtlRemoveLargeMcbEntry(
|
||
&(Vcb->DirtyMcbs),
|
||
Offset, Length);
|
||
|
||
}
|
||
_SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
FFSBreakPoint();
|
||
} _SEH2_END;
|
||
|
||
#if DBG
|
||
{
|
||
BOOLEAN bFound = FALSE;
|
||
LONGLONG DirtyLba, DirtyLen;
|
||
|
||
bFound = FsRtlLookupLargeMcbEntry(
|
||
&(Vcb->DirtyMcbs),
|
||
Offset,
|
||
&DirtyLba,
|
||
&DirtyLen,
|
||
NULL,
|
||
NULL,
|
||
NULL);
|
||
|
||
if (bFound &&(DirtyLba != -1))
|
||
{
|
||
FFSBreakPoint();
|
||
}
|
||
}
|
||
#endif
|
||
|
||
ExReleaseResourceForThreadLite(
|
||
&(Vcb->McbResource),
|
||
ExGetCurrentResourceThread());
|
||
}
|
||
|
||
|
||
__drv_mustHoldCriticalRegion
|
||
BOOLEAN
|
||
FFSLookupMcbEntry(
|
||
IN PFFS_VCB Vcb,
|
||
IN LONGLONG Lba,
|
||
OUT PLONGLONG pLba,
|
||
OUT PLONGLONG pLength,
|
||
OUT PLONGLONG RunStart,
|
||
OUT PLONGLONG RunLength,
|
||
OUT PULONG Index)
|
||
{
|
||
BOOLEAN bRet;
|
||
LONGLONG Offset;
|
||
|
||
PAGED_CODE();
|
||
|
||
Offset = Lba & (~((LONGLONG)BLOCK_SIZE - 1));
|
||
ASSERT ((Offset & (BLOCK_SIZE - 1)) == 0);
|
||
|
||
ASSERT(Lba == Offset);
|
||
|
||
Offset = (Offset >> BLOCK_BITS) + 1;
|
||
|
||
ExAcquireResourceExclusiveLite(
|
||
&(Vcb->McbResource),
|
||
TRUE);
|
||
|
||
bRet = FsRtlLookupLargeMcbEntry(
|
||
&(Vcb->DirtyMcbs),
|
||
Offset,
|
||
pLba,
|
||
pLength,
|
||
RunStart,
|
||
RunLength,
|
||
Index);
|
||
|
||
ExReleaseResourceForThreadLite(
|
||
&(Vcb->McbResource),
|
||
ExGetCurrentResourceThread());
|
||
|
||
if (bRet)
|
||
{
|
||
if (pLba && ((*pLba) != -1))
|
||
{
|
||
ASSERT((*pLba) > 0);
|
||
|
||
(*pLba) = (((*pLba) - 1) << BLOCK_BITS);
|
||
(*pLba) += ((Lba) & ((LONGLONG)BLOCK_SIZE - 1));
|
||
}
|
||
|
||
if (pLength)
|
||
{
|
||
(*pLength) <<= BLOCK_BITS;
|
||
(*pLength) -= ((Lba) & ((LONGLONG)BLOCK_SIZE - 1));
|
||
}
|
||
|
||
if (RunStart && (*RunStart != -1))
|
||
{
|
||
(*RunStart) = (((*RunStart) - 1) << BLOCK_BITS);
|
||
}
|
||
|
||
if (RunLength)
|
||
{
|
||
(*RunLength) <<= BLOCK_BITS;
|
||
}
|
||
}
|
||
|
||
return bRet;
|
||
}
|
||
|
||
|
||
ULONG
|
||
FFSDataBlocks(
|
||
PFFS_VCB Vcb,
|
||
ULONG TotalBlocks)
|
||
{
|
||
ULONG dwData[FFS_BLOCK_TYPES];
|
||
ULONG dwMeta[FFS_BLOCK_TYPES];
|
||
ULONG DataBlocks = 0;
|
||
ULONG i, j;
|
||
|
||
if (TotalBlocks <= NDADDR)
|
||
{
|
||
return TotalBlocks;
|
||
}
|
||
|
||
TotalBlocks -= NDADDR;
|
||
|
||
for (i = 0; i < FFS_BLOCK_TYPES; i++)
|
||
{
|
||
if (i == 0)
|
||
{
|
||
dwData[i] = 1;
|
||
}
|
||
else
|
||
{
|
||
dwData[i] = Vcb->dwData[i];
|
||
}
|
||
|
||
dwMeta[i] = Vcb->dwMeta[i];
|
||
}
|
||
|
||
for(i = 1; (i < FFS_BLOCK_TYPES) && (TotalBlocks > 0); i++)
|
||
{
|
||
if (TotalBlocks >= (dwData[i] + dwMeta[i]))
|
||
{
|
||
TotalBlocks -= (dwData[i] + dwMeta[i]);
|
||
DataBlocks += dwData[i];
|
||
}
|
||
else
|
||
{
|
||
ULONG dwDivide = 0;
|
||
ULONG dwRemain = 0;
|
||
|
||
for (j = i; (j > 0) && (TotalBlocks > 0); j--)
|
||
{
|
||
dwDivide = (TotalBlocks - 1) / (dwData[j - 1] + dwMeta[j - 1]);
|
||
dwRemain = (TotalBlocks - 1) % (dwData[j - 1] + dwMeta[j - 1]);
|
||
|
||
DataBlocks += (dwDivide * dwData[j - 1]);
|
||
TotalBlocks = dwRemain;
|
||
}
|
||
}
|
||
}
|
||
|
||
return (DataBlocks + NDADDR);
|
||
}
|
||
|
||
|
||
ULONG
|
||
FFSTotalBlocks(
|
||
PFFS_VCB Vcb,
|
||
ULONG DataBlocks)
|
||
{
|
||
ULONG dwData[FFS_BLOCK_TYPES];
|
||
ULONG dwMeta[FFS_BLOCK_TYPES];
|
||
ULONG TotalBlocks = 0;
|
||
ULONG i, j;
|
||
|
||
if (DataBlocks <= NDADDR)
|
||
{
|
||
return DataBlocks;
|
||
}
|
||
|
||
DataBlocks -= NDADDR;
|
||
|
||
for (i = 0; i < FFS_BLOCK_TYPES; i++)
|
||
{
|
||
if (i == 0)
|
||
{
|
||
dwData[i] = 1;
|
||
}
|
||
else
|
||
{
|
||
dwData[i] = Vcb->dwData[i];
|
||
}
|
||
|
||
dwMeta[i] = Vcb->dwMeta[i];
|
||
}
|
||
|
||
for(i = 1; (i < FFS_BLOCK_TYPES) && (DataBlocks > 0); i++)
|
||
{
|
||
if (DataBlocks >= dwData[i])
|
||
{
|
||
DataBlocks -= dwData[i];
|
||
TotalBlocks += (dwData[i] + dwMeta[i]);
|
||
}
|
||
else
|
||
{
|
||
ULONG dwDivide = 0;
|
||
ULONG dwRemain = 0;
|
||
|
||
for (j = i; (j > 0) && (DataBlocks > 0); j--)
|
||
{
|
||
dwDivide = (DataBlocks) / (dwData[j - 1]);
|
||
dwRemain = (DataBlocks) % (dwData[j - 1]);
|
||
|
||
TotalBlocks += (dwDivide * (dwData[j - 1] + dwMeta[j - 1]) + 1);
|
||
DataBlocks = dwRemain;
|
||
}
|
||
}
|
||
}
|
||
|
||
return (TotalBlocks + NDADDR);
|
||
}
|