Freigeben über


Durchlaufen eines Puffers von Änderungsjournaldatensätzen

Die Steuercodes, die USN -Änderungsdatensätze (Update Sequence Number) zurückgeben, FSCTL_READ_USN_JOURNAL und FSCTL_ENUM_USN_DATA, geben ähnliche Daten im Ausgabepuffer zurück. Beide geben einen USN gefolgt von null oder mehr Änderungsjournaleinträgen zurück, die jeweils in einer USN_RECORD_V2 - oder USN_RECORD_V3-Struktur enthalten sind.

Das Zielvolume für USN-Vorgänge muss ReFS oder NTFS 3.0 oder höher sein. Um die NTFS-Version eines Volumes abzurufen, öffnen Sie eine Eingabeaufforderung mit Administratorzugriffsrechten, und führen Sie den folgenden Befehl aus:

FSUtil.exe FSInfo NTFSInfoX**:**

wobei X der Laufwerkbuchstabe des Volumes ist.

In der folgenden Liste werden Möglichkeiten zum Abrufen von Änderungsjournaleinträgen beschrieben:

  • Verwenden Sie FSCTL_ENUM_USN_DATA , um eine Auflistung (Enumeration) aller Änderungsjournaleinträge zwischen zwei USNs abzurufen.
  • Verwenden Sie FSCTL_READ_USN_JOURNAL , um selektiver zu sein, z. B. die Auswahl bestimmter Gründe für Änderungen oder das Zurückgeben beim Schließen einer Datei.

Hinweis

Beide Vorgänge geben nur die Teilmenge der Änderungsjournaleinträge zurück, die die angegebenen Kriterien erfüllen.

 

Der als erstes Element im Ausgabepuffer zurückgegebene USN ist der USN des nächsten abzurufenden Datensatzes. Verwenden Sie diesen Wert, um Datensätze von der Endgrenze nach vorne zu lesen.

Das FileName-Elementvon USN_RECORD_V2 oder USN_RECORD_V3 enthält den Namen der Datei, für die der betreffende Datensatz gilt. Der Dateiname variiert in der Länge, sodass USN_RECORD_V2 und USN_RECORD_V3 Strukturen mit variabler Länge sind. Ihr erstes Element, RecordLength, ist die Länge der Struktur (einschließlich des Dateinamens) in Bytes.

Wenn Sie mit dem FileName-Member von USN_RECORD_V2 - und USN_RECORD_V3-Strukturen arbeiten, gehen Sie nicht davon aus, dass der Dateiname ein nachfolgendes Trennzeichen "\0" enthält. Um die Länge des Dateinamens zu bestimmen, verwenden Sie das FileNameLength-Element .

Im folgenden Beispiel wird FSCTL_READ_USN_JOURNAL aufgerufen und der Puffer von Änderungsjournaldatensätzen, die der Vorgang zurückgibt, durchlaufen.

#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);

}

Die Größe in Bytes eines datensatzes, der von einer USN_RECORD_V2 - oder USN_RECORD_V3-Struktur angegeben wird, ist höchstens ((MaxComponentLength - 1) * Width) + Size , wobei MaxComponentLength die maximale Länge in Zeichen des Datensatzdateinamens darstellt. Die Breite ist die Größe eines breiten Zeichens, und die Größe ist die Größe der Struktur.

Um die maximale Länge zu erhalten, rufen Sie die GetVolumeInformation-Funktion auf, und untersuchen Sie den Wert, auf den der parameter lpMaximumComponentLength verweist. Subtrahieren Sie einen von MaxComponentLength , um die Tatsache zu berücksichtigen, dass die Definition von USN_RECORD und USN_RECORD_V3 ein Zeichen des Dateinamens enthält.

In der Programmiersprache C ist die größtmögliche Datensatzgröße wie folgt:

(MaxComponentLength - 1) * sizeof(WCHAR) + sizeof(USN_RECORD)