Changeset 404 for branches/eraser6/Util/Drive.cs
- Timestamp:
- 9/27/2008 4:55:32 AM (5 years ago)
- File:
-
- 1 edited
-
branches/eraser6/Util/Drive.cs (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/eraser6/Util/Drive.cs
r403 r404 36 36 /// Constructor. 37 37 /// </summary> 38 /// <param name="volumeID">The ID of the volume .</param>38 /// <param name="volumeID">The ID of the volume, in the form "\\?\Volume{GUID}\"</param> 39 39 public Volume(string volumeID) 40 40 { … … 58 58 pathNamesBuffer = Marshal.AllocHGlobal((int)(currentBufferSize * sizeof(char))); 59 59 } 60 else 61 throw new Win32Exception(Marshal.GetLastWin32Error(), 62 "Eraser.Util.Volume.Volume"); 60 63 } 61 64 62 pathNames = Marshal.PtrToString Auto(pathNamesBuffer, (int)returnLength);65 pathNames = Marshal.PtrToStringUni(pathNamesBuffer, (int)returnLength); 63 66 } 64 67 finally … … 83 86 } 84 87 } 88 89 //Fill up the remaining members of the structure: file system, label, etc. 90 IntPtr volumeName = Marshal.AllocHGlobal(MaxPath * sizeof(char)), 91 fileSystemName = Marshal.AllocHGlobal(MaxPath * sizeof(char)); 92 try 93 { 94 uint serialNumber, maxComponentLength, filesystemFlags; 95 if (!GetVolumeInformation(volumeID, volumeName, MaxPath, out serialNumber, 96 out maxComponentLength, out filesystemFlags, fileSystemName, MaxPath)) 97 { 98 if (Marshal.GetLastWin32Error() != 21 /*ERROR_NOT_READY*/) 99 throw new Win32Exception(Marshal.GetLastWin32Error(), "Eraser.Util.Volume.Volume"); 100 } 101 else 102 { 103 //OK, the volume information's queried, store what we know. 104 driveFormat = Marshal.PtrToStringUni(fileSystemName); 105 volumeLabel = Marshal.PtrToStringUni(volumeName); 106 isReady = true; 107 } 108 } 109 finally 110 { 111 Marshal.FreeHGlobal(volumeName); 112 Marshal.FreeHGlobal(fileSystemName); 113 } 85 114 } 86 115 … … 93 122 { 94 123 List<Volume> result = new List<Volume>(); 95 IntPtr nextVolume = Marshal.AllocHGlobal( MaxPath * sizeof(char));124 IntPtr nextVolume = Marshal.AllocHGlobal(LongPath * sizeof(char)); 96 125 try 97 126 { 98 SafeHandle handle = FindFirstVolume(nextVolume, MaxPath);127 SafeHandle handle = FindFirstVolume(nextVolume, LongPath); 99 128 if (handle.IsInvalid) 100 129 return result; … … 102 131 //Iterate over the volume mountpoints 103 132 do 104 result.Add(new Volume(Marshal.PtrToString Auto(nextVolume)));105 while (FindNextVolume(handle, nextVolume, MaxPath));133 result.Add(new Volume(Marshal.PtrToStringUni(nextVolume))); 134 while (FindNextVolume(handle, nextVolume, LongPath)); 106 135 107 136 //Close the handle … … 118 147 119 148 /// <summary> 149 /// Creates a Volume object from its mountpoint. 150 /// </summary> 151 /// <param name="mountpoint">The path to the mountpoint.</param> 152 /// <returns>The volume object if such a volume exists, or an exception 153 /// is thrown.</returns> 154 public static Volume FromMountpoint(string mountpoint) 155 { 156 DirectoryInfo mountpointDir = new DirectoryInfo(mountpoint); 157 IntPtr volumeID = Marshal.AllocHGlobal(50 * sizeof(char)); 158 try 159 { 160 do 161 { 162 string currentDir = mountpointDir.FullName; 163 if (currentDir.Length > 0 && currentDir[currentDir.Length - 1] != '\\') 164 currentDir += '\\'; 165 if (GetVolumeNameForVolumeMountPoint(currentDir, volumeID, 50)) 166 return new Volume(Marshal.PtrToStringUni(volumeID)); 167 else if (Marshal.GetLastWin32Error() != 4390 /*ERROR_NOT_A_REPARSE_POINT*/) 168 throw new Win32Exception(Marshal.GetLastWin32Error()); 169 mountpointDir = mountpointDir.Parent; 170 } 171 while (mountpointDir != null); 172 173 throw new Win32Exception(4390 /*ERROR_NOT_A_REPARSE_POINT*/); 174 } 175 finally 176 { 177 Marshal.FreeHGlobal(volumeID); 178 } 179 } 180 181 /// <summary> 182 /// Returns the volume identifier as would be returned from FindFirstVolume. 183 /// </summary> 184 public string VolumeID 185 { 186 get { return volumeID; } 187 } 188 private string volumeID; 189 190 /// <summary> 191 /// Gets or sets the volume label of a drive. 192 /// </summary> 193 public string VolumeLabel 194 { 195 get { return VolumeLabel; } 196 set { throw new NotImplementedException(); } 197 } 198 private string volumeLabel; 199 200 /// <summary> 201 /// Gets the name of the file system, such as NTFS or FAT32. 202 /// </summary> 203 public string VolumeFormat 204 { 205 get 206 { 207 return driveFormat; 208 } 209 } 210 private string driveFormat; 211 212 /// <summary> 213 /// Gets the drive type; returns one of the System.IO.DriveType values. 214 /// </summary> 215 public DriveType VolumeType 216 { 217 get 218 { 219 return (DriveType)GetDriveType(VolumeID); 220 } 221 } 222 223 /// <summary> 120 224 /// Determines the cluster size of the current volume. 121 225 /// </summary> 122 /// <returns>The size of one cluster, in bytes.</returns> 123 public uint GetClusterSize() 124 { 125 UInt32 clusterSize, sectorSize, freeClusters, totalClusters; 126 if (GetDiskFreeSpace(mountPoints[0], out clusterSize, out sectorSize, 127 out freeClusters, out totalClusters)) 128 return clusterSize * sectorSize; 129 130 throw new Win32Exception(Marshal.GetLastWin32Error(), 131 "Eraser.Util.Drive.GetClusterSize"); 226 public int ClusterSize 227 { 228 get 229 { 230 uint clusterSize, sectorSize, freeClusters, totalClusters; 231 if (GetDiskFreeSpace(volumeID, out clusterSize, out sectorSize, 232 out freeClusters, out totalClusters)) 233 return (int)(clusterSize * sectorSize); 234 235 throw new Win32Exception(Marshal.GetLastWin32Error(), 236 "Eraser.Util.Drive.GetClusterSize"); 237 } 132 238 } 133 239 … … 135 241 /// Checks if the current user has disk quotas on the current volume. 136 242 /// </summary> 137 /// <returns>True if quotas are in effect.</returns> 138 public bool HasQuota() 139 { 140 UInt64 freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes; 141 if (GetDiskFreeSpaceEx(VolumeID, out freeBytesAvailable, out totalNumberOfBytes, 142 out totalNumberOfFreeBytes)) 143 return totalNumberOfFreeBytes != freeBytesAvailable; 144 145 throw new Win32Exception(Marshal.GetLastWin32Error(), 146 "Eraser.Util.Drive.HasQuota"); 243 public bool HasQuota 244 { 245 get 246 { 247 ulong freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes; 248 if (GetDiskFreeSpaceEx(volumeID, out freeBytesAvailable, out totalNumberOfBytes, 249 out totalNumberOfFreeBytes)) 250 return totalNumberOfFreeBytes != freeBytesAvailable; 251 252 throw new Win32Exception(Marshal.GetLastWin32Error(), 253 "Eraser.Util.Drive.HasQuota"); 254 } 255 } 256 257 /// <summary> 258 /// Gets a value indicating whether a drive is ready. 259 /// </summary> 260 public bool IsReady 261 { 262 get { return isReady; } 263 } 264 private bool isReady = false; 265 266 /// <summary> 267 /// Gets the total amount of free space available on a drive. 268 /// </summary> 269 public long TotalFreeSpace 270 { 271 get 272 { 273 ulong result, dummy; 274 if (GetDiskFreeSpaceEx(volumeID, out dummy, out dummy, out result)) 275 return (long)result; 276 277 throw new Win32Exception(Marshal.GetLastWin32Error(), 278 "Eraser.Util.Drive.TotalFreeSpace"); 279 } 280 } 281 282 /// <summary> 283 /// Gets the total size of storage space on a drive. 284 /// </summary> 285 public long TotalSize 286 { 287 get 288 { 289 UInt64 result, dummy; 290 if (GetDiskFreeSpaceEx(volumeID, out dummy, out result, out dummy)) 291 return (long)result; 292 293 throw new Win32Exception(Marshal.GetLastWin32Error(), 294 "Eraser.Util.Drive.TotalSize"); 295 } 296 } 297 298 /// <summary> 299 /// Indicates the amount of available free space on a drive. 300 /// </summary> 301 public long AvailableFreeSpace 302 { 303 get 304 { 305 UInt64 result, dummy; 306 if (GetDiskFreeSpaceEx(volumeID, out result, out dummy, out dummy)) 307 return (long)result; 308 309 throw new Win32Exception(Marshal.GetLastWin32Error(), 310 "Eraser.Util.Drive.AvailableFreeSpace"); 311 } 147 312 } 148 313 … … 151 316 /// contains volume mountpoints. 152 317 /// </summary> 153 /// <returns>A list containing Volume objects, representing each of the 154 /// volumes at the mountpoints.</returns> 155 public List<Volume> GetMountpoints() 156 { 157 List<Volume> result = new List<Volume>(); 158 IntPtr nextMountpoint = Marshal.AllocHGlobal(MaxPath * sizeof(char)); 159 try 160 { 161 SafeHandle handle = FindFirstVolumeMountPoint(VolumeID, 162 nextMountpoint, MaxPath); 163 if (handle.IsInvalid) 318 public List<Volume> MountedVolumes 319 { 320 get 321 { 322 List<Volume> result = new List<Volume>(); 323 IntPtr nextMountpoint = Marshal.AllocHGlobal(LongPath * sizeof(char)); 324 try 325 { 326 SafeHandle handle = FindFirstVolumeMountPoint(VolumeID, 327 nextMountpoint, LongPath); 328 if (handle.IsInvalid) 329 return result; 330 331 //Iterate over the volume mountpoints 332 while (FindNextVolumeMountPoint(handle, nextMountpoint, LongPath)) 333 result.Add(new Volume(Marshal.PtrToStringUni(nextMountpoint))); 334 335 //Close the handle 336 if (Marshal.GetLastWin32Error() == 18 /*ERROR_NO_MORE_FILES*/) 337 FindVolumeMountPointClose(handle); 338 164 339 return result; 165 166 //Iterate over the volume mountpoints 167 while (FindNextVolumeMountPoint(handle, nextMountpoint, MaxPath)) 168 result.Add(new Volume(Marshal.PtrToStringAuto(nextMountpoint))); 169 170 //Close the handle 171 if (Marshal.GetLastWin32Error() == 18 /*ERROR_NO_MORE_FILES*/) 172 FindVolumeMountPointClose(handle); 173 174 return result; 175 } 176 finally 177 { 178 Marshal.FreeHGlobal(nextMountpoint); 179 } 180 } 181 182 /// <summary> 183 /// Returns the volume identifier as would be returned from FindFirstVolume. 184 /// </summary> 185 public string VolumeID 186 { 187 get { return volumeID; } 188 } 189 private string volumeID; 340 } 341 finally 342 { 343 Marshal.FreeHGlobal(nextMountpoint); 344 } 345 } 346 } 190 347 191 348 /// <summary> … … 209 366 } 210 367 211 /// <summary>212 /// Gets the drive type; returns one of the System.IO.DriveType values.213 /// </summary>214 public DriveType VolumeType215 {216 get217 {218 return (DriveType)GetDriveType(VolumeID);219 }220 }221 222 internal const int MaxPath = 32768;223 224 368 #region Windows API Functions 369 internal const int MaxPath = 260; 370 internal const int LongPath = 32768; 371 372 /// <summary> 373 /// Retrieves information about the file system and volume associated with 374 /// the specified root directory. 375 /// 376 /// To specify a handle when retrieving this information, use the 377 /// GetVolumeInformationByHandleW function. 378 /// 379 /// To retrieve the current compression state of a file or directory, use 380 /// FSCTL_GET_COMPRESSION. 381 /// </summary> 382 /// <param name="lpRootPathName"> A pointer to a string that contains 383 /// the root directory of the volume to be described. 384 /// 385 /// If this parameter is NULL, the root of the current directory is used. 386 /// A trailing backslash is required. For example, you specify 387 /// \\MyServer\MyShare as "\\MyServer\MyShare\", or the C drive as "C:\".</param> 388 /// <param name="lpVolumeNameBuffer">A pointer to a buffer that receives 389 /// the name of a specified volume. The maximum buffer size is MAX_PATH+1.</param> 390 /// <param name="nVolumeNameSize">The length of a volume name buffer, in 391 /// TCHARs. The maximum buffer size is MAX_PATH+1. 392 /// 393 /// This parameter is ignored if the volume name buffer is not supplied.</param> 394 /// <param name="lpVolumeSerialNumber">A pointer to a variable that receives 395 /// the volume serial number. 396 /// 397 /// This parameter can be NULL if the serial number is not required. 398 /// 399 /// This function returns the volume serial number that the operating system 400 /// assigns when a hard disk is formatted. To programmatically obtain the 401 /// hard disk's serial number that the manufacturer assigns, use the 402 /// Windows Management Instrumentation (WMI) Win32_PhysicalMedia property 403 /// SerialNumber.</param> 404 /// <param name="lpMaximumComponentLength">A pointer to a variable that 405 /// receives the maximum length, in TCHARs, of a file name component that 406 /// a specified file system supports. 407 /// 408 /// A file name component is the portion of a file name between backslashes. 409 /// 410 /// The value that is stored in the variable that *lpMaximumComponentLength 411 /// points to is used to indicate that a specified file system supports 412 /// long names. For example, for a FAT file system that supports long names, 413 /// the function stores the value 255, rather than the previous 8.3 indicator. 414 /// Long names can also be supported on systems that use the NTFS file system.</param> 415 /// <param name="lpFileSystemFlags">A pointer to a variable that receives 416 /// flags associated with the specified file system. 417 /// 418 /// This parameter can be one or more of the FS_FILE* flags. However, 419 /// FS_FILE_COMPRESSION and FS_VOL_IS_COMPRESSED are mutually exclusive.</param> 420 /// <param name="lpFileSystemNameBuffer">A pointer to a buffer that receives 421 /// the name of the file system, for example, the FAT file system or the 422 /// NTFS file system. The maximum buffer size is MAX_PATH+1.</param> 423 /// <param name="nFileSystemNameSize">The length of the file system name 424 /// buffer, in TCHARs. The maximum buffer size is MAX_PATH+1. 425 /// 426 /// This parameter is ignored if the file system name buffer is not supplied.</param> 427 /// <returns>If all the requested information is retrieved, the return value 428 /// is nonzero. 429 /// 430 /// 431 /// If not all the requested information is retrieved, the return value is 432 /// zero (0). To get extended error information, call GetLastError.</returns> 433 [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "GetVolumeInformationW")] 434 [return: MarshalAs(UnmanagedType.Bool)] 435 internal static extern bool GetVolumeInformation( 436 [MarshalAs(UnmanagedType.LPWStr)] string lpRootPathName, 437 IntPtr lpVolumeNameBuffer, 438 uint nVolumeNameSize, 439 out uint lpVolumeSerialNumber, 440 out uint lpMaximumComponentLength, 441 out uint lpFileSystemFlags, 442 IntPtr lpFileSystemNameBuffer, 443 uint nFileSystemNameSize); 444 225 445 /// <summary> 226 446 /// Retrieves information about the specified disk, including the amount … … 256 476 /// <returns>If the function succeeds, the return value is true. To get 257 477 /// extended error information, call Marshal.GetLastWin32Error().</returns> 258 [DllImport("Kernel32.dll", SetLastError = true )]478 [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "GetDiskFreeSpaceW")] 259 479 [return: MarshalAs(UnmanagedType.Bool)] 260 480 internal static extern bool GetDiskFreeSpace( 261 [MarshalAs(UnmanagedType.LP Str)] string lpRootPathName,481 [MarshalAs(UnmanagedType.LPWStr)] string lpRootPathName, 262 482 out UInt32 lpSectorsPerCluster, out UInt32 lpBytesPerSector, 263 483 out UInt32 lpNumberOfFreeClusters, out UInt32 lpTotalNumberOfClusters); 264 484 265 [DllImport("Kernel32.dll", SetLastError = true)] 485 /// <summary> 486 /// Retrieves information about the amount of space that is available on 487 /// a disk volume, which is the total amount of space, the total amount 488 /// of free space, and the total amount of free space available to the 489 /// user that is associated with the calling thread. 490 /// </summary> 491 /// <param name="lpDirectoryName">A directory on the disk. 492 /// 493 /// If this parameter is NULL, the function uses the root of the current 494 /// disk. 495 /// 496 /// If this parameter is a UNC name, it must include a trailing backslash, 497 /// for example, "\\MyServer\MyShare\". 498 /// 499 /// This parameter does not have to specify the root directory on a disk. 500 /// The function accepts any directory on a disk. 501 /// 502 /// The calling application must have FILE_LIST_DIRECTORY access rights 503 /// for this directory.</param> 504 /// <param name="lpFreeBytesAvailable">A pointer to a variable that receives 505 /// the total number of free bytes on a disk that are available to the 506 /// user who is associated with the calling thread. 507 /// 508 /// This parameter can be NULL. 509 /// 510 /// If per-user quotas are being used, this value may be less than the 511 /// total number of free bytes on a disk.</param> 512 /// <param name="lpTotalNumberOfBytes">A pointer to a variable that receives 513 /// the total number of bytes on a disk that are available to the user who 514 /// is associated with the calling thread. 515 /// 516 /// This parameter can be NULL. 517 /// 518 /// If per-user quotas are being used, this value may be less than the 519 /// total number of bytes on a disk. 520 /// 521 /// To determine the total number of bytes on a disk or volume, use 522 /// IOCTL_DISK_GET_LENGTH_INFO.</param> 523 /// <param name="lpTotalNumberOfFreeBytes">A pointer to a variable that 524 /// receives the total number of free bytes on a disk. 525 /// 526 /// This parameter can be NULL.</param> 527 /// <returns>If the function succeeds, the return value is nonzero. 528 /// 529 /// If the function fails, the return value is zero (0). To get extended 530 /// error information, call GetLastError.</returns> 531 [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "GetDiskFreeSpaceExW")] 266 532 [return: MarshalAs(UnmanagedType.Bool)] 267 533 internal static extern bool GetDiskFreeSpaceEx( 268 [MarshalAs(UnmanagedType.LP Str)] string lpDirectoryName,534 [MarshalAs(UnmanagedType.LPWStr)] string lpDirectoryName, 269 535 out UInt64 lpFreeBytesAvailable, 270 536 out UInt64 lpTotalNumberOfBytes, … … 389 655 [return: MarshalAs(UnmanagedType.Bool)] 390 656 internal static extern bool FindVolumeMountPointClose(SafeHandle hFindVolumeMountPoint); 657 658 /// <summary> 659 /// Retrieves the unique volume name for the specified volume mount point or root directory. 660 /// </summary> 661 /// <param name="lpszVolumeMountPoint">The path of a volume mount point (with a trailing 662 /// backslash, "\") or a drive letter indicating a root directory (in the 663 /// form "D:\").</param> 664 /// <param name="lpszVolumeName">A pointer to a string that receives the 665 /// volume name. This name is a unique volume name of the form 666 /// "\\?\Volume{GUID}\" where GUID is the GUID that identifies the volume.</param> 667 /// <param name="cchBufferLength">The length of the output buffer, in TCHARs. 668 /// A reasonable size for the buffer to accommodate the largest possible 669 /// volume name is 50 characters.</param> 670 /// <returns>If the function succeeds, the return value is nonzero. 671 /// 672 /// If the function fails, the return value is zero. To get extended 673 /// error information, call GetLastError.</returns> 674 [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "GetVolumeNameForVolumeMountPointW")] 675 [return: MarshalAs(UnmanagedType.Bool)] 676 internal static extern bool GetVolumeNameForVolumeMountPoint( 677 [MarshalAs(UnmanagedType.LPWStr)] string lpszVolumeMountPoint, 678 IntPtr lpszVolumeName, 679 uint cchBufferLength); 391 680 392 681 /// <summary>
Note: See TracChangeset
for help on using the changeset viewer.
