Внедрение журнала изменений в Delphi (шаг 2)
Продолжая свой предыдущий вопрос, я смог использовать этот модуль delphi для реализации сумасшедшего сканирования дисков FAST с помощью этой функции EnumMFTEntries(), но у меня возникли проблемы при выполнении следующих задач:
Задача № 1: Запрос change journal
чтобы получить недавно измененные файлы (измененные, переименованные, удаленные и т. д.)
Я адаптировал эту нарушенную рутину после прочтения EnumMFTEntries()
функции, а также в USN Journal Explorer от StCroixSkipper (в C#).
По некоторым причинам сообщаемые имена файлов всегда #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;
Задача № 2: Ограничить сканирование определенной папкой?
Если я не ошибаюсь, представляется возможным частично сделать это, определив StartUsn
в функции EnumMFTEntries(), но не ясно, как это сделать.
Задача № 3: Получить полный путь к имени файла?
Например, EnumMFTEntries()
всегда возвращайте только имя вместе с номером ссылки на родительскую папку, не ясно, какой самый быстрый способ получить полный путь.
Я надеюсь, что я не слишком многого требую, эти задачи действительно тесно связаны, я очень надеюсь, что сообщество поможет здесь облегчить разработчикам на Delphi безумное быстрое сканирование папок. Несмотря на свою полезность, журнал изменений / MFT является одной из самых интересных, но забытых технологий. Это должно измениться!
1 ответ
В задаче № 2: вы можете ограничить поиск данных usn определенным файлом /dir, сначала отправив FSCTL_READ_FILE_USN_DATA, чтобы получить номер последнего изменения usn, а затем FSTCL_READ_USN_JOURNAL с членом StartUsn, назначенным этому номеру usn, чтобы получить действительную информацию об изменении (timrstamp, причина). Однако только последнее изменение может быть получено таким образом. Чтобы получить все изменения, я думаю, что можно фильтровать только прочитанные данные журнала usn по определенному номеру файла. Больше информации в библиотеке MSDN.