Changeset 2180
- Timestamp:
- 6/18/2010 9:33:10 AM (20 months ago)
- Location:
- trunk/eraser/Eraser.Util
- Files:
-
- 2 edited
-
NativeMethods/NtDll.cs (modified) (1 diff)
-
PhysicalDriveInfo.cs (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/eraser/Eraser.Util/NativeMethods/NtDll.cs
r2155 r2180 306 306 public ushort MinorVersion; 307 307 } 308 309 /// <summary> 310 /// Represents a counted Unicode string. 311 /// </summary> 312 private struct UNICODE_STRING 313 { 314 /// <summary> 315 /// Constructs a UNICODE_STRING object from an existing <see cref="System.String"/> 316 /// object. 317 /// </summary> 318 /// <param name="str">The string to construct from.</param> 319 public UNICODE_STRING(string str) 320 { 321 if (string.IsNullOrEmpty(str)) 322 MaximumLength = Length = 0; 323 else 324 MaximumLength = Length = checked((ushort)(str.Length * sizeof(char))); 325 Buffer = str; 326 } 327 328 /// <summary> 329 /// Allocates an empty string of the given length. 330 /// </summary> 331 /// <param name="length">The length, in characters, to allocate.</param> 332 public UNICODE_STRING(ushort length) 333 { 334 MaximumLength = checked((ushort)(length * sizeof(char))); 335 Length = 0; 336 Buffer = new string('\0', length); 337 } 338 339 public override string ToString() 340 { 341 if (Length / sizeof(char) > Buffer.Length) 342 return Buffer + new string('\0', Length - Buffer.Length / sizeof(char)); 343 else 344 return Buffer.Substring(0, Length / sizeof(char)); 345 } 346 347 /// <summary> 348 /// Specifies the length, in bytes, of the string pointed to by the Buffer 349 /// member, not including the terminating NULL character, if any. 350 /// </summary> 351 public ushort Length; 352 353 /// <summary> 354 /// Specifies the total size, in bytes, of memory allocated for Buffer. Up to 355 /// MaximumLength bytes may be written into the buffer without trampling memory. 356 /// </summary> 357 public ushort MaximumLength; 358 359 /// <summary> 360 /// Pointer to a wide-character string. 361 /// </summary> 362 [MarshalAs(UnmanagedType.LPWStr)] 363 public string Buffer; 364 } 365 366 /// <summary> 367 /// The OBJECT_ATTRIBUTES structure specifies attributes that can be applied to 368 /// objects or object handles by routines that create objects and/or return 369 /// handles to objects. 370 /// </summary> 371 private struct OBJECT_ATTRIBUTES : IDisposable 372 { 373 public OBJECT_ATTRIBUTES(UNICODE_STRING objectName) 374 : this() 375 { 376 Length = (uint)Marshal.SizeOf(this); 377 ObjectName = Marshal.AllocHGlobal(Marshal.SizeOf(objectName)); 378 Marshal.StructureToPtr(objectName, ObjectName, false); 379 } 380 381 public void Dispose() 382 { 383 Dispose(true); 384 GC.SuppressFinalize(this); 385 } 386 387 public void Dispose(bool disposing) 388 { 389 if (ObjectName != IntPtr.Zero) 390 Marshal.FreeHGlobal(ObjectName); 391 } 392 393 /// <summary> 394 /// The number of bytes of data contained in this structure. 395 /// </summary> 396 public uint Length; 397 398 /// <summary> 399 /// Optional handle to the root object directory for the path name specified by 400 /// the ObjectName member. If RootDirectory is NULL, ObjectName must point 401 /// to a fully-qualified object name that includes the full path to the target 402 /// object. If RootDirectory is non-NULL, ObjectName specifies an object name 403 /// relative to the RootDirectory directory. The RootDirectory handle can refer 404 /// to a file system directory or an object directory in the object manager 405 /// namespace. 406 /// </summary> 407 public IntPtr RootDirectory; 408 409 /// <summary> 410 /// Pointer to a Unicode string that contains the name of the object for which 411 /// a handle is to be opened. This must either be a fully qualified object name, 412 /// or a relative path name to the directory specified by the RootDirectory 413 /// member. 414 /// </summary> 415 public IntPtr ObjectName; 416 417 /// <summary> 418 /// Bitmask of flags that specify object handle attributes. This member can 419 /// contain one or more of the flags in the following table. 420 /// </summary> 421 OBJECT_ATTRIBUTESFlags Attributes; 422 423 /// <summary> 424 /// Specifies a security descriptor (SECURITY_DESCRIPTOR) for the object 425 /// when the object is created. If this member is NULL, the object will 426 /// receive default security settings. 427 /// </summary> 428 IntPtr SecurityDescriptor; 429 430 /// <summary> 431 /// Optional quality of service to be applied to the object when it is created. 432 /// Used to indicate the security impersonation level and context tracking mode 433 /// (dynamic or static). Currently, the InitializeObjectAttributes macro sets 434 /// this member to NULL. 435 /// </summary> 436 IntPtr SecurityQualityOfService; 437 } 438 439 [Flags] 440 public enum OBJECT_ATTRIBUTESFlags 441 { 442 /// <summary> 443 /// No flags specified. 444 /// </summary> 445 None = 0 446 } 447 448 /// <summary> 449 /// Opens an existing symbolic link. 450 /// </summary> 451 /// <param name="LinkHandle">A handle to the newly opened symbolic link object.</param> 452 /// <param name="DesiredAccess">An ACCESS_MASK that specifies the requested access 453 /// to the directory object. It is typical to use GENERIC_READ so the handle can be 454 /// passed to the NtQueryDirectoryObject function.</param> 455 /// <param name="ObjectAttributes">The attributes for the directory object.</param> 456 /// <returns>The function returns STATUS_SUCCESS or an error status.</returns> 457 [DllImport("NtDll.dll")] 458 private static extern uint NtOpenSymbolicLinkObject(out IntPtr LinkHandle, 459 uint DesiredAccess, ref OBJECT_ATTRIBUTES ObjectAttributes); 460 461 /// <summary> 462 /// Retrieves the target of a symbolic link. 463 /// </summary> 464 /// <param name="LinkHandle">A handle to the symbolic link object.</param> 465 /// <param name="LinkTarget">A pointer to an initialized Unicode string that receives 466 /// the target of the symbolic link. The MaximumLength and Buffer members must be 467 /// set if the call fails.</param> 468 /// <param name="ReturnedLength">A pointer to a variable that receives the length of 469 /// the Unicode string returned in the LinkTarget parameter. If the function 470 /// returns STATUS_BUFFER_TOO_SMALL, this variable receives the required buffer 471 /// size.</param> 472 /// <returns>The function returns STATUS_SUCCESS or an error status.</returns> 473 [DllImport("NtDll.dll")] 474 private static extern uint NtQuerySymbolicLinkObject(IntPtr LinkHandle, 475 ref UNICODE_STRING LinkTarget, out uint ReturnedLength); 476 477 /// <summary> 478 /// Queries the provided symbolic link for its target. 479 /// </summary> 480 /// <param name="path">The path to query.</param> 481 /// <returns>The destination of the symbolic link.</returns> 482 public static string NtQuerySymbolicLink(string path) 483 { 484 uint status = 0; 485 IntPtr handle = IntPtr.Zero; 486 UNICODE_STRING drive = new UNICODE_STRING(path); 487 OBJECT_ATTRIBUTES attributes = new OBJECT_ATTRIBUTES(drive); 488 489 try 490 { 491 status = NtOpenSymbolicLinkObject(out handle, GENERIC_READ, ref attributes); 492 if (status != 0) 493 return null; 494 } 495 finally 496 { 497 attributes.Dispose(); 498 } 499 500 UNICODE_STRING target = new UNICODE_STRING(MaxPath); 501 uint length = 0; 502 for ( ; ; ) 503 { 504 status = NtQuerySymbolicLinkObject(handle, ref target, out length); 505 if (status == 0) 506 break; 507 else if (status == 0xC0000023L) //STATUS_BUFFER_TOO_SMALL 508 target = new UNICODE_STRING(target.MaximumLength); 509 else 510 return null; 511 } 512 513 return target.ToString(); 514 } 308 515 } 309 516 } -
trunk/eraser/Eraser.Util/PhysicalDriveInfo.cs
r2174 r2180 127 127 get 128 128 { 129 //Get all registered DOS Device names. 130 string[] dosDevices = NativeMethods.QueryDosDevices(); 129 List<VolumeInfo> result = new List<VolumeInfo>(); 131 130 132 //Get a list of Win32 device names, and map it to DOS Devices. 133 ComLib.Collections.DictionaryMultiValue<string, string> devices = 134 new ComLib.Collections.DictionaryMultiValue<string, string>(); 135 foreach (string dosDevice in dosDevices) 131 //Check every partition index on this drive. 132 for (int i = 1; ; ++i) 136 133 { 137 string win32Device = NativeMethods.QueryDosDevice(dosDevice); 138 if (win32Device != null) 139 devices.Add(win32Device, dosDevice); 140 } 134 string path = string.Format(CultureInfo.InvariantCulture, 135 "\\Device\\Harddisk{0}\\Partition{1}", Index, i); 136 using (SafeFileHandle handle = OpenWin32Device(path)) 137 { 138 if (handle.IsInvalid) 139 break; 140 } 141 141 142 List<VolumeInfo> result = new List<VolumeInfo>(); 143 foreach (VolumeInfo info in VolumeInfo.Volumes) 144 { 145 if (info.VolumeId.Substring(0, 4) == "\\\\?\\") 142 //This partition index is valid. Check which VolumeInfo this maps to. 143 foreach (VolumeInfo info in VolumeInfo.Volumes) 146 144 { 147 string win32Device = NativeMethods.QueryDosDevice( 148 info.VolumeId.Substring(4, info.VolumeId.Length - 5)); 149 foreach (string dosDevice in devices.Get(win32Device)) 145 //Only check local drives 146 if (info.VolumeId.Substring(0, 4) == "\\\\?\\") 150 147 { 151 Match match = HarddiskPartitionRegex.Match(dosDevice); 152 if (!match.Success) 153 continue; 154 155 //Check the HardDisk ID: if it is the same as our index, it is our partition. 156 if (Convert.ToInt32(match.Groups[1].Value) == Index) 148 //Check whether the DOS Device maps to the target of the symbolic link 149 if (NativeMethods.NtQuerySymbolicLink(path) == 150 NativeMethods.QueryDosDevice(info.VolumeId.Substring( 151 4, info.VolumeId.Length - 5))) 157 152 { 158 int partition = Convert.ToInt32(match.Groups[2].Value) - 1; 159 while (partition >= result.Count) 160 result.Add(null); 161 162 result[partition] = info; 153 //Yes, this volume belongs to this disk 154 result.Add(info); 155 break; 163 156 } 164 157 }
Note: See TracChangeset
for help on using the changeset viewer.
