這個問題的快速背景,因為我相信它會引起一些人的注意:我正在用 C 開發一個命令列工具來進行備份,我正在使用 NTFS 硬鏈接實作增量備份。因此,如果符號鏈接存在于先前的備份中,我必須能夠指向符號鏈接本身,而不是目標。
不幸的是,CreateHardLink的頁面明確指出:
符號鏈接行為 - 如果路徑指向符號鏈接,則該函式會創建到目標的硬鏈接。
現在我一直在想,這個問題的解決方案是什么?如何創建指向符號鏈接本身而不是目標的硬鏈接?我確實注意到 Windows 的內部命令MKLINK似乎能夠創建到符號鏈接的硬鏈接。所以理論上,我想我可以system在 C 中使用該函式,但老實說,它感覺很懶惰,我傾向于避免它。是否有可能僅使用 Win32 API 的解決方案?
我還看到了來自 Google 開發人員的一些代碼片段([1] [2]),其中包含有關實作等的一些詳細資訊CreateHardLink,但對我而言,它的級別似乎太低了,無法真正理解它。此外,(我可能錯了)GitHub 存盤庫中提供的功能似乎只與 Windows 10 及更高版本兼容,但我希望至少也支持 Windows 7。
uj5u.com熱心網友回復:
CreateHardLink創建指向符號鏈接(重決議點)本身的硬鏈接,而不是指向目標。所以檔案根本是錯誤的。在lpExistingFileName與選項打開FILE_OPEN_REPARSE_POINT
,所以你可以簡單地使用CreateHardLink的是并沒有什么更需要待辦事項。反之亦然 - 如果您想創建指向目標的硬鏈接,則需要自定義實作CreateHardLink和 不使用FILE_OPEN_REPARSE_POINT(如果您將使用NtOpenFile)或FILE_FLAG_OPEN_REPARSE_POINT如果您使用CreatFileW)
我確實注意到 Windows 的內部命令 MKLINK 似乎能夠創建到符號鏈接的硬鏈接。
如果您使用命令除錯cmd.exe,mklink您很容易注意到它也只是CreateHardLinkW呼叫了 api(設定斷點)
創建到符號鏈接檔案的硬鏈接后,您可以在資源管理器中查看該檔案型別為.symlink。對于測驗,FSCTL_DELETE_REPARSE_POINT如果硬鏈接指向目標,我們可以從目標檔案中洗掉鏈接(通過使用) - 任何帶有符號鏈接的操作都不會影響硬鏈接。但是如果我們創建了硬鏈接到自身的符號鏈接 - 在打破符號鏈接之后 - 硬鏈接也將被打破:
void TestCreateHardLink(PCWSTR lpFileName, PCWSTR lpSymlinkFileName, PCWSTR lpExistingFileName)
{
if (CreateSymbolicLinkW(lpSymlinkFileName, lpExistingFileName, 0))
{
if (CreateHardLinkW(lpFileName, lpSymlinkFileName, 0))
{
HANDLE hFile = CreateFileW(lpSymlinkFileName, FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE, 0, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
REPARSE_DATA_BUFFER rdb = { IO_REPARSE_TAG_SYMLINK };
OVERLAPPED ov {};
if (DeviceIoControl(hFile, FSCTL_DELETE_REPARSE_POINT, &rdb, sizeof(rdb), 0, 0, 0, &ov))
{
MessageBoxW(0, 0, 0, 0);
}
CloseHandle(hFile);
}
DeleteFileW(lpFileName);
}
DeleteFileW(lpSymlinkFileName);
}
}
我們想要更靈活地實作 hardlink create (set target) ,可以使用下一個代碼:
HRESULT CreateHardLinkExW(PCWSTR lpFileName, PCWSTR lpExistingFileName, BOOLEAN ReplaceIfExisting, BOOLEAN bToTarget)
{
HANDLE hFile = CreateFileW(lpExistingFileName, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING,
bToTarget ? FILE_FLAG_BACKUP_SEMANTICS : FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return HRESULT_FROM_WIN32(GetLastError());
}
UNICODE_STRING NtName;
NTSTATUS status = RtlDosPathNameToNtPathName_U_WithStatus(lpFileName, &NtName, 0, 0);
if (0 <= status)
{
ULONG Length = FIELD_OFFSET(FILE_LINK_INFORMATION, FileName) NtName.Length;
if (PFILE_LINK_INFORMATION LinkInfo = (PFILE_LINK_INFORMATION)_malloca(Length))
{
LinkInfo->ReplaceIfExists = ReplaceIfExisting;
LinkInfo->RootDirectory = 0;
LinkInfo->FileNameLength = NtName.Length;
memcpy(LinkInfo->FileName, NtName.Buffer, NtName.Length);
IO_STATUS_BLOCK iosb;
status = NtSetInformationFile(hFile, &iosb, LinkInfo, Length, FileLinkInformation);
}
else
{
status = STATUS_NO_MEMORY;
}
RtlFreeUnicodeString(&NtName);
}
CloseHandle(hFile);
return 0 > status ? HRESULT_FROM_NT(status) : S_OK;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/367272.html
