Continuing my previous question, I was able to use this delphi unit to implement crazy FAST drive scan using this EnumMFTEntries() function, but I have trouble doing the following tasks:
change journal
to get the newly modified files (changed, renamed, deleted, etc...)I adapted this broken routine after reading both the EnumMFTEntries()
function as well as StCroixSkipper's USN Journal Explorer (in C#).
For some reason reported file names are always #0
function EnumUsnEntries(ARootHandle : Cardinal; AMFTEnumBuff : Pointer; EnumCallBack : TMFTEnumCallback) : Boolean;
var
P : Pointer;
UsnEnum : Pointer;
BytesRet : Cardinal;
PUSN : PUSNRecord;
ReadUSN : TReadUSNJournalData;
PReadUSN : PReadUSNJournalData;
UsnJournalData : TUSNJournalData;
BUF_SIZE : Integer;
begin
Result := False;
if (ARootHandle = INVALID_HANDLE_VALUE) OR (AMFTEnumBuff = nil) then
Exit;
QueryUSNJournal(ARootHandle, UsnJournalData);
with ReadUSN do
begin
StartUsn := UsnJournalData.NextUsn;
ReasonMask := USN_REASON_DATA_OVERWRITE OR USN_REASON_DATA_EXTEND OR USN_REASON_NAMED_DATA_OVERWRITE OR USN_REASON_NAMED_DATA_TRUNCATION OR
USN_REASON_FILE_CREATE OR USN_REASON_FILE_DELETE OR USN_REASON_EA_CHANGE OR USN_REASON_SECURITY_CHANGE OR
USN_REASON_RENAME_OLD_NAME OR USN_REASON_RENAME_NEW_NAME OR USN_REASON_INDEXABLE_CHANGE OR USN_REASON_BASIC_INFO_CHANGE OR
USN_REASON_HARD_LINK_CHANGE OR USN_REASON_COMPRESSION_CHANGE OR USN_REASON_ENCRYPTION_CHANGE OR
USN_REASON_OBJECT_ID_CHANGE OR USN_REASON_REPARSE_POINT_CHANGE OR USN_REASON_STREAM_CHANGE OR USN_REASON_CLOSE;
ReturnOnlyOnClose := 0;
Timeout := 0;
BytesToWaitFor := 0;
UsnJournalID := UsnJournalData.UsnJournalID;
end; // with
BUF_SIZE := SizeOf(ReadUSN);
GetMem(P, BUF_SIZE);
try
ZeroMemory(P, BUF_SIZE);
while DeviceIoControl(ARootHandle, FSCTL_READ_USN_JOURNAL, Addr(ReadUSN){UsnEnum}, SizeOf(ReadUSN{TReadUSNJournalData}), P, BUF_SIZE, BytesRet, nil) do
begin
PUSN := PUSNRecord{PReadUSNJournalData}(Integer(P) + SizeOf(Int64));
while (BytesRet > 0{60}) do
begin
if Not EnumCallBack(PUSN, nil{Extra}) then
Exit;
if PUSN.RecordLength > 0 then
Dec(BytesRet, PUSN.RecordLength)
else
Break;
PUSN := PUSNRecord(Cardinal(PUSN) + PUSN.RecordLength);
end; // while
CopyMemory(UsnEnum{MFTEnum}, P, SizeOf(Int64));
end; // while
Result := True;
finally
FreeMem(P);
end; // try/finally
end;
If I'm not mistaken, it seems to be possible to partially do so by defining the StartUsn
in the EnumMFTEntries() function, but it's not clear how to do that.
For example, the EnumMFTEntries()
always return the name only, along with its parent folder reference number, it's not clear what's the fastest way to get the full path.
I hope I'm not asking too much, these tasks are really closely related, I really hope the community will help here to make easy for Delphi developers achieve crazy fast folder scan. Despite its usefulness, change journal / MFT is one of the most interesting-yet-forgotten technologies. This has to change!
On task #2: you can restrict usn data search to a particular file/dir by first emitting FSCTL_READ_FILE_USN_DATA to obtain usn number of last change and then FSTCL_READ_USN_JOURNAL with StartUsn member assigned to that usn number to get valid info on the change (timrstamp, reason). However, only the last change can be obtained this way. To get all changes, I think it is only possible to filter read usn journal data by a particular file reference number. More info in MSDN Library.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With