Closed. This question needs to be more focused。它当前不接受答案。
想改善这个问题吗?更新问题,使其仅通过editing this post专注于一个问题。
去年关闭。
我想使用C读取本地系统的MFT。
我在整个互联网上搜索解决方案,但未找到任何解决方案。
我希望有人为我准备一个教程或一个很好的解释,并提供有关如何执行此操作的代码示例。
提前致谢。
想改善这个问题吗?更新问题,使其仅通过editing this post专注于一个问题。
去年关闭。
我想使用C读取本地系统的MFT。
我在整个互联网上搜索解决方案,但未找到任何解决方案。
我希望有人为我准备一个教程或一个很好的解释,并提供有关如何执行此操作的代码示例。
提前致谢。
最佳答案
首先,我们需要FILE_READ_DATA
打开音量句柄。
那么我们需要使用NTFS_VOLUME_DATA_BUFFER
控制代码查询FSCTL_GET_NTFS_VOLUME_DATA
从这里我们得到单个MFT记录的大小-BytesPerFileRecordSegment
,MFT的总大小-MftValidDataLength
。因此最大记录数为(MftValidDataLength.QuadPart / BytesPerFileRecordSegment)
正确的方法(与ntfs同步)将通过FSCTL_GET_NTFS_FILE_RECORD
读取单个记录。
如果要一次读取多个记录-当然可以直接从卷中读取。我们有MFT的起始LCN-MftStartLcn
。但是MFT可以有几个不连续的片段。因此,如果要获取所有片段位置,则需要使用FSCTL_GET_RETRIEVAL_POINTERS
。将LCN转换为体积偏移量需要将其倍数为BytesPerCluster
演示代码:
void ReadMft(PCWSTR szVolume)
{
HANDLE hVolume = CreateFileW(szVolume, FILE_READ_DATA, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, FILE_OPEN_FOR_BACKUP_INTENT, 0);
if (hVolume != INVALID_HANDLE_VALUE)
{
NTFS_VOLUME_DATA_BUFFER nvdb;
OVERLAPPED ov = {};
if (DeviceIoControl(hVolume, FSCTL_GET_NTFS_VOLUME_DATA, 0, 0, &nvdb, sizeof(nvdb), 0, &ov))
{
NTFS_FILE_RECORD_INPUT_BUFFER nfrib;
nfrib.FileReferenceNumber.QuadPart = nvdb.MftValidDataLength.QuadPart / nvdb.BytesPerFileRecordSegment - 1;
ULONG cb = __builtin_offsetof(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer[nvdb.BytesPerFileRecordSegment]);
PNTFS_FILE_RECORD_OUTPUT_BUFFER pnfrob = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)alloca(cb);
do
{
if (!DeviceIoControl(hVolume, FSCTL_GET_NTFS_FILE_RECORD,
&nfrib, sizeof(nfrib), pnfrob, cb, 0, &ov))
{
break;
}
// pnfrob->FileRecordBuffer :
// here pnfrob->FileReferenceNumber FileRecord
} while (0 <= (nfrib.FileReferenceNumber.QuadPart = pnfrob->FileReferenceNumber.QuadPart - 1));
ReadMft2(szVolume, hVolume, &nvdb);
}
CloseHandle(hVolume);
}
}
void ReadMft2(PCWSTR szVolume, HANDLE hVolume, PNTFS_VOLUME_DATA_BUFFER nvdb)
{
static PCWSTR MFT = L"\\$MFT";
static STARTING_VCN_INPUT_BUFFER vcn {};
static volatile UCHAR guz;
PVOID stack = alloca(guz);
union {
PVOID buf;
PWSTR lpFileName;
PRETRIEVAL_POINTERS_BUFFER rpb;
};
buf = alloca(wcslen(szVolume) * sizeof(WCHAR) + sizeof(MFT));
wcscat(wcscpy(lpFileName, szVolume), MFT);
HANDLE hFile = CreateFileW(lpFileName, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, FILE_OPEN_FOR_BACKUP_INTENT, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
OVERLAPPED ov{};
ULONG cb = RtlPointerToOffset(buf, stack), rcb, ExtentCount = 2;
do
{
rcb = __builtin_offsetof(RETRIEVAL_POINTERS_BUFFER, Extents[ExtentCount]);
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (DeviceIoControl(hFile, FSCTL_GET_RETRIEVAL_POINTERS, &vcn, sizeof(vcn), buf, cb, 0, &ov))
{
if (rpb->Extents->Lcn.QuadPart != nvdb->MftStartLcn.QuadPart)
{
__debugbreak();
}
if (ExtentCount = rpb->ExtentCount)
{
auto Extents = rpb->Extents;
ULONG BytesPerCluster = nvdb->BytesPerCluster;
ULONG BytesPerFileRecordSegment = nvdb->BytesPerFileRecordSegment;
LONGLONG StartingVcn = rpb->StartingVcn.QuadPart, NextVcn, len;
PVOID FileRecordBuffer = alloca(BytesPerFileRecordSegment);
do
{
NextVcn = Extents->NextVcn.QuadPart;
len = NextVcn - StartingVcn, StartingVcn = NextVcn;
DbgPrint("%I64x %I64x\n", Extents->Lcn.QuadPart, len);
if (Extents->Lcn.QuadPart != -1)
{
Extents->Lcn.QuadPart *= BytesPerCluster;
ov.Offset = Extents->Lcn.LowPart;
ov.OffsetHigh = Extents->Lcn.HighPart;
// read 1 record
ReadFile(hVolume, FileRecordBuffer, BytesPerFileRecordSegment, 0, &ov);
}
} while (Extents++, --ExtentCount);
}
break;
}
ExtentCount <<= 1;
} while (GetLastError() == ERROR_MORE_DATA);
CloseHandle(hFile);
}
}
关于c - 如何使用C读取主文件表(MFT)? ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54606760/
10-12 00:01