📄 ffs.c
字号:
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;
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)
{
#if 0
RTL_BITMAP InodeBitmap;
PVOID BitmapCache;
PBCB BitmapBcb;
ULONG Group, i, j;
ULONG Average, Length;
LARGE_INTEGER Offset;
ULONG dwInode;
*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)
{
#if 0
RTL_BITMAP InodeBitmap;
PVOID BitmapCache;
PBCB BitmapBcb;
ULONG Group;
ULONG Length;
LARGE_INTEGER Offset;
ULONG dwIno;
BOOLEAN bModified = FALSE;
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;
}
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;
if (!IsDirectory(Dcb))
{
FFSBreakPoint();
Status = STATUS_INVALID_PARAMETER;
return Status;
}
MainResourceAcquired = ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
__try
{
Dcb->ReferenceCount++;
pDir = (PFFS_DIR_ENTRY)ExAllocatePool(PagedPool,
FFS_DIR_REC_LEN(FFS_NAME_LEN));
if (!pDir)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
pTarget = (PFFS_DIR_ENTRY)ExAllocatePool(PagedPool,
2 * FFS_DIR_REC_LEN(FFS_NAME_LEN));
if (!pTarget)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
__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))
{
__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"));
__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"));
__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;
}
__leave;
}
else // Something must be error!
{
__leave;
}
}
}
__finally
{
Dcb->ReferenceCount--;
if(MainResourceAcquired)
{
ExReleaseResourceForThreadLite(
&Dcb->MainResource,
ExGetCurrentResourceThread());
}
if (pTarget != NULL)
{
ExFreePool(pTarget);
}
if (pDir)
{
ExFreePool(pDir);
}
}
return Status;
}
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;
if (!IsDirectory(Dcb))
{
return FALSE;
}
MainResourceAcquired =
ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
__try
{
Dcb->ReferenceCount++;
pTarget = (PFFS_DIR_ENTRY)ExAllocatePool(PagedPool,
FFS_DIR_REC_LEN(FFS_NAME_LEN));
if (!pTarget)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
pPrevDir = (PFFS_DIR_ENTRY)ExAllocatePool(PagedPool,
FFS_DIR_REC_LEN(FFS_NAME_LEN));
if (!pPrevDir)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
__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"));
__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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -