说,我使用mklink命令创建了一个目录符号链接:
mklink / d“test dir link1”“dest dir”
如何将其复制为目标目录的链接?当我尝试使用CopyFileEx API和COPY_FILE_COPY_SYMLINK标志时:
::CopyFileEx(L"D:\\Path to source\\test dir link1",
L"D:\\Path to destination\\test dir link1 copy",
NULL, NULL, NULL,
COPY_FILE_COPY_SYMLINK);
它返回错误代码ERROR_ACCESS_DENIED
。
PS。我尝试运行我的进程提升(只是在不太可能的情况下,我需要运行提升),它仍然给了我相同的错误代码。
答案 0 :(得分:2)
您要求使用CopyFileEx
API复制目录。它是一个符号链接的事实直到检查它是一个目录后才得到解决,这意味着你不能使用这个API来复制目录符号链接。
目录符号链接与文件符号链接的处理方式略有不同 - 在创建它们时,您必须将额外的参数传递给CreateSymbolicLink
API。
在API文档中有一个关于此行为的微妙提示,其中声明:
要删除符号链接,请删除该文件(使用
DeleteFile
或类似的API)或删除目录(使用RemoveDirectory
或类似的API),具体取决于使用的符号链接类型。
这强烈表明处理文件的API不适用于目录符号链接。
现在关于如何复制它,我强烈期望你必须再次创建符号链接,这个过程是读取符号链接目标,然后在目标中第二次创建链接;类似的东西(根本没有错误处理,将相对链接转换为绝对链接):
HANDLE h = CreateFile(srcFile, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
TCHAR outbuffer[2048];
DWORD written = GetFinalPathNameByHandle(h, outbuffer, 2048, 0);
CreateSymbolicLink(targetFile, outbuffer, SYMBOLIC_LINK_FLAG_DIRECTORY);
CloseHandle(h);
现在使用底层重新分析点数据创建符号链接会让事情变得复杂一些。如果您没有ntifs.h
,那么您需要定义Microsoft重新分析点数据结构(从the MSDN page for REPARSE_DATA_STRUCTURE复制):
typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
USHORT ReparseDataLength;
USHORT Reserved;
union {
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
ULONG Flags;
WCHAR PathBuffer[1];
} SymbolicLinkReparseBuffer;
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
WCHAR PathBuffer[1];
} MountPointReparseBuffer;
struct {
UCHAR DataBuffer[1];
} GenericReparseBuffer;
};
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
我们改变了例程:
HANDLE h = CreateFile(srcFile, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
if (h != INVALID_HANDLE_VALUE) {
char tmpBuffer[32 * 1024];
REPARSE_DATA_BUFFER *repBuffer = reinterpret_cast<REPARSE_DATA_BUFFER *>(tmpBuffer);
DWORD retBytes;
if (DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, 0, 0, (void *)tmpBuffer,
sizeof tmpBuffer, &retBytes, 0)) {
if (repBuffer->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
wchar_t dest[2048];
memcpy(dest, repBuffer->SymbolicLinkReparseBuffer.PathBuffer +
repBuffer->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t),
repBuffer->SymbolicLinkReparseBuffer.PrintNameLength);
dest[repBuffer->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(wchar_t)] = 0;
if (!CreateSymbolicLink(targetFile, dest, SYMBOLIC_LINK_FLAG_DIRECTORY)) {
// Error Handling
}
}
}
CloseHandle(h);
} else {
// Open Error Handling
}
它明显更复杂,但它保留了它的底层形式的符号链接,即如果它是相对链接,那么创建的链接也将是相对链接。此外,如果目标不存在,则仍会创建链接。
这仍然无需删除(a)管理员或(b)将组策略编辑为permit non-admin users to create symbolic links。
答案 1 :(得分:0)
我在寻找有关设置了 COPY_FILE_COPY_SYMLINK 标志的 CopyFileEx 行为的答案时发现了这个旧线程。我有执行此操作的代码,它所做的只是创建具有正确名称的空文件。它们不是功能性符号链接。我什至以提升的权限运行(代码以管理员身份运行,具有 SE_BACKUP_NAME、SE_RESTORE_NAME 权限 - 甚至尝试明确添加 SE_CREATE_SYMBOLIC_LINK_NAME),但没有任何变化。
我还使用 /SL 开关运行 Robocopy -- 它也只是创建这些无用的空文件。似乎是 CopyFileEx 错误(Windows 10 x64)。
PeteSh 的代码应该可以工作(我还没有尝试过),但是很遗憾 CopyFileEx 不能像宣传的那样工作。