创建符号链接-重新解析点缓冲区中存在的数据无效

时间:2019-04-10 13:19:45

标签: winapi symlink deviceiocontrol

目标:使用带有FSCTL_SET_REPARSE_POINT的DeviceIoControl创建符号链接

我知道有 CreateSymbolicLink WinApi调用,它可以工作,但是我不能出于自己的目的使用它。

问题: 当我调用DeviceIOControl(hNewSymLink,FSCTL_SET_REPARSE_POINT ...

时,我一直收到0x80071128(重新解析点缓冲区中存在的数据无效)的信息。

“ c:”驱动器是NTFS,操作系统是Windows 10,我正在以管理员身份进行调试。

最初,我根据https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/b41f1cbf-10df-4a47-98d4-1c52a833d913尝试将REPARSE_DATA_BUFFER放在一起,以达到上述效果。

在test3()中,我阅读了良好的符号链接的结构,并尝试使用它来创建新的符号链接,但是该结构被拒绝,再次出现相同的错误。

void test3()
{
    using (SafeFileHandle hSymLink = NativeMethods.CreateFile(
        @"c:\Temp\link2",
        FileAccess.Read,
        FileShare.Read,
        IntPtr.Zero,
        FileMode.Open,
        (FileAttributes)(NativeMethods.EFileAttributes.FILE_FLAG_OPEN_REPARSE_POINT),
        IntPtr.Zero))
    {
        var reparseDataSize = Marshal.SizeOf(typeof(NativeMethods.REPARSE_DATA_BUFFER));
        var reparseData = Marshal.AllocHGlobal(reparseDataSize);

        try
        {
            int bytesReturned = 0;
            var result = NativeMethods.DeviceIoControl(hSymLink, NativeMethods.DeviceIOControlCode.FSCTL_GET_REPARSE_POINT,
                IntPtr.Zero, 0, 
                reparseData, reparseDataSize, 
                ref bytesReturned, IntPtr.Zero);

            if (!result)
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

            var reparseDataBuffer = (NativeMethods.REPARSE_DATA_BUFFER)
                    Marshal.PtrToStructure(reparseData, typeof(NativeMethods.REPARSE_DATA_BUFFER));

            var printNameDir = Encoding.Unicode.GetString(reparseDataBuffer.PathBuffer,
                    reparseDataBuffer.PrintNameOffset, reparseDataBuffer.PrintNameLength);
//value: "c:\\temp\\target.txt"
            var substituteNameDir = Encoding.Unicode.GetString(reparseDataBuffer.PathBuffer,
                    reparseDataBuffer.SubstituteNameOffset, reparseDataBuffer.SubstituteNameLength);
//value: "\\??\\c:\\temp\\target.txt"

            using (SafeFileHandle hNewSymLink = NativeMethods.CreateFile(
                @"c:\Temp\linkNew",
                FileAccess.Write,
                FileShare.Read,
                IntPtr.Zero,
                FileMode.Create,
                (FileAttributes)(NativeMethods.EFileAttributes.FILE_FLAG_OPEN_REPARSE_POINT), 
                IntPtr.Zero))
            {
                var result2 = NativeMethods.DeviceIoControl(hNewSymLink, NativeMethods.DeviceIOControlCode.FSCTL_SET_REPARSE_POINT,
                    reparseData, reparseDataSize, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero);

                if (!result2)
                    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
//error 0x80071128: wrong reparse buffer
            }
        }
        finally
        {
            Marshal.FreeHGlobal(reparseData);
        }
    }
}

当我检查结构时,看起来不错。 文档指出,相同的REPARSE_DATA_BUFFER用于获取和设置,因此我希望能够使用从现有符号链接(使用MKLINK系统命令创建)检索的格式正确的结构来创建另一个结构。

很明显,我缺少一些东西-任何提示将不胜感激。

2 个答案:

答案 0 :(得分:0)

需要传递结构的确切大小,而不是整个分配缓冲区的大小。谢谢@RbMm

通话应类似于

var result2 = NativeMethods.DeviceIoControl(hNewSymLink, 
    NativeMethods.DeviceIOControlCode.FSCTL_SET_REPARSE_POINT,
    reparseData, bytesReturned, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero);

答案 1 :(得分:0)

使用命令修复磁盘驱动器-

  1. 以管理员身份打开Windows PowerShell
  2. 运行“ chkdsk / f”
  3. 驱动器将被锁定,以计划在下一步中重新启动