private static extern bool DeviceIoControl()

in simpleProviderManaged/FileSystemApi.cs [108:208]


        private static extern bool DeviceIoControl(
            SafeFileHandle deviceHandle,
            uint ioControlCode,
            IntPtr inputBuffer,
            int inputBufferSize,
            IntPtr outputBuffer,
            int outputBufferSize,
            out int bytesReturned,
            IntPtr overlapped);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
        private static extern SafeFileHandle CreateFileW(
            string lpFileName,
            FileDesiredAccess dwDesiredAccess,
            FileShare dwShareMode,
            IntPtr lpSecurityAttributes,
            FileMode dwCreationDisposition,
            FileFlagsAndAttributes dwFlagsAndAttributes,
            IntPtr hTemplateFile);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
        private static extern int CreateSymbolicLinkW(string lpSymlinkFileName, string lpTargetFileName, SymbolicLinkOptions dwFlags);

        [DllImport("shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
        private static extern bool PathRelativePathToW(
            System.Text.StringBuilder pszPath,
            string pszFrom,
            FileFlagsAndAttributes dwAttrFrom,
            string pszTo,
            FileFlagsAndAttributes dwAttrTo);

        private static unsafe string GetReparsePointTarget(SafeFileHandle handle)
        {
            string targetPath = string.Empty;

            int bufferSize = INITIAL_REPARSE_DATA_BUFFER_SIZE;
            int errorCode = ERROR_INSUFFICIENT_BUFFER;

            byte[] buffer = null;
            while (errorCode == ERROR_MORE_DATA || errorCode == ERROR_INSUFFICIENT_BUFFER)
            {
                buffer = new byte[bufferSize];
                bool success = false;

                fixed (byte* pBuffer = buffer)
                {
                    int bufferReturnedSize;
                    success = DeviceIoControl(
                        handle,
                        FSCTL_GET_REPARSE_POINT,
                        IntPtr.Zero,
                        0,
                        (IntPtr)pBuffer,
                        bufferSize,
                        out bufferReturnedSize,
                        IntPtr.Zero);
                }

                bufferSize *= 2;
                errorCode = success ? 0 : Marshal.GetLastWin32Error();
            }

            if (errorCode != 0)
            {
                throw new Win32Exception(errorCode, "DeviceIoControl(FSCTL_GET_REPARSE_POINT)");
            }

            // Now get the offsets in the REPARSE_DATA_BUFFER buffer string based on
            // the offsets for the different type of reparse points.

            const uint PrintNameOffsetIndex = 12;
            const uint PrintNameLengthIndex = 14;
            const uint SubsNameOffsetIndex = 8;
            const uint SubsNameLengthIndex = 10;

            fixed (byte* pBuffer = buffer)
            {
                uint reparsePointTag = *(uint*)(pBuffer);

                if (reparsePointTag != (uint)DwReserved0Flag.IO_REPARSE_TAG_SYMLINK
                    && reparsePointTag != (uint)DwReserved0Flag.IO_REPARSE_TAG_MOUNT_POINT)
                {
                    throw new NotSupportedException($"Reparse point tag {reparsePointTag:X} not supported");
                }

                uint pathBufferOffsetIndex = (uint)((reparsePointTag == (uint)DwReserved0Flag.IO_REPARSE_TAG_SYMLINK) ? 20 : 16);
                char* nameStartPtr = (char*)(pBuffer + pathBufferOffsetIndex);
                int nameOffset = *(short*)(pBuffer + PrintNameOffsetIndex) / 2;
                int nameLength = *(short*)(pBuffer + PrintNameLengthIndex) / 2;
                targetPath = new string(nameStartPtr, nameOffset, nameLength);

                if (string.IsNullOrWhiteSpace(targetPath))
                {
                    nameOffset = *(short*)(pBuffer + SubsNameOffsetIndex) / 2;
                    nameLength = *(short*)(pBuffer + SubsNameLengthIndex) / 2;
                    targetPath = new string(nameStartPtr, nameOffset, nameLength);
                }
            }

            return targetPath;
        }