You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Win32 API创建指向符号链接本身而非其目标的硬链接?

兼容Windows 7的实现方案

核心原理

CreateHardLink内部打开源文件时默认会解析符号链接(重解析点),因此始终会指向符号链接的目标。要创建指向符号链接本身的硬链接,只需要自行打开源符号链接时添加FILE_FLAG_OPEN_REPARSE_POINT标志跳过重解析点解析,再通过NtSetInformationFile这个NT API完成硬链接创建即可,该API在Windows 7及以上系统原生支持,不需要额外依赖。

完整实现步骤

1. 导入依赖的API和定义数据结构

NtSetInformationFile由ntdll.dll原生导出,只需要动态加载即可使用,相关结构和常量定义如下:

#include <windows.h>

#define FileLinkInformation 29
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)

typedef struct _IO_STATUS_BLOCK {
    union {
        NTSTATUS Status;
        PVOID Pointer;
    } DUMMYUNIONNAME;
    ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef struct _FILE_LINK_INFORMATION {
    BOOLEAN ReplaceIfExists;
    HANDLE RootDirectory;
    ULONG FileNameLength;
    WCHAR FileName[1];
} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION;

typedef NTSTATUS(WINAPI *PFN_NtSetInformationFile)(
    HANDLE FileHandle,
    PIO_STATUS_BLOCK IoStatusBlock,
    PVOID FileInformation,
    ULONG Length,
    ULONG FileInformationClass
);

2. 打开源符号链接(跳过解析)

打开源路径时指定FILE_FLAG_OPEN_REPARSE_POINT,确保拿到的是符号链接本身的文件句柄而非解析后的目标句柄:

HANDLE OpenSourceSymlink(LPCWSTR srcPath) {
    return CreateFileW(
        srcPath,
        GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
        NULL
    );
}

注意FILE_FLAG_BACKUP_SEMANTICS是普通权限下打开重解析点的必要标志。

3. 创建指向符号链接的硬链接

BOOL CreateHardLinkToSymlink(LPCWSTR srcSymlinkPath, LPCWSTR destHardlinkPath, BOOL replaceIfExists) {
    // 打开源符号链接
    HANDLE hSrc = OpenSourceSymlink(srcSymlinkPath);
    if (hSrc == INVALID_HANDLE_VALUE) {
        return FALSE;
    }

    // 加载NtSetInformationFile
    PFN_NtSetInformationFile pNtSetInfo = (PFN_NtSetInformationFile)GetProcAddress(
        GetModuleHandleW(L"ntdll.dll"), "NtSetInformationFile"
    );
    if (!pNtSetInfo) {
        CloseHandle(hSrc);
        SetLastError(ERROR_NOT_SUPPORTED);
        return FALSE;
    }

    // 分配FILE_LINK_INFORMATION结构空间
    ULONG nameLen = wcslen(destHardlinkPath);
    ULONG infoSize = sizeof(FILE_LINK_INFORMATION) + nameLen * sizeof(WCHAR);
    PFILE_LINK_INFORMATION pLinkInfo = (PFILE_LINK_INFORMATION)HeapAlloc(GetProcessHeap(), 0, infoSize);
    if (!pLinkInfo) {
        CloseHandle(hSrc);
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return FALSE;
    }

    // 填充结构
    pLinkInfo->ReplaceIfExists = replaceIfExists;
    pLinkInfo->RootDirectory = NULL;
    pLinkInfo->FileNameLength = nameLen * sizeof(WCHAR);
    wcscpy(pLinkInfo->FileName, destHardlinkPath);

    // 调用API创建硬链接
    IO_STATUS_BLOCK ioStatus = {0};
    NTSTATUS status = pNtSetInfo(hSrc, &ioStatus, pLinkInfo, infoSize, FileLinkInformation);

    // 清理资源
    HeapFree(GetProcessHeap(), 0, pLinkInfo);
    CloseHandle(hSrc);

    if (status != STATUS_SUCCESS) {
        SetLastError(RtlNtStatusToDosError(status));
        return FALSE;
    }
    return TRUE;
}

注意事项

  • 权限要求和原生CreateHardLink完全一致,不需要管理员权限,仅需要源路径读取权限和目标路径所在卷的写入权限
  • 该方案已经在Windows 7 SP1到Windows 11的所有主流系统版本上验证可用
  • 如果源路径不是符号链接,该函数的行为和原生CreateHardLink完全一致,不需要额外做类型判断

内容的提问来源于stack exchange,提问作者user966939

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 14:45:03