在 C/C++ 中创建 Windows NTFS 目录联结时出现问题

Issue creating Windows NTFS directory junction in C/C++

我正在尝试使用 Visual C++ 执行此操作。这段代码似乎创建了一个连接点,设置了正确的目标,但是连接点的大小为 0,当我点击它时,我得到:

代码如下:

#include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
#include <ole2.h>
#include <errno.h>

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;

#define REPARSE_MOUNTPOINT_HEADER_SIZE 8

bool createJunction(WCHAR *linkPath, WCHAR *newTargetPath) {
    int create_status = CreateDirectory(linkPath, NULL);

    // If the directory already existed, treat it as a success.
    if (create_status == 0 && (GetLastError() != ERROR_ALREADY_EXISTS || (GetFileAttributesW(linkPath) & FILE_ATTRIBUTE_DIRECTORY) != 0))
        return false;

    HANDLE handle = CreateFile(linkPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
    if (handle == INVALID_HANDLE_VALUE)
    {
        _tprintf(_T("Could not open dir '%s'; error: %d\n"), linkPath, GetLastError());
        CloseHandle(handle);
        return false;
    }

    int target_len = wcslen(newTargetPath);
    if (target_len > MAX_PATH - 1) {
        CloseHandle(handle);
        return false;
    }

    int reparse_data_buffer_size = sizeof REPARSE_DATA_BUFFER + 2 * MAX_PATH * sizeof WCHAR;
    REPARSE_DATA_BUFFER* reparse_data_buffer = static_cast<REPARSE_DATA_BUFFER*>(calloc(reparse_data_buffer_size, 1));

    reparse_data_buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
    wcscpy(reparse_data_buffer->MountPointReparseBuffer.PathBuffer, newTargetPath);
    wcscpy(reparse_data_buffer->MountPointReparseBuffer.PathBuffer + target_len + 1, newTargetPath);
    reparse_data_buffer->MountPointReparseBuffer.SubstituteNameOffset = 0;
    reparse_data_buffer->MountPointReparseBuffer.SubstituteNameLength = target_len * sizeof(WCHAR);
    reparse_data_buffer->MountPointReparseBuffer.PrintNameOffset = (target_len + 1) * sizeof(WCHAR);
    reparse_data_buffer->MountPointReparseBuffer.PrintNameLength = target_len * sizeof(WCHAR);
    reparse_data_buffer->ReparseDataLength = (target_len + 1) * 2 * sizeof(WCHAR) + REPARSE_MOUNTPOINT_HEADER_SIZE;

    DWORD dummy_received_bytes;
    int result = DeviceIoControl(
        handle,
        FSCTL_SET_REPARSE_POINT,
        reparse_data_buffer,
        reparse_data_buffer->ReparseDataLength + REPARSE_MOUNTPOINT_HEADER_SIZE,
        NULL,
        0,
        &dummy_received_bytes,
        NULL);
    if (CloseHandle(handle) == 0)
        return false;
    free(reparse_data_buffer);

    return (result != 0);
}

int _tmain(int argc, _TCHAR* argv[])
{
    createJunction(L"C:\Users\Weston\Desktop\New folder\Junction of asdf", L"C:\Users\Weston\Desktop\New folder\asdf");

    _tprintf(_T("Execution complete.\n"));
    getchar();
}

我几乎可以肯定我没有在某处正确设置大小,但不确定是什么地方。没有错误或警告,似乎只是创建了大小为 0 的联结(具有正确的名称、目标和联结类型)。

未在目标路径前加上 \??\。这样做就是我需要做的。