Поделиться через


Переход к буферу записей журнала изменений

Коды элементов управления, возвращающие записи журнала обновления (USN), изменяют записи журнала, FSCTL_READ_USN_JOURNAL и FSCTL_ENUM_USN_DATA, возвращают аналогичные данные в выходном буфере. Оба возвращают USN, за которым следует нулевая или более записей журнала изменений, каждая из которых содержит USN_RECORD_V2 или USN_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 следующего номера записи, который требуется получить. Используйте это значение для продолжения чтения записей из конечной границы вперед.

Элемент FileName USN_RECORD_V2 или USN_RECORD_V3 содержит имя файла, к которому применяется запись. Имя файла зависит от длины, поэтому USN_RECORD_V2 и USN_RECORD_V3 являются структурами переменной длины. Их первый член RecordLength — это длина структуры (включая имя файла) в байтах.

При работе с элементом FileName USN_RECORD_V2 и структурами USN_RECORD_V3 не предполагается, что имя файла содержит разделитель "\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 является максимальной длиной в символах имени файла записи. Ширина — это размер широкого символа, а размер — это размер структуры.

Чтобы получить максимальную длину, вызовите функцию GetVolumeInformation и проверьте значение, указанное параметром lpMaximumComponentLength . Вычитает один из MaxComponentLength, чтобы учитывать тот факт, что определение USN_RECORD и USN_RECORD_V3 включает один символ имени файла.

На языке программирования C максимальный размер записи имеет следующий размер:

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