我一直在尝试避免递归父目录搜索以获得完整路径,因为我的初始测试增加了解析路径所需的总时间。
在使用了几个小时的 windbg 和一些 OSR Onlinefourm 的帮助之后,我终于明白了。
发布答案以帮助遇到同样问题的其他人。
我目前的解决方案如下。
USN_RECORD-> FileReferenceNumber 完全依赖于 USN_RECORD 的版本,一旦从 FileReferenceNumber 中提取 FILE_ID_DESCRIPTOR,就可以调用 OpenFileById() 并传递 FILE_ID_DESCRIPTOR 来获取父文件夹的句柄。
然后可以调用 GetFinalPathNameByHandle() 来获取 ParentDirectory 路径。
下面是我提取 FILE_ID_DESCRIPTOR 的代码
如果是 USN_RECORD_V2 中的 FileId,则 FileReferenceNu DWORDLONG。
FILE_ID_DESCRIPTOR getFileIdDescriptor(const DWORDLONG fileId)
{
FILE_ID_DESCRIPTOR fileDescriptor;
fileDescriptor.Type = FileIdType;
fileDescriptor.FileId.QuadPart = fileId;
fileDescriptor.dwSize = sizeof(fileDescriptor);
return fileDescriptor;
}
如果您最终得到 UNS_RECORD_V3,则 fileId 的类型为 FILE_ID_128,这里是提取 FileId 的代码。
FILE_ID_DESCRIPTOR getFileIdDescriptor(const FILE_ID_128& fileId)
{
FILE_ID_DESCRIPTOR fileDescriptor;
fileDescriptor.Type = ExtendedFileIdType;
fileDescriptor.ExtendedFileId = fileId;
fileDescriptor.dwSize = sizeof(fileDescriptor);
return fileDescriptor;
}
提取 FileId 后,您可以通过以下方式获取父路径。
TCHAR filePath[MAX_PATH];
HANDLE hh= OpenFileById(volume_, &(getFileIdDescriptor(UsnRecord->FileReferenceNumber)), 0, 0, 0, 0);
GetFinalPathNameByHandle(hh,filePath, MAX_PATH, 0);
可以找到参考实现@https://github.com/kirankumarcelestial/NTFSChangeJournalUserMode
但是我发现GetFilePathNameByHandle()其实很慢,这个API最终会调用GetFileInformationByHandleEx(),而GetFileInformationByHandleEx()是对KernelMode的一次调用,这将是获取Parent Information的有效方法。