您现在的位置是:网站首页> 编程资料编程资料
.Net中的Junction Points(交接点)操作_实用技巧_
2023-05-24
309人已围观
简介 .Net中的Junction Points(交接点)操作_实用技巧_
Junction Points是NTFS v5+的新特性,功能和我们所熟知的UNIX中的文件夹软链接类似(与Windows中的文件夹快捷方式不同的是,它进行了路径重定向)。如在Vista中的C:\Documents and Settings 就是C:\Users的一个链接。然而,在Windows中并没有提供相关命令,只能编程通过API来实现。
由于我对WinAPI编程并不熟,这里就不更多介绍了,更多信息请访问原作者相关文章。这里仅转一下相关函数用法:
创建Junction Point
// Creates a Junction Point at // C:\Foo\JunctionPoint that points to the directory C:\Bar. // Fails if there is already a file, // directory or Junction Point with the specified path. JunctionPoint.Create(@"C:\Foo\JunctionPoint", @"C:\Bar", false/*don't overwrite*/) // Creates a Junction Point at C:\Foo\JunctionPoint that points to // the directory C:\Bar. // Replaces an existing Junction Point if found at the specified path. JunctionPoint.Create(@"C:\Foo\JunctionPoint", @"C:\Bar", true/*overwrite*/)
注:不能对文件创建Junction Points.
删除Junction Point
// Delete a Junction Point at C:\Foo\JunctionPoint if it exists. // Does nothing if there is no such Junction Point. // Fails if the specified path refers to an existing file or // directory rather than a Junction Point. JunctionPoint.Delete(@"C:\Foo\JunctionPoint")
判断Junction Point是否存在
// Returns true if there is a Junction Point at C:\Foo\JunctionPoint. // Returns false if the specified path refers to an existing file // or directory rather than a Junction Point // or if it refers to the vacuum of space. bool exists = JunctionPoint.Exists(@"C:\Foo\JunctionPoint")
获取Junction Point所指向的实际地址
// Create a Junction Point for demonstration purposes whose target is C:\Bar. JunctionPoint.Create(@"C:\Foo\JunctionPoint", @"C:\Bar", false) // Returns the full path of the target of the Junction Point at // C:\Foo\JunctionPoint. // Fails if the specified path does not refer to a Junction Point. string target = JunctionPoint.GetTarget(@"C:\Foo\JunctionPoint") // target will be C:\Bar
注:这个函数有问题,对系统的权限要求过高,如果对系统盘的一些文件夹链接访问往往会报异常,我把它改了一下,新的代码如下:
////// Provides access to NTFS junction points in .Net. /// public static class JunctionPoint { ////// The file or directory is not a reparse point. /// private const int ERROR_NOT_A_REPARSE_POINT = 4390; ////// The reparse point attribute cannot be set because it conflicts with an existing attribute. /// private const int ERROR_REPARSE_ATTRIBUTE_CONFLICT = 4391; ////// The data present in the reparse point buffer is invalid. /// private const int ERROR_INVALID_REPARSE_DATA = 4392; ////// The tag present in the reparse point buffer is invalid. /// private const int ERROR_REPARSE_TAG_INVALID = 4393; ////// There is a mismatch between the tag specified in the request and the tag present in the reparse point. /// private const int ERROR_REPARSE_TAG_MISMATCH = 4394; ////// Command to set the reparse point data block. /// private const int FSCTL_SET_REPARSE_POINT = 0x000900A4; ////// Command to get the reparse point data block. /// private const int FSCTL_GET_REPARSE_POINT = 0x000900A8; ////// Command to delete the reparse point data base. /// private const int FSCTL_DELETE_REPARSE_POINT = 0x000900AC; ////// Reparse point tag used to identify mount points and junction points. /// private const uint IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003; ////// This prefix indicates to NTFS that the path is to be treated as a non-interpreted /// path in the virtual file system. /// private const string NonInterpretedPathPrefix = @"\??\"; [Flags] private enum EFileAccess : uint { GenericRead = 0x80000000, GenericWrite = 0x40000000, GenericExecute = 0x20000000, GenericAll = 0x10000000, GenericNone = 0x0, } [Flags] private enum EFileShare : uint { None = 0x00000000, Read = 0x00000001, Write = 0x00000002, Delete = 0x00000004, } private enum ECreationDisposition : uint { New = 1, CreateAlways = 2, OpenExisting = 3, OpenAlways = 4, TruncateExisting = 5, } [Flags] private enum EFileAttributes : uint { Readonly = 0x00000001, Hidden = 0x00000002, System = 0x00000004, Directory = 0x00000010, Archive = 0x00000020, Device = 0x00000040, Normal = 0x00000080, Temporary = 0x00000100, SparseFile = 0x00000200, ReparsePoint = 0x00000400, Compressed = 0x00000800, Offline = 0x00001000, NotContentIndexed = 0x00002000, Encrypted = 0x00004000, Write_Through = 0x80000000, Overlapped = 0x40000000, NoBuffering = 0x20000000, RandomAccess = 0x10000000, SequentialScan = 0x08000000, DeleteOnClose = 0x04000000, BackupSemantics = 0x02000000, PosixSemantics = 0x01000000, OpenReparsePoint = 0x00200000, OpenNoRecall = 0x00100000, FirstPipeInstance = 0x00080000 } [StructLayout(LayoutKind.Sequential)] private struct REPARSE_DATA_BUFFER { ////// Reparse point tag. Must be a Microsoft reparse point tag. /// public uint ReparseTag; ////// Size, in bytes, of the data after the Reserved member. This can be calculated by: /// (4 * sizeof(ushort)) + SubstituteNameLength + PrintNameLength + /// (namesAreNullTerminated ? 2 * sizeof(char) : 0); /// public ushort ReparseDataLength; ////// Reserved; do not use. /// public ushort Reserved; ////// Offset, in bytes, of the substitute name string in the PathBuffer array. /// public ushort SubstituteNameOffset; ////// Length, in bytes, of the substitute name string. If this string is null-terminated, /// SubstituteNameLength does not include space for the null character. /// public ushort SubstituteNameLength; ////// Offset, in bytes, of the print name string in the PathBuffer array. /// public ushort PrintNameOffset; ////// Length, in bytes, of the print name string. If this string is null-terminated, /// PrintNameLength does not include space for the null character. /// public ushort PrintNameLength; ////// A buffer containing the unicode-encoded path string. The path string contains /// the substitute name string and print name string. /// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3FF0)] public byte[] PathBuffer; } [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, IntPtr InBuffer, int nInBufferSize, IntPtr OutBuffer, int nOutBufferSize, out int pBytesReturned, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr CreateFile( string lpFileName, EFileAccess dwDesiredAccess, EFileShare dwShareMode, IntPtr lpSecurityAttributes, ECreationDisposition dwCreationDisposition, EFileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile); ////// Creates a junction point from the specified directory to the specified target directory. /// ////// Only works on NTFS. /// /// The junction point path /// The target directory /// If true overwrites an existing reparse point or empty directory ///Thrown when the junction point could not be created or when /// an existing directory was found and 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(NonInterpretedPathPrefix + Path.GetFullPath(targetDir)); 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); } } } ///if false /// Deletes a junction point at the specified source directory along with the directory itself. /// Does nothing if the junction point does not exist. /// ////// Only works on NTFS. /// /// The junction point path 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)) { REPARSE_DATA_BUFFER reparseDataBuffer = new REPARSE_DATA_BUFFER(); reparseDataBuffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT
相关内容
- .Net Core日志记录之第三方框架Serilog_实用技巧_
- .Net Core日志记录之自定义日志组件_实用技巧_
- .Net Core使用Logger实现log写入本地文件系统_实用技巧_
- .Net Core日志记录的核心机制_实用技巧_
- .Net Core日志记录之日志配置_实用技巧_
- 基于.Net Core认证授权方案之JwtBearer认证_实用技巧_
- 基于ABP架构开发的.Net Core项目部署到IIS问题汇总_实用技巧_
- .Net Core授权认证方案JWT(JSON Web Token)初探_实用技巧_
- ASP.Net Core基于ABP架构配置To Json序列化_实用技巧_
- 为Visual Studio手工安装微软ReportViewer控件_自学过程_
点击排行
本栏推荐
