走動變更日誌記錄的緩衝區

傳回更新序號 (USN) 變更記錄的控制程式碼,FSCTL_READ_USN_JOURNALFSCTL_ENUM_USN_DATA,會在輸出緩衝區中傳回類似的數據。 兩者都會傳回 USN,後面接著零筆或多個變更日誌記錄,每個記錄都位於 USN_RECORD_V2USN_RECORD_V3 結構中。

USN 作業的目標磁碟區必須是 ReFS 或 NTFS 3.0 或更新版本。 若要取得磁碟區的NTFS版本,請使用系統管理員訪問許可權開啟命令提示字元,然後執行下列命令:

FSUtil.exe FSInfo NTFSInfo X**:**

其中 X 是磁碟區的驅動器號。

下列清單會識別取得變更紀錄記錄的方式:

  • 使用 FSCTL_ENUM_USN_DATA 取得兩個USN之間所有變更日誌記錄的清單(列舉)。
  • 使用 FSCTL_READ_USN_JOURNAL 更具選擇性,例如選取檔案關閉時變更或傳回的特定原因。

注意

這兩項作業只會傳回符合指定準則的變更日誌記錄子集。

 

作為輸出緩衝區中第一個項目傳回的 USN 是要擷取之下一個記錄編號的 USN。 使用此值繼續從結束界限向前讀取記錄。

USN_RECORD_V2或USN_RECORD_V3 FileName 成員包含所要套用記錄的檔名。 檔名會隨著長度而有所不同,因此 USN_RECORD_V2USN_RECORD_V3 都是可變長度結構。 其第一個成員 RecordLength 是以位元組為單位的結構長度(包括檔名)。

當您使用 USN_RECORD_V2 和 USN_RECORD_V3 結構的 FileName 成員時,請勿假設檔名包含尾端 '\0' 分隔符。 若要判斷檔名的長度,請使用 FileNameLength 成員。

下列範例會呼叫 FSCTL_READ_USN_JOURNAL ,並逐步解說作業傳回的變更日誌記錄緩衝區。

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

}

USN_RECORD_V2或USN_RECORD_V3結構所指定之任何記錄的大小,最多((MaxComponentLength - 1) * Width) + Size是 MaxComponentLength 是記錄檔名稱字元的最大長度。 寬度是寬字元的大小, 而 Size 是結構的大小。

若要取得最大長度,請呼叫 GetVolumeInformation 函式,並檢查 lpMaximumComponentLength 參數所指向的值。 從 MaxComponentLength 減去其中一個,以說明USN_RECORD的定義和USN_RECORD_V3包含檔名的一個字元。

在 C 程式設計語言中,最大的可能記錄大小如下:

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