Changeset 401
- Timestamp:
- 9/27/2008 3:25:45 AM (5 years ago)
- File:
-
- 1 edited
-
branches/eraser6/Util/Drive.cs (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/eraser6/Util/Drive.cs
r348 r401 27 27 using System.ComponentModel; 28 28 using System.IO; 29 using Microsoft.Win32.SafeHandles; 29 30 30 31 namespace Eraser.Util 31 32 { 32 public static class Drive33 public class Volume 33 34 { 34 35 /// <summary> 36 /// Constructor. 37 /// </summary> 38 /// <param name="volumeID">The ID of the volume.</param> 39 public Volume(string volumeID) 40 { 41 //Set the volume Id 42 this.volumeID = volumeID; 43 44 //Get the paths of the said volume 45 IntPtr pathNamesBuffer = IntPtr.Zero; 46 string pathNames = string.Empty; 47 try 48 { 49 uint currentBufferSize = MaxPath; 50 uint returnLength = 0; 51 pathNamesBuffer = Marshal.AllocHGlobal((int)(currentBufferSize * sizeof(char))); 52 while (!GetVolumePathNamesForVolumeName(volumeID, pathNamesBuffer, currentBufferSize, 53 out returnLength)) 54 { 55 if (Marshal.GetLastWin32Error() == 234/*ERROR_MORE_DATA*/) 56 { 57 currentBufferSize *= 2; 58 pathNamesBuffer = Marshal.AllocHGlobal((int)(currentBufferSize * sizeof(char))); 59 } 60 } 61 62 pathNames = Marshal.PtrToStringAuto(pathNamesBuffer, (int)returnLength); 63 } 64 finally 65 { 66 if (pathNamesBuffer != IntPtr.Zero) 67 Marshal.FreeHGlobal(pathNamesBuffer); 68 } 69 70 //OK, the marshalling is complete. Convert the pathNames string into a list 71 //of strings containing all of the volumes mountpoints; because the 72 //GetVolumePathNamesForVolumeName function returns a convoluted structure 73 //containing the path names. 74 for (int lastIndex = 0, i = 0; i != pathNames.Length; ++i) 75 { 76 if (pathNames[i] == '\0') 77 { 78 mountPoints.Add(pathNames.Substring(lastIndex, i - lastIndex)); 79 80 lastIndex = i + 1; 81 if (pathNames[lastIndex] == '\0') 82 break; 83 } 84 } 85 } 86 87 public static List<Volume> GetVolumes() 88 { 89 List<Volume> result = new List<Volume>(); 90 IntPtr nextVolume = Marshal.AllocHGlobal(MaxPath * sizeof(char)); 91 try 92 { 93 SafeHandle handle = FindFirstVolume(nextVolume, MaxPath); 94 if (handle.IsInvalid) 95 return result; 96 97 //Iterate over the volume mountpoints 98 do 99 result.Add(new Volume(Marshal.PtrToStringAuto(nextVolume))); 100 while (FindNextVolume(handle, nextVolume, MaxPath)); 101 102 //Close the handle 103 if (Marshal.GetLastWin32Error() == 18 /*ERROR_NO_MORE_FILES*/) 104 FindVolumeClose(handle); 105 106 return result; 107 } 108 finally 109 { 110 Marshal.FreeHGlobal(nextVolume); 111 } 112 } 113 114 /// <summary> 35 115 /// Determines the cluster size of the given volume. 36 116 /// </summary> 37 /// <param name="driveName">The path to the root of the drive, including38 /// the trailing \</param>39 117 /// <returns>The size of one cluster, in bytes.</returns> 40 public static uint GetClusterSize(string driveName)41 { 42 UInt32 clusterSize = 0, sectorSize, freeClusters, totalClusters;43 if (GetDiskFreeSpace( driveName, out clusterSize, out sectorSize,118 public uint GetClusterSize() 119 { 120 UInt32 clusterSize, sectorSize, freeClusters, totalClusters; 121 if (GetDiskFreeSpace(mountPoints[0], out clusterSize, out sectorSize, 44 122 out freeClusters, out totalClusters)) 45 123 return clusterSize * sectorSize; … … 52 130 /// Checks if the current user has disk quotas on the volume provided. 53 131 /// </summary> 54 /// <param name="driveName">The path to the root of the drive, including55 /// the trailing \</param>56 132 /// <returns>True if quotas are in effect.</returns> 57 public static bool HasQuota(string driveName) 58 { 59 DriveInfo info = new DriveInfo(driveName); 60 return info.TotalFreeSpace != info.AvailableFreeSpace; 61 } 62 133 public bool HasQuota() 134 { 135 UInt64 freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes; 136 if (GetDiskFreeSpaceEx(VolumeID, out freeBytesAvailable, out totalNumberOfBytes, 137 out totalNumberOfFreeBytes)) 138 return totalNumberOfFreeBytes != freeBytesAvailable; 139 140 throw new Win32Exception(Marshal.GetLastWin32Error(), 141 "Eraser.Util.Drive.HasQuota"); 142 } 143 144 /// <summary> 145 /// Retrieves all mountpoints in the drive, if the drive contains volume 146 /// mountpoints. 147 /// </summary> 148 /// <returns>A list containing Volume objects, representing each of the 149 /// volumes at the mountpoints.</returns> 150 public List<Volume> GetMountpoints() 151 { 152 List<Volume> result = new List<Volume>(); 153 IntPtr nextMountpoint = Marshal.AllocHGlobal(MaxPath * sizeof(char)); 154 try 155 { 156 SafeHandle handle = FindFirstVolumeMountPoint(VolumeID, 157 nextMountpoint, MaxPath); 158 if (handle.IsInvalid) 159 return result; 160 161 //Iterate over the volume mountpoints 162 while (FindNextVolumeMountPoint(handle, nextMountpoint, MaxPath)) 163 result.Add(new Volume(Marshal.PtrToStringAuto(nextMountpoint))); 164 165 //Close the handle 166 if (Marshal.GetLastWin32Error() == 18 /*ERROR_NO_MORE_FILES*/) 167 FindVolumeMountPointClose(handle); 168 169 return result; 170 } 171 finally 172 { 173 Marshal.FreeHGlobal(nextMountpoint); 174 } 175 } 176 177 /// <summary> 178 /// Returns the volume identifier as would be returned from FindFirstVolume. 179 /// </summary> 180 public string VolumeID 181 { 182 get { return volumeID; } 183 } 184 private string volumeID; 185 186 /// <summary> 187 /// The various mountpoints to the root of the volume. This list contains 188 /// paths which may be a drive or a mountpoint. Every string includes the 189 /// trailing backslash. 190 /// </summary> 191 public List<string> MountPoints 192 { 193 get { return mountPoints; } 194 set { mountPoints = value; } 195 } 196 private List<string> mountPoints = new List<string>(); 197 198 /// <summary> 199 /// Gets whether the current volume is mounted at any place. 200 /// </summary> 201 public bool IsMounted 202 { 203 get { return mountPoints.Count != 0; } 204 } 205 206 /// <summary> 207 /// Gets the drive type; returns one of the System.IO.DriveType values. 208 /// </summary> 209 public DriveType VolumeType 210 { 211 get 212 { 213 return (DriveType)GetDriveType(mountPoints[0]); 214 } 215 } 216 217 internal const int MaxPath = 32768; 218 219 #region Windows API Functions 63 220 /// <summary> 64 221 /// Retrieves information about the specified disk, including the amount … … 97 254 [return: MarshalAs(UnmanagedType.Bool)] 98 255 internal static extern bool GetDiskFreeSpace( 99 [MarshalAs(UnmanagedType.LPStr)] string lpRootPathName,256 [MarshalAs(UnmanagedType.LPStr)] string lpRootPathName, 100 257 out UInt32 lpSectorsPerCluster, out UInt32 lpBytesPerSector, 101 258 out UInt32 lpNumberOfFreeClusters, out UInt32 lpTotalNumberOfClusters); 259 260 [DllImport("Kernel32.dll", SetLastError = true)] 261 [return: MarshalAs(UnmanagedType.Bool)] 262 internal static extern bool GetDiskFreeSpaceEx( 263 [MarshalAs(UnmanagedType.LPStr)] string lpDirectoryName, 264 out UInt64 lpFreeBytesAvailable, 265 out UInt64 lpTotalNumberOfBytes, 266 out UInt64 lpTotalNumberOfFreeBytes); 267 268 /// <summary> 269 /// Retrieves the name of a volume on a computer. FindFirstVolume is used 270 /// to begin scanning the volumes of a computer. 271 /// </summary> 272 /// <param name="lpszVolumeName">A pointer to a buffer that receives a 273 /// null-terminated string that specifies the unique volume name of the 274 /// first volume found.</param> 275 /// <param name="cchBufferLength">The length of the buffer to receive the 276 /// name, in TCHARs.</param> 277 /// <returns>If the function succeeds, the return value is a search handle 278 /// used in a subsequent call to the FindNextVolume and FindVolumeClose 279 /// functions. 280 /// 281 /// If the function fails to find any volumes, the return value is the 282 /// INVALID_HANDLE_VALUE error code. To get extended error information, 283 /// call GetLastError.</returns> 284 [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "FindFirstVolumeW")] 285 internal static extern SafeFileHandle FindFirstVolume( 286 IntPtr lpszVolumeName, 287 uint cchBufferLength); 288 289 /// <summary> 290 /// Continues a volume search started by a call to the FindFirstVolume 291 /// function. FindNextVolume finds one volume per call. 292 /// </summary> 293 /// <param name="hFindVolume">The volume search handle returned by a previous 294 /// call to the FindFirstVolume function.</param> 295 /// <param name="lpszVolumeName">A pointer to a string that receives the 296 /// unique volume name found.</param> 297 /// <param name="cchBufferLength">The length of the buffer that receives 298 /// the name, in TCHARs.</param> 299 /// <returns>If the function succeeds, the return value is nonzero. 300 /// 301 /// If the function fails, the return value is zero. To get extended error 302 /// information, call GetLastError. If no matching files can be found, the 303 /// GetLastError function returns the ERROR_NO_MORE_FILES error code. In 304 /// that case, close the search with the FindVolumeClose function.</returns> 305 [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "FindNextVolumeW")] 306 [return: MarshalAs(UnmanagedType.Bool)] 307 internal static extern bool FindNextVolume(SafeHandle hFindVolume, 308 IntPtr lpszVolumeName, uint cchBufferLength); 309 310 /// <summary> 311 /// Closes the specified volume search handle. The FindFirstVolume and 312 /// FindNextVolume functions use this search handle to locate volumes. 313 /// </summary> 314 /// <param name="hFindVolume">The volume search handle to be closed. This 315 /// handle must have been previously opened by the FindFirstVolume function.</param> 316 /// <returns>If the function succeeds, the return value is nonzero. 317 /// 318 /// If the function fails, the return value is zero. To get extended error 319 /// information, call GetLastError.</returns> 320 [DllImport("Kernel32.dll", SetLastError = true)] 321 [return: MarshalAs(UnmanagedType.Bool)] 322 internal static extern bool FindVolumeClose(SafeHandle hFindVolume); 323 324 /// <summary> 325 /// Retrieves the name of a volume mount point on the specified volume. 326 /// FindFirstVolumeMountPoint is used to begin scanning the volume mount 327 /// points on a volume. 328 /// </summary> 329 /// <param name="lpszRootPathName">The unique volume name of the volume 330 /// to scan for volume mount points. A trailing backslash is required.</param> 331 /// <param name="lpszVolumeMountPoint">A pointer to a buffer that receives 332 /// the name of the first volume mount point found.</param> 333 /// <param name="cchBufferLength">The length of the buffer that receives 334 /// the volume mount point name, in TCHARs.</param> 335 /// <returns>If the function succeeds, the return value is a search handle 336 /// used in a subsequent call to the FindNextVolumeMountPoint and 337 /// FindVolumeMountPointClose functions. 338 /// 339 /// If the function fails to find a volume mount point on the volume, the 340 /// return value is the INVALID_HANDLE_VALUE error code. To get extended 341 /// error information, call GetLastError.</returns> 342 [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "FindFirstVolumeMountPointW")] 343 internal static extern SafeFileHandle FindFirstVolumeMountPoint( 344 [MarshalAs(UnmanagedType.LPTStr)] string lpszRootPathName, 345 IntPtr lpszVolumeMountPoint, 346 uint cchBufferLength); 347 348 /// <summary> 349 /// Continues a volume mount point search started by a call to the 350 /// FindFirstVolumeMountPoint function. FindNextVolumeMountPoint finds one 351 /// volume mount point per call. 352 /// </summary> 353 /// <param name="hFindVolumeMountPoint">A mount-point search handle returned 354 /// by a previous call to the FindFirstVolumeMountPoint function.</param> 355 /// <param name="lpszVolumeMountPoint">A pointer to a buffer that receives 356 /// the name of the volume mount point found.</param> 357 /// <param name="cchBufferLength">The length of the buffer that receives 358 /// the names, in TCHARs.</param> 359 /// <returns>If the function succeeds, the return value is nonzero. 360 /// 361 /// If the function fails, the return value is zero. To get extended error 362 /// information, call GetLastError. If no matching files can be found, the 363 /// GetLastError function returns the ERROR_NO_MORE_FILES error code. In 364 /// that case, close the search with the FindVolumeMountPointClose function.</returns> 365 [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "FindNextVolumeMountPointW")] 366 [return: MarshalAs(UnmanagedType.Bool)] 367 internal static extern bool FindNextVolumeMountPoint(SafeHandle hFindVolumeMountPoint, 368 IntPtr lpszVolumeMountPoint, 369 uint cchBufferLength); 370 371 /// <summary> 372 /// Closes the specified mount-point search handle. The FindFirstVolumeMountPoint 373 /// and FindNextVolumeMountPoint functions use this search handle to locate 374 /// volume mount points on a specified volume. 375 /// </summary> 376 /// <param name="hFindVolumeMountPoint">The mount-point search handle to 377 /// be closed. This handle must have been previously opened by the 378 /// FindFirstVolumeMountPoint function.</param> 379 /// <returns>If the function succeeds, the return value is nonzero. 380 /// 381 /// If the function fails, the return value is zero. To get extended error 382 /// information, call GetLastError.</returns> 383 [DllImport("Kernel32.dll", SetLastError = true)] 384 [return: MarshalAs(UnmanagedType.Bool)] 385 internal static extern bool FindVolumeMountPointClose(SafeHandle hFindVolumeMountPoint); 386 387 /// <summary> 388 /// Retrieves a list of path names for the specified volume name. 389 /// </summary> 390 /// <param name="lpszVolumeName">The volume name.</param> 391 /// <param name="lpszVolumePathNames">A pointer to a buffer that receives 392 /// the list of volume path names. The list is an array of null-terminated 393 /// strings terminated by an additional NULL character. If the buffer is 394 /// not large enough to hold the complete list, the buffer holds as much 395 /// of the list as possible.</param> 396 /// <param name="cchBufferLength">The length of the lpszVolumePathNames 397 /// buffer, in TCHARs.</param> 398 /// <param name="lpcchReturnLength">If the call is successful, this parameter 399 /// is the number of TCHARs copied to the lpszVolumePathNames buffer. Otherwise, 400 /// this parameter is the size of the buffer required to hold the complete 401 /// list, in TCHARs.</param> 402 /// <returns></returns> 403 [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "GetVolumePathNamesForVolumeNameW")] 404 internal static extern bool GetVolumePathNamesForVolumeName( 405 [MarshalAs(UnmanagedType.LPTStr)] string lpszVolumeName, 406 IntPtr lpszVolumePathNames, 407 uint cchBufferLength, 408 out uint lpcchReturnLength); 409 410 /// <summary> 411 /// Determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk, 412 /// or network drive. 413 /// </summary> 414 /// <param name="lpRootPathName">The root directory for the drive. 415 /// 416 /// A trailing backslash is required. If this parameter is NULL, the function 417 /// uses the root of the current directory.</param> 418 /// <returns>The return value specifies the type of drive, which can be 419 /// one of the DriveInfo.DriveType values.</returns> 420 [DllImport("Kernel32.dll", SetLastError = true)] 421 internal static extern uint GetDriveType( 422 [MarshalAs(UnmanagedType.LPTStr)] string lpRootPathName); 423 #endregion 102 424 } 103 425 }
Note: See TracChangeset
for help on using the changeset viewer.
