Создание символической ссылки. Данные, присутствующие в буфере точек повторной обработки, недействительны

Цель: для создания символической ссылки с помощью 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), для создания другой.

Очевидно, я что-то упускаю - любые подсказки будут высоко оценены.

var reparseDataSize = Marshal.SizeOf(typeof(NativeMethods.REPARSE_DATA_BUFFER)); конечно ошибка - здесь должен быть реальный размер данных, который больше

RbMm 10.04.2019 17:59
PrintNameLength, SubstituteNameLength - не инициализированы.. я не могу понять код C# в деталях, но код obvivois неверен. ReparseTag не установлено, ReparseDataLength не установлено..
RbMm 10.04.2019 18:01

@RbMm структура репарса считывается из существующей симлинка в reparseData, reparseDataSize, сбоку есть какая-то распаковка, просто посмотреть что внутри, но тот самый нетронутый буфер передается обратно при создании новой симлинка

Michal Kupczyk 11.04.2019 11:38

ваш код неверен, конечно. у вас неправильный буфер инициализации

RbMm 11.04.2019 11:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
1 284
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Нужно передать точный размер структуры, а не размер всего выделенного буфера. Спасибо @RbMm

Вызов должен выглядеть

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

исправить дисковод с помощью команды-

  1. Откройте Windows PowerShell от имени администратора.
  2. Запустите «chkdsk/f»
  3. Диск будет заблокирован, запланируйте его для следующего перезапуска на следующем шаге.

Другие вопросы по теме