Esempio n. 1
0
        /// <summary>
        /// Helper method to create a junction.
        /// </summary>
        /// <param name="path">The path of the junction to create.</param>
        /// <param name="target">The target for the junction.</param>
        public virtual void CreateJunction(string path, string target)
        {
            path   = Path.GetFullPath(path);
            target = Path.GetFullPath(target);

            Win32FindData data;

            using (var handle = NativeMethods.FindFirstFile(path, out data))
            {
                if (!handle.IsInvalid)
                {
                    throw new InvalidOperationException("A file or folder already exists with the same name as the junction.");
                }
            }

            Directory.CreateDirectory(path);

            var encoding = Encoding.Unicode;
            var nullChar = new byte[] { 0, 0 };

            var printName       = ParseDosDevicePath(target);
            var printNameBytes  = encoding.GetBytes(printName);
            var printNameLength = printNameBytes.Length;

            var substituteName       = FormatDosDevicePath(printName, false);
            var substituteNameBytes  = encoding.GetBytes(substituteName);
            var substituteNameLength = substituteNameBytes.Length;

            var junction = new JunctionData
            {
                SubstituteNameOffset = 0,
                SubstituteNameLength = checked ((ushort)substituteNameLength),
                PrintNameOffset      = checked ((ushort)(substituteNameLength + nullChar.Length)),
                PrintNameLength      = checked ((ushort)printNameLength)
            };

            var junctionLength = Marshal.SizeOf(junction) + nullChar.Length * 2;
            var reparseLength  = junctionLength + junction.SubstituteNameLength + junction.PrintNameLength;

            var reparse = new ReparseHeader
            {
                ReparseTag        = Win32Constants.IO_REPARSE_TAG_MOUNT_POINT,
                ReparseDataLength = checked ((ushort)(reparseLength)),
                Reserved          = 0,
            };

            var bufferLength = Marshal.SizeOf(reparse) + reparse.ReparseDataLength;

            using (var hReparsePoint = OpenReparsePoint(path, AccessRights.GenericWrite))
                using (var buffer = SafeLocalAllocHandle.Allocate(bufferLength))
                {
                    var offset = buffer.Write(0, reparse);
                    offset += buffer.Write(offset, junction);
                    offset += buffer.Write(offset, substituteNameBytes, 0, substituteNameBytes.Length);
                    offset += buffer.Write(offset, nullChar, 0, nullChar.Length);
                    offset += buffer.Write(offset, printNameBytes, 0, printNameBytes.Length);
                    offset += buffer.Write(offset, nullChar, 0, nullChar.Length);
                    Debug.Assert(offset == bufferLength);

                    int bytesReturned;
                    var b = NativeMethods.DeviceIoControl(
                        hReparsePoint,
                        Win32Constants.FSCTL_SET_REPARSE_POINT,
                        buffer,
                        bufferLength,
                        SafeLocalAllocHandle.InvalidHandle,
                        0,
                        out bytesReturned,
                        IntPtr.Zero);

                    if (!b)
                    {
                        throw new Win32Exception();
                    }
                }
        }
Esempio n. 2
0
        /// <summary>
        /// Given a path, returns the information about a reparse point.
        /// </summary>
        /// <param name="path">The path to inspect.</param>
        /// <returns>A <see cref="ReparseLink"/> that contains the information
        /// about a reparse point.</returns>
        public virtual ReparseLink GetLink(string path)
        {
            FileAttributes attributes;

            try
            {
                attributes = File.GetAttributes(path);
            }
            catch (DirectoryNotFoundException)
            {
                return(new ReparseLink());
            }
            catch (FileNotFoundException)
            {
                return(new ReparseLink());
            }

            var link = new ReparseLink
            {
                Attributes = attributes
            };

            if (!attributes.HasFlag(FileAttributes.ReparsePoint))
            {
                link.Type = attributes.HasFlag(FileAttributes.Directory)
          ? LinkType.Unknown
          : LinkType.HardLink;

                return(link);
            }

            var encoding          = Encoding.Unicode;
            var reparseHeaderSize = Marshal.SizeOf(typeof(ReparseHeader));
            var bufferLength      = reparseHeaderSize + 2048;

            using (var hReparsePoint = OpenReparsePoint(path, AccessRights.GenericRead))
            {
                int error;
                do
                {
                    using (var buffer = SafeLocalAllocHandle.Allocate(bufferLength))
                    {
                        int bytesReturned;
                        var b = NativeMethods.DeviceIoControl(
                            hReparsePoint,
                            Win32Constants.FSCTL_GET_REPARSE_POINT,
                            SafeLocalAllocHandle.InvalidHandle,
                            0,
                            buffer,
                            bufferLength,
                            out bytesReturned,
                            IntPtr.Zero);
                        error = Marshal.GetLastWin32Error();

                        if (b)
                        {
                            var reparseHeader = buffer.Read <ReparseHeader>(0);

                            IReparseData data;
                            switch (reparseHeader.ReparseTag)
                            {
                            case Win32Constants.IO_REPARSE_TAG_MOUNT_POINT:
                                data      = buffer.Read <JunctionData>(reparseHeaderSize);
                                link.Type = LinkType.Junction;
                                break;

                            case Win32Constants.IO_REPARSE_TAG_SYMLINK:
                                data      = buffer.Read <SymbolicData>(reparseHeaderSize);
                                link.Type = LinkType.Symbolic;
                                break;

                            default:
                                throw new InvalidOperationException(String.Format(
                                                                        "An unknown reparse tag {0:X} was encountered.",
                                                                        reparseHeader.ReparseTag));
                            }

                            var offset = Marshal.SizeOf(data) + reparseHeaderSize;
                            var target = buffer.ReadString(offset + data.SubstituteNameOffset, data.SubstituteNameLength, encoding);

                            link.Target = ParseDosDevicePath(target);
                            return(link);
                        }

                        if (error == Win32Constants.ERROR_INSUFFICIENT_BUFFER)
                        {
                            var reparseHeader = buffer.Read <ReparseHeader>(0);
                            bufferLength = reparseHeader.ReparseDataLength;
                        }
                        else
                        {
                            throw new Win32Exception(error);
                        }
                    }
                }while (error == Win32Constants.ERROR_INSUFFICIENT_BUFFER);
            }
            return(link);
        }