我一直在尝试避免递归父目录搜索以获取完整路径,因为我的初始测试增加了解析路径所需的总时间。
在使用了几个小时的 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的一次调用,这将是获取父信息的有效方法。