C++ 如何获取USN日志查询的完整路径?

C++ 如何获取USN日志查询的完整路径?,c++,visual-studio,winapi,msdn,ntfs-mft,C++,Visual Studio,Winapi,Msdn,Ntfs Mft,我试图通过MSDN()上的示例了解如何查询USN日志以跟踪NTFS驱动器上的文件更改。示例代码运行良好 但是,在这个示例代码中,USN_记录结构只返回文件引用号和文件名。它不会返回文件的完整路径。有人知道如何查询USN日志以返回完整路径吗?或者有一种方法可以从文件引用号获取完整路径 谢谢。USN\u RECORD结构的ParentFileReferenceNumber成员是包含该文件的目录的参考号 您可以使用按参考号查找文件(或目录!)。您需要在树上迭代以构建完整的路径。这里有一些代码作为示例可

我试图通过MSDN()上的示例了解如何查询USN日志以跟踪NTFS驱动器上的文件更改。示例代码运行良好

但是,在这个示例代码中,USN_记录结构只返回文件引用号和文件名。它不会返回文件的完整路径。有人知道如何查询USN日志以返回完整路径吗?或者有一种方法可以从文件引用号获取完整路径


谢谢。

USN\u RECORD结构的
ParentFileReferenceNumber
成员是包含该文件的目录的参考号

您可以使用按参考号查找文件(或目录!)。您需要在树上迭代以构建完整的路径。这里有一些代码作为示例可能会有所帮助

此代码查找根目录的参考号,这样您就可以知道何时完成:

HANDLE rootdir_handle;
USN_RECORD * rootdir_usn;

printf("Opening root directory.\n");

rootdir_handle = CreateFile(L"\\\\?\\C:\\", GENERIC_READ, 
                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 
                            FILE_FLAG_BACKUP_SEMANTICS, NULL);

if (rootdir_handle == INVALID_HANDLE_VALUE)
{
    printf("CreateFile: %u\n", GetLastError());
    return 0;
}

if (!DeviceIoControl(rootdir_handle, FSCTL_READ_FILE_USN_DATA, NULL, 0, 
                     buffer, BUFFER_SIZE, &bytecount, NULL))
{
    printf("FSCTL_READ_FILE_USN_DATA: %u\n", GetLastError());
}
else
{
    rootdir_usn = (USN_RECORD *)buffer;
    show_record(rootdir_usn, FALSE);
    rootdir = rootdir_usn->FileReferenceNumber;
}

我一直试图避免递归父目录搜索以获取完整路径,因为我的初始测试增加了解析路径所需的总时间

在windbg上花了几个小时,在OSR Online fourm的帮助下,我终于得到了它

发布答案以帮助最终遇到相同问题的其他人

我目前的解决办法如下

USN\u RECORD->FileReferenceNumber完全依赖于USN\u RECORD的版本,一旦从FileReferenceNumber提取文件\u ID\u描述符,就可以调用OpenFileById()并传递文件\u ID\u描述符以获取父文件夹的句柄

然后可以调用GetFinalPathNameByHandle()来获取ParentDirectory路径

下面是我用来提取文件ID描述符的代码

如果USN_RECORD_V2中的文件ID为,则文件引用为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;
}
提取文件ID后,以下是获取父路径的方法

TCHAR filePath[MAX_PATH];
HANDLE hh= OpenFileById(volume_, &(getFileIdDescriptor(UsnRecord->FileReferenceNumber)), 0, 0, 0, 0);
GetFinalPathNameByHandle(hh,filePath, MAX_PATH, 0);
您可以找到参考实现@


但是我发现
GetFilePathNameByHandle()
实际上速度很慢,这个API最终会调用
GetFileInformationByHandleEx()
,而
GetFileInformationByHandleEx()
是对KernelMode的单个调用,这将是获取父信息的有效方法

为了成为一个维基,并有助于下一个搜索此问题的人,以及我希望为后代存档的事实,这里有:MSDN上解释更新序列号(USN)日志的页面,它是什么,它是如何工作的,以及如何查询它


@moonbear,你建议的编辑不正确。
FSCTL_ENUM_USN_DATA
的输出以一个USN开始,但是
FSCTL_READ_FILE_USN_DATA
的输出不会。TCHAR filePath[MAX_PATH]会将字符串限制为260个字符吗?