📄 ffs.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;
FFSSb = (PFFS_SUPER_BLOCK)ExAllocatePool(PagedPool, SUPER_BLOCK_SIZE);
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;
}
BOOLEAN
FFSSaveSuper(
IN PFFS_IRP_CONTEXT IrpContext,
IN PFFS_VCB Vcb)
{
LONGLONG Offset;
BOOLEAN bRet;
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;
}
#if 0
BOOLEAN
FFSLoadGroup(
IN PFFS_VCB Vcb)
{
ULONG Size;
PVOID Buffer;
LONGLONG Lba;
NTSTATUS Status;
PFFS_SUPER_BLOCK FFSSb;
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 = ExAllocatePool(PagedPool, Size);
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;
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;
#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;
#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;
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;
if (!FFSv2GetInodeLba(Vcb, inode, &Offset))
{
FFSPrint((DBG_ERROR, "FFSv2LoadInode: error get inode(%xh)'s addr.\n", inode));
return FALSE;
}
Offset += (LONGLONG)FFSGlobal->FSOffset[FFSGlobal->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;
}
*/
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;
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;
}
BOOLEAN
FFSv2SaveInode(
IN PFFS_IRP_CONTEXT IrpContext,
IN PFFS_VCB Vcb,
IN ULONG Inode,
IN PFFSv2_INODE dinode2)
{
return FALSE;
}
BOOLEAN
FFSv1LoadBlock(
IN PFFS_VCB Vcb,
IN ULONG dwBlk,
IN PVOID Buffer)
{
IO_STATUS_BLOCK IoStatus;
LONGLONG Offset;
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;
Offset = (LONGLONG)dwBlk;
Offset = Offset * SUPER_BLOCK->fs_fsize; // fragment size
Offset += FFSGlobal->FSOffset[FFSGlobal->PartitionNumber];
if (!FFSCopyRead(
Vcb->StreamObj,
(PLARGE_INTEGER)&Offset,
Vcb->BlockSize,
PIN_WAIT,
Buffer,
&IoStatus));
if (!NT_SUCCESS(IoStatus.Status))
{
return FALSE;
}
return TRUE;
}
BOOLEAN
FFSSaveBlock(
IN PFFS_IRP_CONTEXT IrpContext,
IN PFFS_VCB Vcb,
IN ULONG dwBlk,
IN PVOID Buf)
{
LONGLONG Offset;
BOOLEAN bRet;
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;
}
BOOLEAN
FFSSaveBuffer(
IN PFFS_IRP_CONTEXT IrpContext,
IN PFFS_VCB Vcb,
IN LONGLONG Offset,
IN ULONG Size,
IN PVOID Buf)
{
PBCB Bcb;
PVOID Buffer;
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;
}
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;
if (layer == 0)
{
dwBlk = dwContent;
}
else if (layer <= 3)
{
pData = (ULONG *)ExAllocatePool(PagedPool,
Vcb->BlockSize);
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;
if (layer == 0)
{
dwBlk = dwContent;
}
else if (layer <= 3)
{
pData = (ULONGLONG *)ExAllocatePool(PagedPool,
Vcb->BlockSize);
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;
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;
}
/* 流立, 埃立, 2吝 埃立 贸府 */
for (i = 0; i < FFS_BLOCK_TYPES; i++)
{
if (Index < dwSizes[i])
{
if (i == 0)
dwBlk = dinode1->di_db[Index]; /* 流立 */
else
dwBlk = dinode1->di_ib[i - 1]; /* 埃立 */
#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;
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;
}
/* 流立, 埃立, 2吝 埃立 贸府 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -