Percorrer um buffer de registros do diário de alterações
Os códigos de controle que retornam o USN (número de sequência de atualização) alteram registros de diário, FSCTL_READ_USN_JOURNAL e FSCTL_ENUM_USN_DATA, retornam dados semelhantes no buffer de saída. Ambos retornam um USN seguido de zero ou mais registros de diário de alterações, cada um em uma estrutura USN_RECORD_V2 ou USN_RECORD_V3.
O volume de destino para operações de USN deve ser ReFS ou NTFS 3.0 ou posterior. Para obter a versão NTFS de um volume, abra um prompt de comando com direitos de acesso de Administrador e execute o seguinte comando:
FSUtil.exe FSInfo NTFSInfo X**:**
em que X é a letra da unidade do volume.
A lista a seguir identifica maneiras de obter registros do diário de alterações:
- Use FSCTL_ENUM_USN_DATA para obter uma listagem (enumeração) de todos os registros do diário de alterações entre dois USNs.
- Use FSCTL_READ_USN_JOURNAL para ser mais seletivo, como a seleção de motivos específicos para alterações ou o retorno quando um arquivo for fechado.
Observação
Ambas as operações só retornam o subconjunto de registros do diário de alterações que atendam aos critérios especificados.
O USN retornado como o primeiro item no buffer de saída é o USN do próximo número de registro a ser recuperado. Use esse valor para continuar lendo registros do limite final em diante.
O membro FileName de USN_RECORD_V2 ou USN_RECORD_V3 contém o nome do arquivo ao qual o registro em questão se aplica. O nome do arquivo varia em termos de comprimento, logo, USN_RECORD_V2 e USN_RECORD_V3 são estruturas de comprimento variável. O primeiro membro, RecordLength, é o comprimento da estrutura (inclusive o nome do arquivo), em bytes.
Ao trabalhar com o FileName membro das estruturas USN_RECORD_V2 e USN_RECORD_V3 não presuma que o nome do arquivo contenha um delimitador '\0' à direita. Para determinar o comprimento do nome do arquivo, use o membro FileNameLength.
O exemplo a seguir chama FSCTL_READ_USN_JOURNAL e percorre o buffer de registros do diário de alterações retornado pela operação.
#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);
}
O tamanho em bytes de qualquer registro especificado por uma estrutura USN_RECORD_V2 ou USN_RECORD_V3 está no máximo ((MaxComponentLength - 1) * Width) + Size
em que MaxComponentLength é o comprimento máximo em caracteres do nome de arquivo do registro. A largura é o tamanho de um caractere largo, e o Size é o tamanho da estrutura.
Para obter o comprimento máximo, chame a função GetVolumeInformation e examine o valor apontado pelo parâmetro lpMaximumComponentLength. Subtraia um de MaxComponentLength para levar em conta o fato de que a definição de USN_RECORD e USN_RECORD_V3 inclui um caracteres do nome de arquivo.
Na linguagem de programação C, o maior tamanho de registro possível é o seguinte:
(MaxComponentLength - 1) * sizeof(WCHAR) + sizeof(USN_RECORD)