遍历更改日记记录的缓冲区
返回更新序列号 (USN) 更改日记记录的控制代码 ,FSCTL_READ_USN_JOURNAL 和 FSCTL_ENUM_USN_DATA在输出缓冲区中返回类似的数据。 两者都返回一个 USN,后跟零个或多个更改日记记录,每个记录采用 USN_RECORD_V2 或 USN_RECORD_V3 结构。
USN 操作的目标卷必须是 ReFS 或 NTFS 3.0 或更高版本。 若要获取卷的 NTFS 版本,请使用管理员访问权限打开命令提示符并执行以下命令:
FSUtil.exe FSInfo NTFSInfoX**:**
其中 X 是卷的驱动器号。
以下列表标识了获取更改日记记录的方法:
- 使用 FSCTL_ENUM_USN_DATA 获取两个 USN 之间所有更改日记记录的列表 (枚举) 。
- 使用 FSCTL_READ_USN_JOURNAL 更具选择性,例如选择更改的特定原因或在关闭文件时返回。
注意
这两个操作仅返回满足指定条件的更改日记记录的子集。
作为输出缓冲区中第一项返回的 USN 是要检索的下一个记录编号的 USN。 使用此值可继续从结束边界向前读取记录。
USN_RECORD_V2 或 USN_RECORD_V3 的 FileName 成员包含所适用的记录的文件的名称。 文件名的长度各不相同,因此 USN_RECORD_V2 和 USN_RECORD_V3 是可变长度结构。 其第一个成员 RecordLength 是结构的长度, (包括文件名) (以字节为单位)。
使用 USN_RECORD_V2 和 USN_RECORD_V3 结构的 FileName 成员时,不要假定文件名包含尾随“\0”分隔符。 若要确定文件名的长度,请使用 FileNameLength 成员。
以下示例调用 FSCTL_READ_USN_JOURNAL 并遍历操作返回的更改日记记录的缓冲区。
#include <Windows.h>
#include <WinIoCtl.h>
#include <stdio.h>
#define BUF_LEN 4096
void main()
{
HANDLE hVol;
CHAR Buffer[BUF_LEN];
USN_JOURNAL_DATA JournalData;
READ_USN_JOURNAL_DATA ReadData = {0, 0xFFFFFFFF, FALSE, 0, 0};
PUSN_RECORD UsnRecord;
DWORD dwBytes;
DWORD dwRetBytes;
int I;
hVol = CreateFile( TEXT("\\\\.\\c:"),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if( hVol == INVALID_HANDLE_VALUE )
{
printf("CreateFile failed (%d)\n", GetLastError());
return;
}
if( !DeviceIoControl( hVol,
FSCTL_QUERY_USN_JOURNAL,
NULL,
0,
&JournalData,
sizeof(JournalData),
&dwBytes,
NULL) )
{
printf( "Query journal failed (%d)\n", GetLastError());
return;
}
ReadData.UsnJournalID = JournalData.UsnJournalID;
printf( "Journal ID: %I64x\n", JournalData.UsnJournalID );
printf( "FirstUsn: %I64x\n\n", JournalData.FirstUsn );
for(I=0; I<=10; I++)
{
memset( Buffer, 0, BUF_LEN );
if( !DeviceIoControl( hVol,
FSCTL_READ_USN_JOURNAL,
&ReadData,
sizeof(ReadData),
&Buffer,
BUF_LEN,
&dwBytes,
NULL) )
{
printf( "Read journal failed (%d)\n", GetLastError());
return;
}
dwRetBytes = dwBytes - sizeof(USN);
// Find the first record
UsnRecord = (PUSN_RECORD)(((PUCHAR)Buffer) + sizeof(USN));
printf( "****************************************\n");
// This loop could go on for a long time, given the current buffer size.
while( dwRetBytes > 0 )
{
printf( "USN: %I64x\n", UsnRecord->Usn );
printf("File name: %.*S\n",
UsnRecord->FileNameLength/2,
UsnRecord->FileName );
printf( "Reason: %x\n", UsnRecord->Reason );
printf( "\n" );
dwRetBytes -= UsnRecord->RecordLength;
// Find the next record
UsnRecord = (PUSN_RECORD)(((PCHAR)UsnRecord) +
UsnRecord->RecordLength);
}
// Update starting USN for next call
ReadData.StartUsn = *(USN *)&Buffer;
}
CloseHandle(hVol);
}
USN_RECORD_V2或USN_RECORD_V3结构指定的任何记录的大小(((MaxComponentLength - 1) * Width) + Size
以字节为单位),其中 MaxComponentLength 是记录文件名的最大长度(以字符为单位)。 宽度是宽字符的大小, 大小 是结构的大小。
若要获取最大长度,请调用 GetVolumeInformation 函数并检查 lpMaximumComponentLength 参数指向的值。 从 MaxComponentLength 中减去一个值,以说明 USN_RECORD 和 USN_RECORD_V3 的定义包含文件名的一个字符。
在 C 编程语言中,最大可能的记录大小如下:
(MaxComponentLength - 1) * sizeof(WCHAR) + sizeof(USN_RECORD)
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈