ホームページ >バックエンド開発 >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 を使用するアプローチは次のことを実現します:

  • 高速列挙プロセス: 1 秒あたり 6000 レコードを超える処理が可能。
  • 効率的なフィルタリング: 関連するファイル変更レコードのみが分析され、一時ファイルからのオーバーヘッドが排除されます。
  • 潜在的制限事項: 非常に大規模なボリュームではパフォーマンスが異なる場合がありますが、通常はアーカイブ ビットをチェックするより効率的です。

追加メモ

  • Windows では MFT_ENUM_DATA を MFT_ENUM_DATA_V0 に置き換えてください。 Windows 7 より後のバージョン。
  • ファイル参照番号は 32 ビットとして出力されますが、これは間違いです。製品コードでは、64 ビット値を使用することをお勧めします。

以上がFSCTL_ENUM_USN_DATA を使用して NTFS ボリューム上のファイル変更を効率的に検出するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。