Временные метки появляются 0, потому что FSCTL_QUERY_USN_JOURNAL
не заполняет эту информацию.Это явно не указано в документации контрольного кода , и я не могу найти никакой официальной документации, где она находится.Но есть места, где упоминается, что USN_RECORD
заселён лишь частично.Как и в этой ссылке , которая дана из USN_RECORD_V2
документации , хотя я даже не уверен, о чем FSCTL говорит прежняя ссылка.
В любом случаеэто соответствует всем примерам, которые я могу найти, включая Microsoft own .Ниже приведен перевод этого кода на Delphi.Информация USN, полученная с использованием контрольного кода FSCTL_QUERY_USN_JOURNAL
, используется в вызове DeviceIoControl
с использованием FSCTL_READ_USN_JOURNAL
для получения подробной информации.
Есть несколько исключений из прямого перевода, одно из них - получение имени файла, чего я не понял, как работает код C ++.Другой - печать временных отметок, поскольку это ваше требование.Кроме того, вам необходимо добавить блоки проверки ошибок и защиты для таких ресурсов, как дескриптор тома или память и т. Д.
В коде используются объявления вспомогательного модуля, который вы включили в вопрос.Я проверил отметки времени в бесплатной утилите третьей стороны, которую нашел здесь , и они соответствуют.
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
windows,
uMFT;
type
USN = LONGLONG;
const
BUF_LEN = 4096;
var
hVol: THandle;
JournalData: TUSNJournalData;
dwBytes: DWORD;
dwRetBytes: DWORD;
ReadData: TReadUSNJournalData;
i: Integer;
Buffer: array [0..BUF_LEN - 1] of Byte;
UsnRecord: PUSNRecord;
FileName: PWideChar;
SysTime: TSystemTime;
begin
hVol := CreateFile( '\\.\c:', GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if hVol = INVALID_HANDLE_VALUE then begin
Writeln(Format('CreateFile failed (%d)', [GetLastError]));
Exit;
end;
if not DeviceIoControl(hVol, FSCTL_QUERY_USN_JOURNAL, nil, 0, @JournalData,
SizeOf(JournalData), dwBytes, nil) then begin
Writeln(Format('Query journal failed (%d)', [GetLastError]));
Exit;
end;
ZeroMemory(@ReadData, SizeOf(ReadData));
ReadData.ReasonMask := $FFFFFFFF;
ReadData.UsnJournalID := JournalData.UsnJournalID;
Writeln(Format('Journal ID: %x', [JournalData.UsnJournalID]));
Writeln(Format('FirstUsn: %x' + sLineBreak, [JournalData.FirstUsn]));
for i := 0 to 10 do begin
FillChar(Buffer, BUF_LEN, 0);
if not DeviceIoControl(hVol, FSCTL_READ_USN_JOURNAL, @ReadData,
SizeOf(ReadData), @Buffer, BUF_LEN, dwBytes, nil) then begin
Writeln(Format('Read journal failed (%d)', [GetLastError]));
Exit;
end;
dwRetBytes := dwBytes - SizeOf(USN);
// Find the first record
UsnRecord := PUsnRecord(NativeInt(@Buffer) + SizeOf(USN));
Writeln('****************************************');
while dwRetBytes > 0 do begin
Writeln(Format('USN: %x', [UsnRecord.Usn]));
GetMem(FileName, UsnRecord.FileNameLength + SizeOf(Char));
Move(Pointer(NativeInt(UsnRecord) + UsnRecord.FileNameOffset)^, FileName^,
UsnRecord.FileNameLength);
FileName[UsnRecord.FileNameLength div 2] := #0;
Writeln(Format('File name: %s', [FileName]));
FreeMem(FileName);
FileTimeToSystemTime(@UsnRecord.TimeStamp, SysTime);
Writeln(Format('Time stamp: %s', [DateTimeToStr(SystemTimeToDateTime(SysTime))]));
Writeln(Format('Reason: %x', [UsnRecord.Reason]));
Writeln;
dwRetBytes := dwRetBytes - UsnRecord.RecordLength;
// Find the next record
UsnRecord := PUsnRecord(NativeInt(UsnRecord) + UsnRecord.RecordLength);
end;
end;
CloseHandle(hVol);
Writeln;
Writeln('End of sample');
Readln;
end.