Esempio n. 1
0
        public static string GetDestination(string path)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException(nameof(path));
            }

            FileAttributes attributes;

            if (!Kernel32.TryGetFileAttributes(path, out attributes))
            {
                throw new IOException($"The path '{path}' does not exist.");
            }

            if ((attributes & JunctionAttributes) == JunctionAttributes)
            {
                ReparseDataBuffer data = GetReparseData(path);
                if (data.ReparseTag == ReparseTagType.MountPoint)
                {
                    string destination = Encoding.Unicode.GetString(data.PathBuffer, data.SubstituteNameOffset, data.SubstituteNameLength);
                    if (destination.StartsWith(DestinationPrefix))
                    {
                        destination = destination.Substring(DestinationPrefix.Length);
                    }
                    return(destination);
                }
            }

            throw new IOException($"The path '{path}' does not point to a valid directory junction.");
        }
Esempio n. 2
0
        /// <summary>
        /// Creates a junction point from the specified directory to the specified target directory.
        /// </summary>
        /// <remarks>
        /// Only works on NTFS.
        /// </remarks>
        /// <param name="junctionPoint">The junction point path</param>
        /// <param name="targetDir">The target directory</param>
        /// <param name="overwrite">If true overwrites an existing reparse point or empty directory</param>
        /// <exception cref="IOException">Thrown when the junction point could not be created or when
        /// an existing directory was found and <paramref name="overwrite" /> if false</exception>
        public static void Create(string junctionPoint, string targetDir, bool overwrite)
        {
            targetDir = Path.GetFullPath(targetDir);

            if (!Directory.Exists(targetDir))
            {
                throw new IOException("Target path does not exist or is not a directory.");
            }

            if (Directory.Exists(junctionPoint))
            {
                if (!overwrite)
                {
                    throw new IOException("Directory already exists and overwrite parameter is false.");
                }
            }
            else
            {
                Directory.CreateDirectory(junctionPoint);
            }

            using (SafeFileHandle handle = OpenReparsePoint(junctionPoint, EFileAccess.GenericWrite))
            {
                byte[] targetDirBytes = Encoding.Unicode.GetBytes(NON_INTERPRETED_PATH_PREFIX + Path.GetFullPath(targetDir));

                ReparseDataBuffer reparseDataBuffer = new ReparseDataBuffer();

                reparseDataBuffer.ReparseTag           = IO_REPARSE_TAG_MOUNT_POINT;
                reparseDataBuffer.ReparseDataLength    = (ushort)(targetDirBytes.Length + 12);
                reparseDataBuffer.SubstituteNameOffset = 0;
                reparseDataBuffer.SubstituteNameLength = (ushort)targetDirBytes.Length;
                reparseDataBuffer.PrintNameOffset      = (ushort)(targetDirBytes.Length + 2);
                reparseDataBuffer.PrintNameLength      = 0;
                reparseDataBuffer.PathBuffer           = new byte[0x3ff0];
                Array.Copy(targetDirBytes, reparseDataBuffer.PathBuffer, targetDirBytes.Length);

                int    inBufferSize = Marshal.SizeOf(reparseDataBuffer);
                IntPtr inBuffer     = Marshal.AllocHGlobal(inBufferSize);

                try
                {
                    Marshal.StructureToPtr(reparseDataBuffer, inBuffer, false);

                    int  bytesReturned;
                    bool result = DeviceIoControl(handle.DangerousGetHandle(), FSCTL_SET_REPARSE_POINT,
                                                  inBuffer, targetDirBytes.Length + 20, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);

                    if (!result)
                    {
                        ThrowLastWin32Error("Unable to create junction point.");
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(inBuffer);
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Deletes a junction point at the specified source directory along with the directory itself.
        /// Does nothing if the junction point does not exist.
        /// </summary>
        /// <remarks>
        /// Only works on NTFS.
        /// </remarks>
        /// <param name="junctionPoint">The junction point path</param>
        public static void Delete(string junctionPoint)
        {
            if (!Directory.Exists(junctionPoint))
            {
                if (File.Exists(junctionPoint))
                {
                    throw new IOException("Path is not a junction point.");
                }

                return;
            }

            using (SafeFileHandle handle = OpenReparsePoint(junctionPoint, EFileAccess.GenericWrite))
            {
                ReparseDataBuffer reparseDataBuffer = new ReparseDataBuffer();

                reparseDataBuffer.ReparseTag        = IO_REPARSE_TAG_MOUNT_POINT;
                reparseDataBuffer.ReparseDataLength = 0;
                reparseDataBuffer.PathBuffer        = new byte[0x3ff0];

                int    inBufferSize = Marshal.SizeOf(reparseDataBuffer);
                IntPtr inBuffer     = Marshal.AllocHGlobal(inBufferSize);
                try
                {
                    Marshal.StructureToPtr(reparseDataBuffer, inBuffer, false);

                    int  bytesReturned;
                    bool result = DeviceIoControl(handle.DangerousGetHandle(), FSCTL_DELETE_REPARSE_POINT,
                                                  inBuffer, 8, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);

                    if (!result)
                    {
                        ThrowLastWin32Error("Unable to delete junction point.");
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(inBuffer);
                }

                try
                {
                    Directory.Delete(junctionPoint);
                }
                catch (IOException ex)
                {
                    throw new IOException("Unable to delete junction point.", ex);
                }
            }
        }
Esempio n. 4
0
        public static void SetDestination(string path, string destination)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException(nameof(path));
            }
            if (string.IsNullOrEmpty(destination))
            {
                throw new ArgumentNullException(nameof(destination));
            }

            FileAttributes attributes;

            if (!Kernel32.TryGetFileAttributes(path, out attributes))
            {
                throw new IOException($"The path '{path}' does not exist.");
            }

            if ((attributes & FileAttributes.Directory) == FileAttributes.Directory)
            {
                destination = Path.GetFullPath(destination);
                string print = destination;
                destination = DestinationPrefix + destination;

                int destinationLength = Encoding.Unicode.GetByteCount(destination);
                int printLength       = Encoding.Unicode.GetByteCount(print);

                var data = new ReparseDataBuffer()
                {
                    ReparseTag           = ReparseTagType.MountPoint,
                    ReparseDataLength    = (ushort)(4 * sizeof(ushort) + destinationLength + sizeof(char) + printLength + sizeof(char)),
                    SubstituteNameOffset = 0,
                    SubstituteNameLength = (ushort)destinationLength,
                    PrintNameOffset      = (ushort)(destinationLength + sizeof(char)),
                    PrintNameLength      = (ushort)printLength,
                    PathBuffer           = new byte[0x3FF0]
                };

                Encoding.Unicode.GetBytes(destination, 0, destination.Length, data.PathBuffer, 0);
                Encoding.Unicode.GetBytes(print, 0, print.Length, data.PathBuffer, destinationLength + sizeof(char));

                SetReparseData(path, data);
                return;
            }

            throw new IOException($"The path '{path}' does not point to a valid directory.");
        }
Esempio n. 5
0
        private static void SetReparseData(string path, ReparseDataBuffer data)
        {
            using SafeFileHandle reparsePointHandle = OpenReparsePoint(path, true);
            IntPtr buffer = Marshal.AllocHGlobal(Marshal.SizeOf(data));

            try
            {
                Marshal.StructureToPtr(data, buffer, false);

                Kernel32.DeviceIOControl(reparsePointHandle, IOControlCode.FsctlSetReparsePoint,
                                         buffer, ReparseDataBuffer.HeaderSize + data.ReparseDataLength, IntPtr.Zero, 0, out _);
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }
        internal static void CreateReparsePoint(string junctionPoint, string targetDirectoryPath)
        {
            using (var handle = OpenReparsePoint(junctionPoint, EFileAccess.GenericWrite))
            {
                var targetDirBytes = Encoding.Unicode.GetBytes(_nonInterpretedPathPrefix + Path.GetFullPath(targetDirectoryPath));

                var reparseDataBuffer = new ReparseDataBuffer();
                reparseDataBuffer.ReparseTag           = _reparseTagMountPoint;
                reparseDataBuffer.ReparseDataLength    = (ushort)(targetDirBytes.Length + 12);
                reparseDataBuffer.SubstituteNameOffset = 0;
                reparseDataBuffer.SubstituteNameLength = (ushort)targetDirBytes.Length;
                reparseDataBuffer.PrintNameOffset      = (ushort)(targetDirBytes.Length + 2);
                reparseDataBuffer.PrintNameLength      = 0;
                reparseDataBuffer.PathBuffer           = new byte[0x3ff0];

                Array.Copy(targetDirBytes, reparseDataBuffer.PathBuffer, targetDirBytes.Length);

                var inBufferSize = Marshal.SizeOf(reparseDataBuffer);
                var inBuffer     = Marshal.AllocHGlobal(inBufferSize);

                try
                {
                    Marshal.StructureToPtr(reparseDataBuffer, inBuffer, false);

                    int bytesReturned;
                    var result = DeviceIoControl(
                        handle.DangerousGetHandle(),
                        _setReparsePointCommand,
                        inBuffer,
                        targetDirBytes.Length + 20,
                        IntPtr.Zero,
                        0,
                        out bytesReturned,
                        IntPtr.Zero);

                    if (!result)
                    {
                        ThrowLastWin32Error("Unable to create junction point.");
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(inBuffer);
                }
            }
        }
Esempio n. 7
0
        private static string InternalGetTarget(SafeFileHandle handle)
        {
            int    outBufferSize = Marshal.SizeOf(typeof(ReparseDataBuffer));
            IntPtr outBuffer     = Marshal.AllocHGlobal(outBufferSize);

            try
            {
                int  bytesReturned;
                bool result = DeviceIoControl(handle.DangerousGetHandle(), FSCTL_GET_REPARSE_POINT,
                                              IntPtr.Zero, 0, outBuffer, outBufferSize, out bytesReturned, IntPtr.Zero);

                if (!result)
                {
                    int error = Marshal.GetLastWin32Error();
                    if (error == ERROR_NOT_A_REPARSE_POINT)
                    {
                        return(null);
                    }

                    ThrowLastWin32Error("Unable to get information about junction point.");
                }

                ReparseDataBuffer reparseDataBuffer = (ReparseDataBuffer)
                                                      Marshal.PtrToStructure(outBuffer, typeof(ReparseDataBuffer));

                if (reparseDataBuffer.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
                {
                    return(null);
                }

                string targetDir = Encoding.Unicode.GetString(reparseDataBuffer.PathBuffer,
                                                              reparseDataBuffer.SubstituteNameOffset, reparseDataBuffer.SubstituteNameLength);

                if (targetDir.StartsWith(NON_INTERPRETED_PATH_PREFIX))
                {
                    targetDir = targetDir.Substring(NON_INTERPRETED_PATH_PREFIX.Length);
                }

                return(targetDir);
            }
            finally
            {
                Marshal.FreeHGlobal(outBuffer);
            }
        }
Esempio n. 8
0
        private static ReparseDataBuffer GetReparseData(string path)
        {
            using SafeFileHandle reparsePointHandle = OpenReparsePoint(path, false);
            IntPtr buffer = Marshal.AllocHGlobal(ReparseDataBuffer.MaximumSize);

            try
            {
                Kernel32.DeviceIOControl(reparsePointHandle, IOControlCode.FsctlGetReparsePoint,
                                         IntPtr.Zero, 0, buffer, ReparseDataBuffer.MaximumSize, out _);

                ReparseDataBuffer data = Marshal.PtrToStructure <ReparseDataBuffer>(buffer);
                return(data);
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Determines whether the given path refers to an existing directory junction on disk.
        /// </summary>
        /// <param name="path">The path to test.</param>
        /// <returns>Returns true if path refers to an existing directory junction, othwerwise false.</returns>
        public static bool Exists(string path)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException(nameof(path));
            }

            if (!Kernel32.TryGetFileAttributes(path, out var attributes))
            {
                return(false);
            }

            if ((attributes & JunctionAttributes) != JunctionAttributes)
            {
                return(false);
            }

            ReparseDataBuffer data = GetReparseData(path);

            return(data.ReparseTag == ReparseTagType.MountPoint);
        }
 private static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, out ReparseDataBuffer outBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped);
Esempio n. 11
0
 private static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, out ReparseDataBuffer outBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped);