Heim >Backend-Entwicklung >C++ >Wie kann ich Dateiänderungen auf einem NTFS-Volume mithilfe der Funktion FSCTL_ENUM_USN_DATA effizient erkennen?

Wie kann ich Dateiänderungen auf einem NTFS-Volume mithilfe der Funktion FSCTL_ENUM_USN_DATA effizient erkennen?

DDD
DDDOriginal
2024-10-29 08:14:30612Durchsuche

How can I efficiently detect file changes on an NTFS volume using the FSCTL_ENUM_USN_DATA function?

Änderungen auf einem Volume erkennen: Eine detaillierte Lösung

Um Dateilöschungen, -änderungen und -erstellungen auf einem NTFS-Volume effektiv zu erkennen, können Sie Folgendes tun Verwenden Sie die Funktion FSCTL_ENUM_USN_DATA. Dieser Ansatz bietet mehrere Vorteile:

  • Schnelle Aufzählung: Das Volume wird effizient gescannt, wobei nur vorhandene Dateien mit einer Leistung von über 6000 Datensätzen pro Sekunde abgerufen werden.
  • Detaillierte Informationen: Es liefert umfassende Daten, einschließlich Dateikennzeichen und USNs, und ermöglicht so präzise Methoden zur Änderungserkennung.
  • Hierarchische Dateidaten: Durch den Abgleich von übergeordneten IDs mit Datei-IDs Sie können den vollständigen Dateipfad für jede erkannte Datei rekonstruieren.

Implementierungsschritte:

  1. Dateien auflisten: Verwenden Sie FSCTL_ENUM_USN_DATA um Datensätze für alle vorhandenen Dateien abzurufen.
  2. Änderungen identifizieren: Analysieren Sie die Dateiflags und USNs, um festzustellen, welche Dateien geändert, erstellt oder gelöscht wurden.
  3. Dateipfade rekonstruieren: Ordnen Sie übergeordnete IDs den Datei-IDs zu, um die vollständigen Pfade der betroffenen Dateien zu erhalten.

Ein Beispiel-C-Programm, das diesen Ansatz demonstriert, wird unten bereitgestellt und sucht nach Dateien mit dem Namen „test .txt“ und zeigt Informationen zu ihren Änderungen und übergeordneten Verzeichnissen an:

<code class="c++">#include <Windows.h>
#include <stdio.h>

#define BUFFER_SIZE (1024 * 1024)

int main() {
  HANDLE drive = CreateFileW(L"\\?\c:", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_FLAG_NO_BUFFERING, NULL);

  MFT_ENUM_DATA mft_enum_data;
  USN maxusn;
  USN_RECORD *record;

  // Query USN journal for information
  if (DeviceIoControl(drive, FSCTL_QUERY_USN_JOURNAL, NULL, 0, &maxusn, sizeof(USN), NULL, NULL)) {
    mft_enum_data.StartFileReferenceNumber = 0;
    mft_enum_data.LowUsn = 0;
    mft_enum_data.HighUsn = maxusn;
    
    DWORDLONG nextid, filecount = 0;

    for (;;) {
      void *buffer = VirtualAlloc(NULL, BUFFER_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

      if (DeviceIoControl(drive, FSCTL_ENUM_USN_DATA, &mft_enum_data, sizeof(mft_enum_data), buffer, BUFFER_SIZE, NULL, NULL)) {
        nextid = *((DWORDLONG *)buffer);

        record = (USN_RECORD *)((USN *)buffer + 1);
        while (record < (USN_RECORD *)(((BYTE *)buffer) + BUFFER_SIZE)) {
          filecount++;
          WCHAR *filename = (WCHAR *)(((BYTE *)record) + record->FileNameOffset);
          if (wcsncmp(filename, L"test.txt", 8) == 0) {
            printf("=================================================================\n");
            printf("RecordLength: %u\n", record->RecordLength);
            printf("MajorVersion: %u\n", (DWORD)record->MajorVersion);
            printf("MinorVersion: %u\n", (DWORD)record->MinorVersion);
            printf("FileReferenceNumber: %lu\n", record->FileReferenceNumber);
            printf("ParentFRN: %lu\n", record->ParentFileReferenceNumber);
            printf("USN: %lu\n", record->Usn);
            printf("Timestamp: %lu\n", record->TimeStamp);
            printf("Reason: %u\n", record->Reason);
            printf("SourceInfo: %u\n", record->SourceInfo);
            printf("SecurityId: %u\n", record->SecurityId);
            printf("FileAttributes: %x\n", record->FileAttributes);
            printf("FileNameLength: %u\n", (DWORD)record->FileNameLength);
            printf("FileName: %.*ls\n", record->FileNameLength, filename);
            
            // Reconstruct file path by matching parent file reference numbers
            DWORD bytecount;
            if (DeviceIoControl(drive, FSCTL_ENUM_USN_DATA, &mft_enum_data, sizeof(mft_enum_data), buffer, BUFFER_SIZE, &bytecount, NULL)) {
              USN_RECORD *parent_record = (USN_RECORD *)((USN *)buffer + 1);
              if (parent_record->FileReferenceNumber == record->ParentFileReferenceNumber) {
                printf("Parent File:\n");
                printf("=================================================================\n");
                printf("FileName: %.*ls\n", parent_record->FileNameLength, (WCHAR *)(((BYTE *)parent_record) + parent_record->FileNameOffset));
              }
            }
          }
          record = (USN_RECORD *)(((BYTE *)record) + record->RecordLength);
        }
        mft_enum_data.StartFileReferenceNumber = nextid;
      } else {
        printf("FSCTL_ENUM_USN_DATA failed\n");
        break;
      }
      if (nextid == 0) break;
    }
    printf("Total Files: %lu\n", filecount);
  } else {
    printf("FSCTL_QUERY_USN_JOURNAL failed\n");
  }

  if (drive != INVALID_HANDLE_VALUE)
    CloseHandle(drive);

  return 0;
}</code>

Das obige ist der detaillierte Inhalt vonWie kann ich Dateiänderungen auf einem NTFS-Volume mithilfe der Funktion FSCTL_ENUM_USN_DATA effizient erkennen?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn