Цель: для создания символической ссылки с помощью DeviceIoControl с FSCTL_SET_REPARSE_POINT.
Я знаю, что есть вызов Создатьсимволическую ссылку WinApi, он работает, но я не могу использовать его для своей цели.
Проблема: Я продолжаю получать 0x80071128 (данные, присутствующие в буфере точки повторной обработки, недействительны), когда я вызываю DeviceIOControl(hNewSymLink,FSCTL_SET_REPARSE_POINT...
диск «c:» — NTFS, ОС — Windows 10, я отлаживаю как администратор.
Сначала я попытался собрать REPARSE_DATA_BUFFER в соответствии с https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/b41f1cbf-10df-4a47-98d4-1c52a833d913 для вышеуказанного эффекта.
В 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), для создания другой.
Очевидно, я что-то упускаю - любые подсказки будут высоко оценены.
PrintNameLength
, SubstituteNameLength
- не инициализированы.. я не могу понять код C# в деталях, но код obvivois неверен. ReparseTag
не установлено, ReparseDataLength
не установлено..
@RbMm структура репарса считывается из существующей симлинка в reparseData, reparseDataSize, сбоку есть какая-то распаковка, просто посмотреть что внутри, но тот самый нетронутый буфер передается обратно при создании новой симлинка
ваш код неверен, конечно. у вас неправильный буфер инициализации
Нужно передать точный размер структуры, а не размер всего выделенного буфера. Спасибо @RbMm
Вызов должен выглядеть
var result2 = NativeMethods.DeviceIoControl(hNewSymLink,
NativeMethods.DeviceIOControlCode.FSCTL_SET_REPARSE_POINT,
reparseData, bytesReturned, IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero);
исправить дисковод с помощью команды-
var reparseDataSize = Marshal.SizeOf(typeof(NativeMethods.REPARSE_DATA_BUFFER));
конечно ошибка - здесь должен быть реальный размер данных, который больше