Пример #1
0
        /// <summary>[AlphaFS] Creates an NTFS directory junction (similar to CMD command: "MKLINK /J").</summary>
        internal static void CreateDirectoryJunction(SafeFileHandle safeHandle, string directoryPath)
        {
            var targetDirBytes = Encoding.Unicode.GetBytes(Path.NonInterpretedPathPrefix + Path.GetRegularPathCore(directoryPath, GetFullPathOptions.AddTrailingDirectorySeparator, false));

            var header = new NativeMethods.ReparseDataBufferHeader
            {
                ReparseTag        = ReparsePointTag.MountPoint,
                ReparseDataLength = (ushort)(targetDirBytes.Length + 12)
            };

            var mountPoint = new NativeMethods.MountPointReparseBuffer
            {
                SubstituteNameOffset = 0,
                SubstituteNameLength = (ushort)targetDirBytes.Length,
                PrintNameOffset      = (ushort)(targetDirBytes.Length + UnicodeEncoding.CharSize),
                PrintNameLength      = 0
            };

            var reparseDataBuffer = new NativeMethods.REPARSE_DATA_BUFFER
            {
                ReparseTag        = header.ReparseTag,
                ReparseDataLength = header.ReparseDataLength,

                SubstituteNameOffset = mountPoint.SubstituteNameOffset,
                SubstituteNameLength = mountPoint.SubstituteNameLength,
                PrintNameOffset      = mountPoint.PrintNameOffset,
                PrintNameLength      = mountPoint.PrintNameLength,

                PathBuffer = new byte[NativeMethods.MAXIMUM_REPARSE_DATA_BUFFER_SIZE - 16] // 16368
            };

            targetDirBytes.CopyTo(reparseDataBuffer.PathBuffer, 0);


            using (var safeBuffer = new SafeGlobalMemoryBufferHandle(Marshal.SizeOf(reparseDataBuffer)))
            {
                safeBuffer.StructureToPtr(reparseDataBuffer, false);

                uint bytesReturned;
                var  succes = NativeMethods.DeviceIoControl2(safeHandle, NativeMethods.FSCTL_SET_REPARSE_POINT, safeBuffer, (uint)(targetDirBytes.Length + 20), IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);

                var lastError = Marshal.GetLastWin32Error();
                if (!succes)
                {
                    NativeError.ThrowException(lastError, directoryPath);
                }
            }
        }
Пример #2
0
        internal static LinkTargetInfo GetLinkTargetInfoInternal(SafeFileHandle safeHandle)
        {
            // Start with a large buffer to prevent a 2nd call.
            uint bytesReturned = NativeMethods.MaxPathUnicode;

            using (SafeGlobalMemoryBufferHandle safeBuffer = new SafeGlobalMemoryBufferHandle((int)bytesReturned))
            {
                do
                {
                    // Possible PInvoke signature bug: safeBuffer.Capacity and bytesReturned are always the same.
                    // Since a large buffer is used, we are not affected.

                    // DeviceIoControlMethod.Buffered = 0,
                    // DeviceIoControlFileDevice.FileSystem = 9
                    // FsctlGetReparsePoint = (DeviceIoControlFileDevice.FileSystem << 16) | (42 << 2) | DeviceIoControlMethod.Buffered | (0 << 14)

                    if (!NativeMethods.DeviceIoControl(safeHandle, ((9 << 16) | (42 << 2) | 0 | (0 << 14)), IntPtr.Zero, 0, safeBuffer, (uint)safeBuffer.Capacity, out bytesReturned, IntPtr.Zero))
                    {
                        int lastError = Marshal.GetLastWin32Error();
                        switch ((uint)lastError)
                        {
                        case Win32Errors.ERROR_MORE_DATA:
                        case Win32Errors.ERROR_INSUFFICIENT_BUFFER:
                            if (safeBuffer.Capacity < bytesReturned)
                            {
                                safeBuffer.Close();
                                break;
                            }

                            // Throws IOException.
                            NativeError.ThrowException(lastError, true);
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }
                } while (true);



                // CA2001:AvoidCallingProblematicMethods

                IntPtr buffer     = IntPtr.Zero;
                bool   successRef = false;
                safeBuffer.DangerousAddRef(ref successRef);

                // MSDN: The DangerousGetHandle method poses a security risk because it can return a handle that is not valid.
                if (successRef)
                {
                    buffer = safeBuffer.DangerousGetHandle();
                }

                safeBuffer.DangerousRelease();

                if (buffer == IntPtr.Zero)
                {
                    NativeError.ThrowException(Resources.HandleDangerousRef);
                }

                // CA2001:AvoidCallingProblematicMethods


                Type   toMountPointReparseBuffer   = typeof(NativeMethods.MountPointReparseBuffer);
                Type   toReparseDataBufferHeader   = typeof(NativeMethods.ReparseDataBufferHeader);
                Type   toSymbolicLinkReparseBuffer = typeof(NativeMethods.SymbolicLinkReparseBuffer);
                IntPtr marshalReparseBuffer        = Marshal.OffsetOf(toReparseDataBufferHeader, "data");

                NativeMethods.ReparseDataBufferHeader header = Utils.MarshalPtrToStructure <NativeMethods.ReparseDataBufferHeader>(0, buffer);

                IntPtr dataPos;
                byte[] dataBuffer;

                switch (header.ReparseTag)
                {
                case ReparsePointTag.MountPoint:
                    NativeMethods.MountPointReparseBuffer mprb = Utils.MarshalPtrToStructure <NativeMethods.MountPointReparseBuffer>(0, new IntPtr(buffer.ToInt64() + marshalReparseBuffer.ToInt64()));

                    dataPos    = new IntPtr(marshalReparseBuffer.ToInt64() + Marshal.OffsetOf(toMountPointReparseBuffer, "data").ToInt64());
                    dataBuffer = new byte[bytesReturned - dataPos.ToInt64()];

                    Marshal.Copy(new IntPtr(buffer.ToInt64() + dataPos.ToInt64()), dataBuffer, 0, dataBuffer.Length);

                    return(new LinkTargetInfo(
                               Encoding.Unicode.GetString(dataBuffer, mprb.SubstituteNameOffset, mprb.SubstituteNameLength),
                               Encoding.Unicode.GetString(dataBuffer, mprb.PrintNameOffset, mprb.PrintNameLength)));


                case ReparsePointTag.SymLink:
                    NativeMethods.SymbolicLinkReparseBuffer slrb = Utils.MarshalPtrToStructure <NativeMethods.SymbolicLinkReparseBuffer>(0, new IntPtr(buffer.ToInt64() + marshalReparseBuffer.ToInt64()));

                    dataPos    = new IntPtr(marshalReparseBuffer.ToInt64() + Marshal.OffsetOf(toSymbolicLinkReparseBuffer, "data").ToInt64());
                    dataBuffer = new byte[bytesReturned - dataPos.ToInt64()];

                    Marshal.Copy(new IntPtr(buffer.ToInt64() + dataPos.ToInt64()), dataBuffer, 0, dataBuffer.Length);

                    return(new SymbolicLinkTargetInfo(
                               Encoding.Unicode.GetString(dataBuffer, slrb.SubstituteNameOffset, slrb.SubstituteNameLength),
                               Encoding.Unicode.GetString(dataBuffer, slrb.PrintNameOffset, slrb.PrintNameLength), slrb.Flags));


                default:
                    throw new UnrecognizedReparsePointException();
                }
            }
        }