2014-06-09 228 views
0

說,我創建使用mklink命令,這樣的目錄符號鏈接:作爲鏈接到目標目錄如何將目錄符號鏈接複製爲目標鏈接?

mklink/d「測試目錄鏈接1」,「目標目錄」

我怎麼能複製嗎?當我嘗試使用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

根據需要測試您是否具有讀取和寫入權限,並且該文件具有適當的所有權/模式。無論是鏈接,文件,目錄還是其他目錄,它都被認爲是用於linux/gcc計算目的的'文件'。所以先檢查基礎知識。 –

+0

@ DavidC.Rankin:我問這是用於Windows操作系統。是的,我有適當的文件所有權。 – c00000fd

回答

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做,那麼你需要定義微軟重新分析點的數據結構(從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

+0

好的。謝謝。我明白了爲什麼我得到一個錯誤。不過,我的問題依然存在。如何複製該鏈接? – c00000fd

+0

您可能不得不重新創建它。 – Petesh

+0

爲什麼不給你的僞代碼樣本添加一個'CloseHandle'調用,我將其標記爲答案。它似乎做的工作。這種方法的缺點是需要以管理員身份運行。這需要獲得'CreateSymbolicLink'成功所需的'SE_CREATE_SYMBOLIC_LINK_NAME'特權。 – c00000fd