Как скопировать каталог символическую ссылку как ссылку на цель?

Скажем, я создал символическую ссылку на каталог, используя 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. Я попытался запустить мой процесс с повышенными правами (просто в маловероятном сценарии, который мне нужен для запуска с повышенными правами), и он все равно дал мне тот же код ошибки.

0

Решение

Вы просите скопировать каталог, используя 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
}

Это значительно сложнее, но он сохраняет символическую ссылку в своей основной форме, то есть, если это относительная ссылка, то созданная ссылка также будет относительной ссылкой. Кроме того, если цель не существует, ссылка все равно создается.

Это по-прежнему не устраняет необходимость быть (а) администратором или (б) редактировать групповую политику для разрешить пользователям без прав администратора создавать символические ссылки.

2

Другие решения


По вопросам рекламы [email protected]