Обход буфера записей журнала изменений
Коды элементов управления, возвращающие записи журнала изменений с порядком обновления (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 следующего номера записи, который требуется извлечь. Используйте это значение, чтобы продолжить чтение записей с конечной границы вперед.
Элемент FileNameUSN_RECORD_V2 или USN_RECORD_V3 содержит имя файла, к которому применяется соответствующая запись. Имя файла зависит от длины, поэтому USN_RECORD_V2 и USN_RECORD_V3 являются структурами переменной длины. Их первый член, RecordLength, представляет собой длину структуры (включая имя файла) в байтах.
При работе с элементом FileNameUSN_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)
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по