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


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

Коды управления, которые возвращают записи журнала изменений (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 NTFSInfoX**:**

где 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)