7

继续我之前的问题,我可以使用这个delphi 单元来使用这个EnumMFTEntries() 函数实现疯狂的 FAST 驱动器扫描,但是我在执行以下任务时遇到了麻烦:

任务#1:查询change journal以获取新修改的文​​件(更改、重命名、删除等...)

在阅读了该函数以及 StCroixSkipper 的 USN Journal Explorer(在 C# 中)之后,我调整了这个损坏的例程。EnumMFTEntries()

由于某种原因,报告的文件名总是#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:限制扫描到某个文件夹?

如果我没记错的话,似乎可以通过在EnumMFTEntries()函数中定义来部分地做到这一点,但目前尚不清楚如何做到这一点。StartUsn

任务#3:获取文件名的完整路径?

例如,EnumMFTEntries()总是只返回名称及其父文件夹参考号,不清楚获取完整路径的最快方法是什么。


我希望我没有问太多,这些任务真的是息息相关的,我真的希望社区在这里帮助Delphi开发人员轻松实现疯狂的快速文件夹扫描。尽管它很有用,但变更日志/MFT 是最有趣但被遗忘的技术之一。这必须改变!

4

1 回答 1

2

在任务 #2 上:您可以通过首先发出 FSCTL_READ_FILE_USN_DATA 来将 usn 数据搜索限制到特定文件/目录以获取最后更改的 usn 编号,然后 FSTCL_READ_USN_JOURNAL 将 StartUsn 成员分配给该 usn 编号以获取有关更改的有效信息(timrstamp,原因)。但是,这种方式只能获得最后的变化。要获得所有更改,我认为只能通过特定文件参考号过滤读取的 usn 日志数据。MSDN 库中的更多信息。

于 2013-01-30T06:00:19.730 回答