Создание символической ссылки - данные, присутствующие в буфере точек повторной обработки, недействительны - PullRequest
0 голосов
/ 10 апреля 2019

Цель : создать символическую ссылку с помощью DeviceIoControl с FSCTL_SET_REPARSE_POINT

Я знаю, что CreateSymbolicLink Вызов 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), для создания еще одной.

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

1 Ответ

0 голосов
/ 12 апреля 2019

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

Звонок должен выглядеть как

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