public static void CreateSymlinkTo(this PathSpec linkPath, PathSpec targetPath) { switch (targetPath.GetPathType()) { case PathType.File: if (!CreateSymbolicLink(linkPath.ToString(), targetPath.ToString(), TargetIsAFile)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } break; default: if (!CreateSymbolicLink(linkPath.ToString(), targetPath.ToString(), TargetIsADirectory) || Marshal.GetLastWin32Error() != 0) { try { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } catch (COMException exception) { throw new IOException(exception.Message, exception); } } break; } }
/// <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 CreateJunctionPointTo(this PathSpec junctionPoint, PathSpec targetDir, bool overwrite) { targetDir = targetDir.ToAbsolute(); if (targetDir.GetPathType() != PathType.Folder) throw new IOException("Target path does not exist or is not a directory."); if (junctionPoint.GetPathType() == PathType.Folder) { if (!overwrite) throw new IOException("Directory already exists and overwrite parameter is false."); } else { junctionPoint.Create(PathType.Folder); } using (SafeFileHandle handle = OpenReparsePoint(junctionPoint.ToString(), EFileAccess.GenericWrite)) { byte[] targetDirBytes = Encoding.Unicode.GetBytes(NonInterpretedPathPrefix + Path.GetFullPath(targetDir.ToString())); REPARSE_DATA_BUFFER reparseDataBuffer = new REPARSE_DATA_BUFFER(); 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); } } }