创建符号链接 - 重分析点缓冲区中存在的数据无效
Creating symlink - The data present in the reparse point buffer is invalid
目标:使用 DeviceIoControl 和 FSCTL_SET_REPARSE_POINT
创建符号 link
我知道有 CreateSymbolicLink WinApi 调用,它有效,但我无法将其用于我的目的。
问题:
当我调用 DeviceIOControl(hNewSymLink,FSCTL_SET_REPARSE_POINT ...
时,我不断收到 0x80071128(重分析点缓冲区中存在的数据无效)
'c:' 驱动器是 NTFS,OS 是 Windows 10,我正在以管理员身份调试。
最初我尝试按照 https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/b41f1cbf-10df-4a47-98d4-1c52a833d913 将 REPARSE_DATA_BUFFER 放在一起以达到上述效果。
在 test3() 中,我阅读了 good symlink 的结构并尝试使用它来创建新的结构,但该结构被拒绝,再次出现相同的错误。
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 用于 get 和 set,因此我希望能够使用从现有 symlink(使用 MKLINK 系统命令创建)检索的格式正确的结构来创建另一个。
显然我遗漏了一些东西 - 任何提示都将不胜感激。
需要传递结构的确切大小,而不是整个已分配缓冲区的大小。谢谢@RbMm
调用应该类似于
var result2 = NativeMethods.DeviceIoControl(hNewSymLink,
NativeMethods.DeviceIOControlCode.FSCTL_SET_REPARSE_POINT,
reparseData, bytesReturned, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero);
使用命令修复磁盘驱动器-
- 以管理员身份打开 Windows PowerShell
- 运行 "chkdsk /f"
- 驱动器将被锁定并安排在下一步中重新启动
目标:使用 DeviceIoControl 和 FSCTL_SET_REPARSE_POINT
创建符号 link我知道有 CreateSymbolicLink WinApi 调用,它有效,但我无法将其用于我的目的。
问题: 当我调用 DeviceIOControl(hNewSymLink,FSCTL_SET_REPARSE_POINT ...
时,我不断收到 0x80071128(重分析点缓冲区中存在的数据无效)'c:' 驱动器是 NTFS,OS 是 Windows 10,我正在以管理员身份调试。
最初我尝试按照 https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/b41f1cbf-10df-4a47-98d4-1c52a833d913 将 REPARSE_DATA_BUFFER 放在一起以达到上述效果。
在 test3() 中,我阅读了 good symlink 的结构并尝试使用它来创建新的结构,但该结构被拒绝,再次出现相同的错误。
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 用于 get 和 set,因此我希望能够使用从现有 symlink(使用 MKLINK 系统命令创建)检索的格式正确的结构来创建另一个。
显然我遗漏了一些东西 - 任何提示都将不胜感激。
需要传递结构的确切大小,而不是整个已分配缓冲区的大小。谢谢@RbMm
调用应该类似于
var result2 = NativeMethods.DeviceIoControl(hNewSymLink,
NativeMethods.DeviceIOControlCode.FSCTL_SET_REPARSE_POINT,
reparseData, bytesReturned, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero);
使用命令修复磁盘驱动器-
- 以管理员身份打开 Windows PowerShell
- 运行 "chkdsk /f"
- 驱动器将被锁定并安排在下一步中重新启动