Menjalankan Buffer Change Journal Records

Kode kontrol yang mengembalikan nomor urutan pembaruan (USN) mengubah rekaman jurnal, FSCTL_READ_USN_JOURNAL dan FSCTL_ENUM_USN_DATA, mengembalikan data serupa di buffer output. Keduanya mengembalikan USN diikuti dengan nol atau lebih rekaman jurnal perubahan, masing-masing dalam struktur USN_RECORD_V2 atau USN_RECORD_V3 .

Volume target untuk operasi USN harus ReFS atau NTFS 3.0 atau yang lebih baru. Untuk mendapatkan versi volume NTFS, buka prompt perintah dengan hak akses Administrator dan jalankan perintah berikut:

FSUtil.exe FSInfo NTFSInfoX**:**

di mana X adalah huruf kandar volume.

Daftar berikut mengidentifikasi cara untuk mendapatkan catatan jurnal perubahan:

  • Gunakan FSCTL_ENUM_USN_DATA untuk mendapatkan daftar (enumerasi) dari semua catatan jurnal perubahan antara dua USN.
  • Gunakan FSCTL_READ_USN_JOURNAL agar lebih selektif, seperti memilih alasan tertentu untuk perubahan atau mengembalikan saat file ditutup.

Catatan

Kedua operasi ini hanya mengembalikan subset rekaman jurnal perubahan yang memenuhi kriteria yang ditentukan.

 

USN yang dikembalikan sebagai item pertama dalam buffer output adalah USN dari nomor rekaman berikutnya yang akan diambil. Gunakan nilai ini untuk terus membaca rekaman dari batas akhir ke depan.

Anggota FileNamedari USN_RECORD_V2 atau USN_RECORD_V3 berisi nama file tempat rekaman yang dimaksud diterapkan. Panjang nama file bervariasi, jadi USN_RECORD_V2 dan USN_RECORD_V3 adalah struktur panjang variabel. Anggota pertama mereka, RecordLength, adalah panjang struktur (termasuk nama file), dalam byte.

Saat Anda bekerja dengan anggota FileName dari struktur USN_RECORD_V2 dan USN_RECORD_V3 , jangan berasumsi bahwa nama file berisi pemisah '\0' berikutnya. Untuk menentukan panjang nama file, gunakan anggota FileNameLength .

Contoh berikut memanggil FSCTL_READ_USN_JOURNAL dan memanjakan buffer catatan jurnal perubahan yang dikembalikan operasi.

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

}

Ukuran dalam byte dari rekaman apa pun yang ditentukan oleh struktur USN_RECORD_V2 atau USN_RECORD_V3 paling banyak ((MaxComponentLength - 1) * Width) + Size di mana MaxComponentLength adalah panjang maksimum dalam karakter nama file rekaman. Lebar adalah ukuran karakter lebar, dan Ukuran adalah ukuran struktur.

Untuk mendapatkan panjang maksimum, panggil fungsi GetVolumeInformation dan periksa nilai yang diarahkan oleh parameter lpMaximumComponentLength . Kurangi satu dari MaxComponentLength untuk memperkirakan fakta bahwa definisi USN_RECORD dan USN_RECORD_V3 menyertakan satu karakter nama file.

Dalam bahasa pemrograman C, ukuran rekaman terbesar yang mungkin adalah sebagai berikut:

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