Changeset 2549
- Timestamp:
- 3/19/2012 8:06:33 AM (14 months ago)
- Location:
- trunk/eraser/Eraser.Util
- Files:
-
- 3 edited
-
ExtensionMethods/PathUtil.cs (modified) (2 diffs)
-
NativeMethods/Kernel.cs (modified) (2 diffs)
-
VolumeInfo.cs (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/eraser/Eraser.Util/ExtensionMethods/PathUtil.cs
r2516 r2549 27 27 using System.Drawing; 28 28 using System.Windows.Forms; 29 using System.Runtime.InteropServices; 30 using Microsoft.Win32.SafeHandles; 29 31 30 32 namespace Eraser.Util.ExtensionMethods … … 162 164 return GetCompactPath(longPath, newWidth, control.Font); 163 165 } 166 167 /// <summary> 168 /// Resolves the reparse point pointed to by the path. 169 /// </summary> 170 /// <param name="path">The path to the reparse point.</param> 171 /// <returns>The NT Namespace Name of the reparse point.</returns> 172 public static string ResolveReparsePoint(string path) 173 { 174 if (string.IsNullOrEmpty(path)) 175 throw new ArgumentException(path); 176 177 //If the path is a directory, remove the trailing \ 178 if (Directory.Exists(path) && path[path.Length - 1] == '\\') 179 path = path.Remove(path.Length - 1); 180 181 using (SafeFileHandle handle = NativeMethods.CreateFile(path, 182 NativeMethods.GENERIC_READ, 183 NativeMethods.FILE_SHARE_READ | NativeMethods.FILE_SHARE_WRITE, 184 IntPtr.Zero, NativeMethods.OPEN_EXISTING, 185 NativeMethods.FILE_FLAG_OPEN_REPARSE_POINT | 186 NativeMethods.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero)) 187 { 188 if (handle.IsInvalid) 189 throw new System.IO.IOException(string.Format("Cannot open handle to {0}", path)); 190 191 int bufferSize = Marshal.SizeOf(typeof(NativeMethods.REPARSE_DATA_BUFFER)) + 260 * sizeof(char); 192 IntPtr buffer = Marshal.AllocHGlobal(bufferSize); 193 194 //Get all the information about the reparse point. 195 try 196 { 197 uint returnedBytes = 0; 198 while (!NativeMethods.DeviceIoControl(handle, NativeMethods.FSCTL_GET_REPARSE_POINT, 199 IntPtr.Zero, 0, buffer, (uint)bufferSize, out returnedBytes, IntPtr.Zero)) 200 { 201 if (Marshal.GetLastWin32Error() == 122) //ERROR_INSUFFICIENT_BUFFER 202 { 203 bufferSize *= 2; 204 Marshal.FreeHGlobal(buffer); 205 buffer = Marshal.AllocHGlobal(bufferSize); 206 } 207 else 208 { 209 throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()); 210 } 211 } 212 213 string result = ResolveReparsePoint(buffer, path); 214 215 //Is it a directory? If it is, we need to add a trailing \ 216 if (Directory.Exists(path)) 217 result += '\\'; 218 return result; 219 } 220 finally 221 { 222 Marshal.FreeHGlobal(buffer); 223 } 224 } 225 } 226 227 private static string ResolveReparsePoint(IntPtr ptr, string path) 228 { 229 NativeMethods.REPARSE_DATA_BUFFER buffer = (NativeMethods.REPARSE_DATA_BUFFER) 230 Marshal.PtrToStructure(ptr, typeof(NativeMethods.REPARSE_DATA_BUFFER)); 231 232 //Check that this Reparse Point has a Microsoft Tag 233 if (((uint)buffer.ReparseTag & (1 << 31)) == 0) 234 { 235 //We can only handle Microsoft's reparse tags. 236 throw new ArgumentException("Unknown Reparse point type."); 237 } 238 239 //Then handle the tags 240 switch (buffer.ReparseTag) 241 { 242 case NativeMethods.REPARSE_DATA_TAG.IO_REPARSE_TAG_MOUNT_POINT: 243 return ResolveReparsePointJunction((IntPtr)(ptr.ToInt64() + Marshal.SizeOf(buffer))); 244 245 case NativeMethods.REPARSE_DATA_TAG.IO_REPARSE_TAG_SYMLINK: 246 return ResolveReparsePointSymlink((IntPtr)(ptr.ToInt64() + Marshal.SizeOf(buffer)), 247 path); 248 249 default: 250 throw new ArgumentException("Unsupported Reparse point type."); 251 } 252 } 253 254 private static string ResolveReparsePointJunction(IntPtr ptr) 255 { 256 NativeMethods.REPARSE_DATA_BUFFER.MountPointReparseBuffer buffer = 257 (NativeMethods.REPARSE_DATA_BUFFER.MountPointReparseBuffer) 258 Marshal.PtrToStructure(ptr, 259 typeof(NativeMethods.REPARSE_DATA_BUFFER.MountPointReparseBuffer)); 260 261 //Get the substitute and print names from the buffer. 262 string substituteName; 263 string printName; 264 unsafe 265 { 266 char* path = (char*)(((byte*)ptr.ToInt64()) + Marshal.SizeOf(buffer)); 267 printName = new string(path + (buffer.PrintNameOffset / sizeof(char)), 0, 268 buffer.PrintNameLength / sizeof(char)); 269 substituteName = new string(path + (buffer.SubstituteNameOffset / sizeof(char)), 0, 270 buffer.SubstituteNameLength / sizeof(char)); 271 } 272 273 return substituteName; 274 } 275 276 private static string ResolveReparsePointSymlink(IntPtr ptr, string path) 277 { 278 NativeMethods.REPARSE_DATA_BUFFER.SymbolicLinkReparseBuffer buffer = 279 (NativeMethods.REPARSE_DATA_BUFFER.SymbolicLinkReparseBuffer) 280 Marshal.PtrToStructure(ptr, 281 typeof(NativeMethods.REPARSE_DATA_BUFFER.SymbolicLinkReparseBuffer)); 282 283 //Get the substitute and print names from the buffer. 284 string substituteName; 285 string printName; 286 unsafe 287 { 288 char* pathBuffer = (char*)(((byte*)ptr.ToInt64()) + Marshal.SizeOf(buffer)); 289 printName = new string(pathBuffer + (buffer.PrintNameOffset / sizeof(char)), 0, 290 buffer.PrintNameLength / sizeof(char)); 291 substituteName = new string(pathBuffer + (buffer.SubstituteNameOffset / sizeof(char)), 0, 292 buffer.SubstituteNameLength / sizeof(char)); 293 } 294 295 if ((buffer.Flags & NativeMethods.REPARSE_DATA_BUFFER.SymbolicLinkFlags.SYMLINK_FLAG_RELATIVE) != 0) 296 { 297 return Path.Combine(Path.GetDirectoryName(path), substituteName); 298 } 299 300 return substituteName; 301 } 164 302 } 165 303 } -
trunk/eraser/Eraser.Util/NativeMethods/Kernel.cs
r2516 r2549 652 652 [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 653 653 [return: MarshalAs(UnmanagedType.Bool)] 654 public static externbool DeviceIoControl(SafeFileHandle hDevice,654 public extern static bool DeviceIoControl(SafeFileHandle hDevice, 655 655 uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, 656 656 out NTFS_VOLUME_DATA_BUFFER lpOutBuffer, uint nOutBufferSize, … … 764 764 /// </summary> 765 765 public long ExtentLength; 766 } 767 768 public const uint FSCTL_GET_REPARSE_POINT = (9 << 16) | (42 << 2); 769 770 /// <summary> 771 /// The REPARSE_DATA_BUFFER structure contains reparse point data for a 772 /// Microsoft reparse point. (Third-party reparse point owners must use 773 /// the REPARSE_GUID_DATA_BUFFER structure instead.) 774 /// </summary> 775 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 776 public struct REPARSE_DATA_BUFFER 777 { 778 /// <summary> 779 /// Contains the reparse point information for a Symbolic Link. 780 /// </summary> 781 /// <remarks>The PathBuffer member found at the end of the C structure 782 /// declaration is appended at the end of this structure.</remarks> 783 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 784 public struct SymbolicLinkReparseBuffer 785 { 786 /// <summary> 787 /// Offset, in bytes, of the substitute name string in the PathBuffer 788 /// array. Note that this offset must be divided by sizeof(char) to 789 /// get the array index. 790 /// </summary> 791 public ushort SubstituteNameOffset; 792 793 /// <summary> 794 /// Length, in bytes, of the substitute name string. If this string is 795 /// NULL-terminated, SubstituteNameLength does not include space for 796 /// the UNICODE_NULL character. 797 /// </summary> 798 public ushort SubstituteNameLength; 799 800 /// <summary> 801 /// Offset, in bytes, of the print name string in the PathBuffer array. 802 /// Note that this offset must be divided by sizeof(char) to get the 803 /// array index. 804 /// </summary> 805 public ushort PrintNameOffset; 806 807 /// <summary> 808 /// Length, in bytes, of the print name string. If this string is 809 /// NULL-terminated, PrintNameLength does not include space for the 810 /// UNICODE_NULL character. 811 /// </summary> 812 public ushort PrintNameLength; 813 814 /// <summary> 815 /// Used to indicate if the given symbolic link is an absolute or relative 816 /// symbolic link. If Flags contains SYMLINK_FLAG_RELATIVE, the symbolic 817 /// link contained in the PathBuffer array (at offset SubstitueNameOffset) 818 /// is processed as a relative symbolic link; otherwise, it is processed 819 /// as an absolute symbolic link. 820 /// </summary> 821 public SymbolicLinkFlags Flags; 822 } 823 824 /// <summary> 825 /// Contains the reparse point information for a Directory Junction. 826 /// </summary> 827 /// <remarks>The PathBuffer member found at the end of the C structure 828 /// declaration is appended at the end of this structure.</remarks> 829 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 830 public struct MountPointReparseBuffer 831 { 832 /// <summary> 833 /// Offset, in bytes, of the substitute name string in the PathBuffer 834 /// array. Note that this offset must be divided by sizeof(char) to 835 /// get the array index. 836 /// </summary> 837 public ushort SubstituteNameOffset; 838 839 /// <summary> 840 /// Length, in bytes, of the substitute name string. If this string is 841 /// NULL-terminated, SubstituteNameLength does not include space for 842 /// the UNICODE_NULL character. 843 /// </summary> 844 public ushort SubstituteNameLength; 845 846 /// <summary> 847 /// Offset, in bytes, of the print name string in the PathBuffer array. 848 /// Note that this offset must be divided by sizeof(char) to get the 849 /// array index. 850 /// </summary> 851 public ushort PrintNameOffset; 852 853 /// <summary> 854 /// Length, in bytes, of the print name string. If this string is 855 /// NULL-terminated, PrintNameLength does not include space for the 856 /// UNICODE_NULL character. 857 /// </summary> 858 public ushort PrintNameLength; 859 } 860 861 [Flags] 862 public enum SymbolicLinkFlags 863 { 864 /// <summary> 865 /// <see cref="SymbolicLinkReparseBuffer.Flags"/> 866 /// </summary> 867 SYMLINK_FLAG_RELATIVE = 0x00000001 868 } 869 870 /// <summary> 871 /// Reparse point tag. Must be a Microsoft reparse point tag. (See the following Remarks section.) 872 /// </summary> 873 public REPARSE_DATA_TAG ReparseTag; 874 875 /// <summary> 876 /// Size, in bytes, of the reparse data in the DataBuffer member. 877 /// </summary> 878 public ushort ReparseDataLength; 879 ushort Reserved; 880 } 881 882 /// <summary> 883 /// See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365511%28v=vs.85%29.aspx. 884 /// </summary> 885 public enum REPARSE_DATA_TAG : uint 886 { 887 IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003, 888 IO_REPARSE_TAG_HSM = 0xC0000004, 889 IO_REPARSE_TAG_HSM2 = 0x80000006, 890 IO_REPARSE_TAG_SIS = 0x80000007, 891 IO_REPARSE_TAG_WIM = 0x80000008, 892 IO_REPARSE_TAG_CSV = 0x80000009, 893 IO_REPARSE_TAG_DFS = 0x8000000A, 894 IO_REPARSE_TAG_SYMLINK = 0xA000000C, 895 IO_REPARSE_TAG_DFSR = 0x80000012 766 896 } 767 897 -
trunk/eraser/Eraser.Util/VolumeInfo.cs
r2516 r2549 304 304 else 305 305 { 306 //If this is a mountpoint, resolve it before calling 307 //GetVolumeNameForVolumeMountPoint since it will return an error if 308 //the path given is a reparse point, but not a volume reparse point. 309 while ((new DirectoryInfo(currentDir).Attributes & FileAttributes.ReparsePoint) != 0) 310 { 311 currentDir = ExtensionMethods.PathUtil.ResolveReparsePoint(currentDir); 312 313 //Strip the NT namespace bit 314 if (currentDir.StartsWith("\\??\\Volume")) 315 throw new ArgumentException(S._("The path provided includes a reparse" + 316 "point which references another volume.")); 317 else 318 currentDir = currentDir.Substring(4); 319 mountpointDir = new DirectoryInfo(currentDir); 320 } 321 306 322 if (!NativeMethods.GetVolumeNameForVolumeMountPoint(currentDir, volumeID, 50)) 307 323 {
Note: See TracChangeset
for help on using the changeset viewer.
