首页 >后端开发 >C++ >如何使用 FSCTL_ENUM_USN_DATA 有效检测 NTFS 卷上的文件更改?

如何使用 FSCTL_ENUM_USN_DATA 有效检测 NTFS 卷上的文件更改?

Patricia Arquette
Patricia Arquette原创
2024-10-30 13:03:26898浏览

 How Can You Efficiently Detect File Changes on an NTFS Volume Using FSCTL_ENUM_USN_DATA?

使用 FSCTL_ENUM_USN_DATA 高效检测 NTFS 卷上的文件更改

背景

检查每个文件的存档位的现有备份方法可能会变得缓慢且缓慢对于大型文件系统效率低下。此方法需要扫描所有文件,包括临时文件,并可能导致冗长的备份过程。

使用文件系统 USN 的替代方法

更有效的方法涉及使用文件系统 USN(更新序列)号)更改日志。文件系统 USN 提供对文件系统所做的每个更改的记录,包括文件创建、删除和修改。

FSCTL_ENUM_USN_DATA 的工作原理

要检测 NTFS 卷上的更改,我们可以利用FSCTL_ENUM_USN_DATA 控制代码。此控制代码:

  • 枚举卷上的所有文件,仅包括当前存在的文件。
  • 检索每个文件的关键数据,包括:

    • 文件标志
    • USN
    • 文件名
    • 父文件参考号

实施更改检测

检测更改:

  1. 获取文件系统 USN 数据:使用 FSCTL_QUERY_USN_JOURNAL 获取系统的最大 USN (maxusn)。
  2. 枚举 USN 记录: 使用 FSCTL_ENUM_USN_DATA 循环遍历 USN 记录。
  3. 识别相关记录: 检查标志并比较 USN 以检测创建、删除或修改的文件。
  4. 解析父路径:将父文件参考号与目录的文件参考号匹配,以获得完整的文件路径。

C 代码示例

这是演示该方法的代码片段:

<code class="c++">DWORDLONG nextid;
DWORDLONG filecount = 0;
DWORD starttick, endtick;

// Allocate memory for USN records
void * buffer = VirtualAlloc(NULL, BUFFER_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

// Open volume handle
HANDLE drive = CreateFile(L"\\?\c:", GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_FLAG_NO_BUFFERING, NULL);

// Get volume USN journal data
USN_JOURNAL_DATA * journal = (USN_JOURNAL_DATA *)buffer;
if (!DeviceIoControl(drive, FSCTL_QUERY_USN_JOURNAL, NULL, 0, buffer, BUFFER_SIZE, &bytecount, NULL)) {
  (...)
}
maxusn = journal->MaxUsn;

MFT_ENUM_DATA mft_enum_data;
mft_enum_data.StartFileReferenceNumber = 0;
mft_enum_data.LowUsn = 0;
mft_enum_data.HighUsn = maxusn;

while (...) {
  if (!DeviceIoControl(drive, FSCTL_ENUM_USN_DATA, &mft_enum_data, sizeof(mft_enum_data), buffer, BUFFER_SIZE, &bytecount, NULL)) {
    (...)
  }

  nextid = *((DWORDLONG *)buffer);
  USN_RECORD * record = (USN_RECORD *)((USN *)buffer + 1);
  USN_RECORD * recordend = (USN_RECORD *)(((BYTE *)buffer) + bytecount);

  while (record < recordend) {
    filecount++;
    // Check flags and USNs to identify changes
    (...)
    record = (USN_RECORD *)(((BYTE *)record) + record->RecordLength);
  }
  mft_enum_data.StartFileReferenceNumber = nextid;
}</code>

性能注意事项

使用 FSCTL_ENUM_USN_DATA 的方法提供:

  • 快速枚举过程: 每秒能够处理超过 6000 条记录。
  • 高效过滤: 仅分析相关的文件更改记录,消除临时文件的开销。
  • 潜力限制: 在非常大的卷上性能可能会有所不同,但它通常比检查存档位更有效。

附加说明

  • 在 Windows 上将 MFT_ENUM_DATA 替换为 MFT_ENUM_DATA_V0 Windows 7 之后的版本。
  • 文件参考号打印为 32 位,这是一个错误。在生产代码中,建议使用 64 位值。

以上是如何使用 FSCTL_ENUM_USN_DATA 有效检测 NTFS 卷上的文件更改?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn