Partager via


Parcourir une mémoire tampon d’enregistrements de journal des modifications

Les codes de contrôle qui retournent le numéro séquentiel de mise à jour (USN) modifient les enregistrements du journal, FSCTL_READ_USN_JOURNAL et FSCTL_ENUM_USN_DATA, retournent des données similaires dans la mémoire tampon de sortie. Les deux renvoient un USN suivi de zéro ou plusieurs enregistrements de journal des modifications, chacun dans une structure USN_RECORD_V2 ou USN_RECORD_V3 .

Le volume cible pour les opérations USN doit être ReFS ou NTFS 3.0 ou version ultérieure. Pour obtenir la version NTFS d’un volume, ouvrez une invite de commandes avec des droits d’accès administrateur et exécutez la commande suivante :

FSUtil.exe FSInfo NTFSInfoX**:**

X est la lettre de lecteur du volume.

La liste suivante identifie les façons d’obtenir les enregistrements du journal des modifications :

  • Utilisez FSCTL_ENUM_USN_DATA pour obtenir une liste (énumération) de tous les enregistrements de journal des modifications entre deux NOMS DE SERVICE.
  • Utilisez FSCTL_READ_USN_JOURNAL pour être plus sélectif, par exemple en sélectionnant des raisons spécifiques des modifications ou en retournant lorsqu’un fichier est fermé.

Notes

Ces deux opérations retournent uniquement le sous-ensemble d’enregistrements du journal des modifications qui répondent aux critères spécifiés.

 

L’USN retourné en tant que premier élément de la mémoire tampon de sortie est l’USN du numéro d’enregistrement suivant à récupérer. Utilisez cette valeur pour continuer à lire les enregistrements à partir de la limite de fin vers l’avant.

Le membre FileName de USN_RECORD_V2 ou USN_RECORD_V3 contient le nom du fichier auquel s’applique l’enregistrement en question. Le nom de fichier varie en longueur, de sorte que USN_RECORD_V2 et USN_RECORD_V3 sont des structures de longueur variable. Leur premier membre, RecordLength, est la longueur de la structure (y compris le nom de fichier), en octets.

Lorsque vous travaillez avec le membre FileName des structures USN_RECORD_V2 et USN_RECORD_V3 , ne supposez pas que le nom de fichier contient un délimiteur « \0 » de fin. Pour déterminer la longueur du nom de fichier, utilisez le membre FileNameLength .

L’exemple suivant appelle FSCTL_READ_USN_JOURNAL et guide la mémoire tampon des enregistrements de journal des modifications que l’opération retourne.

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

}

La taille en octets d’un enregistrement spécifié par une structure USN_RECORD_V2 ou USN_RECORD_V3 est au maximum ((MaxComponentLength - 1) * Width) + SizeMaxComponentLength est la longueur maximale en caractères du nom du fichier d’enregistrement. La largeur est la taille d’un caractère large, et la taille est la taille de la structure.

Pour obtenir la longueur maximale, appelez la fonction GetVolumeInformation et examinez la valeur pointée par le paramètre lpMaximumComponentLength . Soustrayez un de MaxComponentLength pour tenir compte du fait que la définition de USN_RECORD et USN_RECORD_V3 inclut un caractère du nom de fichier.

Dans le langage de programmation C, la taille d’enregistrement la plus élevée possible est la suivante :

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