获取符号 link 目标 [NTFS] 的卷名的最佳方法
Best way to get volume name of symbolic link target [NTFS]
我想要一种可靠的方法来获取符号 link 的目标的卷名称,该目标不是很复杂。
所以看起来 FILE_NAME_INFO
结构不包含有关文件所在卷的任何信息。我能够从此结构中获取 symlink 目标的路径,但现在我只是假设目标驻留在同一卷上。但是,我知道 symlinks 允许其他卷上的目标。
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <ole2.h>
struct FILE_NAME_INFO_AND_BUF {
FILE_NAME_INFO fni;
WCHAR buf[260];
};
WCHAR* getReparseTarget(WCHAR* linkFileName) {
HANDLE hFile;
WCHAR *szGuid = (WCHAR *)malloc(sizeof(WCHAR) * MAX_PATH);
BOOL result;
FILE_NAME_INFO_AND_BUF fnib = { 0 };
hFile = ::CreateFile(linkFileName, FILE_READ_ATTRIBUTES,
FILE_SHARE_READ |
FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, 0);
if (hFile == INVALID_HANDLE_VALUE) {
::CloseHandle(hFile);
return NULL;
}
result = ::GetFileInformationByHandleEx(hFile, FileNameInfo, &fnib, sizeof(fnib));
if (!result) {
fprintf(stderr, "GetFileInformationByHandleEx Error %d\n", ::GetLastError());
::CloseHandle(hFile);
return NULL;
}
WCHAR *targetFileName = (WCHAR *)malloc(sizeof(WCHAR) * MAX_PATH);
wmemset(targetFileName, 0, MAX_PATH);
wcsncpy(targetFileName, linkFileName, 2);
wcscat(targetFileName, fnib.fni.FileName);
return targetFileName;
}
如您所见,我在作弊并从输入字符串中获取卷名,在本例中为驱动器号,但如果目标位于另一个卷上,这将不起作用。此外,我更喜欢使用 GUID 获取卷名,例如\?\Volume{f993747a-5d7a-4de1-a97a-c20c1af1ba02}\
在其中比驱动器号例如C:\
最简单的方法,只要您可以针对 Vista 或更高版本,就是使用 GetFinalPathNameByHandle
函数。
如果您还需要以 XP 为目标,那么您可以通过使用 [=11= 打开 link 本身(而不是它指向的文件)来找到 symlink 的目标]标志,然后使用FSCTL_GET_REPARSE_POINT
IO控制代码找到link的目标。
因为 link 的目标可能包含其他 link(我相信最多 31 个),您必须对路径的每个元素执行此操作以确保你找到了最终目标。
我想要一种可靠的方法来获取符号 link 的目标的卷名称,该目标不是很复杂。
所以看起来 FILE_NAME_INFO
结构不包含有关文件所在卷的任何信息。我能够从此结构中获取 symlink 目标的路径,但现在我只是假设目标驻留在同一卷上。但是,我知道 symlinks 允许其他卷上的目标。
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <ole2.h>
struct FILE_NAME_INFO_AND_BUF {
FILE_NAME_INFO fni;
WCHAR buf[260];
};
WCHAR* getReparseTarget(WCHAR* linkFileName) {
HANDLE hFile;
WCHAR *szGuid = (WCHAR *)malloc(sizeof(WCHAR) * MAX_PATH);
BOOL result;
FILE_NAME_INFO_AND_BUF fnib = { 0 };
hFile = ::CreateFile(linkFileName, FILE_READ_ATTRIBUTES,
FILE_SHARE_READ |
FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, 0);
if (hFile == INVALID_HANDLE_VALUE) {
::CloseHandle(hFile);
return NULL;
}
result = ::GetFileInformationByHandleEx(hFile, FileNameInfo, &fnib, sizeof(fnib));
if (!result) {
fprintf(stderr, "GetFileInformationByHandleEx Error %d\n", ::GetLastError());
::CloseHandle(hFile);
return NULL;
}
WCHAR *targetFileName = (WCHAR *)malloc(sizeof(WCHAR) * MAX_PATH);
wmemset(targetFileName, 0, MAX_PATH);
wcsncpy(targetFileName, linkFileName, 2);
wcscat(targetFileName, fnib.fni.FileName);
return targetFileName;
}
如您所见,我在作弊并从输入字符串中获取卷名,在本例中为驱动器号,但如果目标位于另一个卷上,这将不起作用。此外,我更喜欢使用 GUID 获取卷名,例如\?\Volume{f993747a-5d7a-4de1-a97a-c20c1af1ba02}\
在其中比驱动器号例如C:\
最简单的方法,只要您可以针对 Vista 或更高版本,就是使用 GetFinalPathNameByHandle
函数。
如果您还需要以 XP 为目标,那么您可以通过使用 [=11= 打开 link 本身(而不是它指向的文件)来找到 symlink 的目标]标志,然后使用FSCTL_GET_REPARSE_POINT
IO控制代码找到link的目标。
因为 link 的目标可能包含其他 link(我相信最多 31 个),您必须对路径的每个元素执行此操作以确保你找到了最终目标。