Скажем, я создал символическую ссылку на каталог, используя mklink команда как таковая:
mklink / d «test dir link1» «dest dir»
Как я могу скопировать его как ссылку на целевой каталог? Когда я пытаюсь использовать API CopyFileEx и 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. Я попытался запустить мой процесс с повышенными правами (просто в маловероятном сценарии, который мне нужен для запуска с повышенными правами), и он все равно дал мне тот же код ошибки.
Вы просите скопировать каталог, используя 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 (скопирован из страница MSDN для 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
}
Это значительно сложнее, но он сохраняет символическую ссылку в своей основной форме, то есть, если это относительная ссылка, то созданная ссылка также будет относительной ссылкой. Кроме того, если цель не существует, ссылка все равно создается.
Это по-прежнему не устраняет необходимость быть (а) администратором или (б) редактировать групповую политику для разрешить пользователям без прав администратора создавать символические ссылки.