3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
10 ** <OWNER>Microsoft</OWNER>
13 ** Purpose: Exposes routines for exploring a drive.
16 ===========================================================*/
20 using System.Runtime.InteropServices;
21 using Microsoft.Win32;
22 using System.Security.Permissions;
23 using System.Runtime.Serialization;
24 using System.Runtime.Versioning;
25 using System.Diagnostics.Contracts;
29 // Matches Win32's DRIVE_XXX #defines from winbase.h
31 [System.Runtime.InteropServices.ComVisible(true)]
43 // Ideally we'll get a better security permission, but possibly
47 public sealed class DriveInfo : ISerializable
51 private const String NameField = "_name"; // For serialization
53 [System.Security.SecuritySafeCritical] // auto-generated
54 [ResourceExposure(ResourceScope.Machine)]
55 [ResourceConsumption(ResourceScope.Machine)]
56 public DriveInfo(String driveName)
58 if (driveName == null)
59 throw new ArgumentNullException("driveName");
60 Contract.EndContractBlock();
61 if (driveName.Length == 1)
62 _name = driveName + ":\\";
64 // GetPathRoot does not check all invalid characters
65 Path.CheckInvalidPathChars(driveName);
66 _name = Path.GetPathRoot(driveName);
67 // Disallow null or empty drive letters and UNC paths
68 if (_name == null || _name.Length == 0 || _name.StartsWith("\\\\", StringComparison.Ordinal))
69 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDriveLetterOrRootDir"));
71 // We want to normalize to have a trailing backslash so we don't have two equivalent forms and
72 // because some Win32 API don't work without it.
73 if (_name.Length == 2 && _name[1] == ':') {
77 // Now verify that the drive letter could be a real drive name.
78 // On Windows this means it's between A and Z, ignoring case.
79 // On a Unix platform, perhaps this should be a device name with
80 // a partition like /dev/hdc0, or possibly a mount point.
81 char letter = driveName[0];
82 if (!((letter >= 'A' && letter <= 'Z') || (letter >= 'a' && letter <= 'z')))
83 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDriveLetterOrRootDir"));
85 // Now do a security check.
86 String demandPath = _name + '.';
87 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPath).Demand();
90 [System.Security.SecurityCritical] // auto-generated
91 private DriveInfo(SerializationInfo info, StreamingContext context)
93 // Need to add in a security check here once it has been spec'ed.
94 _name = (String) info.GetValue(NameField, typeof(String));
96 // Now do a security check.
97 String demandPath = _name + '.';
98 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPath).Demand();
102 get { return _name; }
105 public DriveType DriveType {
106 [System.Security.SecuritySafeCritical] // auto-generated
108 // GetDriveType can't fail
109 return (DriveType) Win32Native.GetDriveType(Name);
113 public String DriveFormat {
114 [System.Security.SecuritySafeCritical] // auto-generated
115 [ResourceExposure(ResourceScope.None)]
116 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
118 const int volNameLen = 50;
119 StringBuilder volumeName = new StringBuilder(volNameLen);
120 const int fileSystemNameLen = 50;
121 StringBuilder fileSystemName = new StringBuilder(fileSystemNameLen);
122 int serialNumber, maxFileNameLen, fileSystemFlags;
124 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
126 bool r = Win32Native.GetVolumeInformation(Name, volumeName, volNameLen, out serialNumber, out maxFileNameLen, out fileSystemFlags, fileSystemName, fileSystemNameLen);
128 int errorCode = Marshal.GetLastWin32Error();
129 __Error.WinIODriveError(Name, errorCode);
133 Win32Native.SetErrorMode(oldMode);
135 return fileSystemName.ToString();
139 public bool IsReady {
140 [System.Security.SecuritySafeCritical] // auto-generated
141 [ResourceExposure(ResourceScope.None)]
142 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
144 return Directory.InternalExists(Name);
148 public long AvailableFreeSpace {
149 [System.Security.SecuritySafeCritical] // auto-generated
150 [ResourceExposure(ResourceScope.None)]
151 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
153 long userBytes, totalBytes, freeBytes;
154 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
156 bool r = Win32Native.GetDiskFreeSpaceEx(Name, out userBytes, out totalBytes, out freeBytes);
158 __Error.WinIODriveError(Name);
161 Win32Native.SetErrorMode(oldMode);
167 public long TotalFreeSpace {
168 [System.Security.SecuritySafeCritical] // auto-generated
169 [ResourceExposure(ResourceScope.None)]
170 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
172 long userBytes, totalBytes, freeBytes;
173 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
175 bool r = Win32Native.GetDiskFreeSpaceEx(Name, out userBytes, out totalBytes, out freeBytes);
177 __Error.WinIODriveError(Name);
180 Win32Native.SetErrorMode(oldMode);
186 public long TotalSize {
187 [System.Security.SecuritySafeCritical] // auto-generated
188 [ResourceExposure(ResourceScope.None)]
189 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
191 // Don't cache this, to handle variable sized floppy drives
192 // or other various removable media drives.
193 long userBytes, totalBytes, freeBytes;
194 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
196 bool r = Win32Native.GetDiskFreeSpaceEx(Name, out userBytes, out totalBytes, out freeBytes);
198 __Error.WinIODriveError(Name);
201 Win32Native.SetErrorMode(oldMode);
207 [ResourceExposure(ResourceScope.Machine)]
208 [ResourceConsumption(ResourceScope.Machine)]
209 public static DriveInfo[] GetDrives()
211 // Directory.GetLogicalDrives demands unmanaged code permission
212 String[] drives = Directory.GetLogicalDrives();
213 DriveInfo[] di = new DriveInfo[drives.Length];
214 for(int i=0; i<drives.Length; i++)
215 di[i] = new DriveInfo(drives[i]);
219 public DirectoryInfo RootDirectory {
220 [ResourceExposure(ResourceScope.Machine)]
221 [ResourceConsumption(ResourceScope.Machine)]
223 return new DirectoryInfo(Name);
227 // Null is a valid volume label.
228 public String VolumeLabel {
229 [System.Security.SecuritySafeCritical] // auto-generated
230 [ResourceExposure(ResourceScope.None)]
231 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
233 // NTFS uses a limit of 32 characters for the volume label,
234 // as of Windows Server 2003.
235 const int volNameLen = 50;
236 StringBuilder volumeName = new StringBuilder(volNameLen);
237 const int fileSystemNameLen = 50;
238 StringBuilder fileSystemName = new StringBuilder(fileSystemNameLen);
239 int serialNumber, maxFileNameLen, fileSystemFlags;
241 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
243 bool r = Win32Native.GetVolumeInformation(Name, volumeName, volNameLen, out serialNumber, out maxFileNameLen, out fileSystemFlags, fileSystemName, fileSystemNameLen);
245 int errorCode = Marshal.GetLastWin32Error();
246 // Win9x appears to return ERROR_INVALID_DATA when a
247 // drive doesn't exist.
248 if (errorCode == Win32Native.ERROR_INVALID_DATA)
249 errorCode = Win32Native.ERROR_INVALID_DRIVE;
250 __Error.WinIODriveError(Name, errorCode);
254 Win32Native.SetErrorMode(oldMode);
256 return volumeName.ToString();
258 [System.Security.SecuritySafeCritical] // auto-generated
259 [ResourceExposure(ResourceScope.None)]
260 [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
262 String demandPath = _name + '.';
263 new FileIOPermission(FileIOPermissionAccess.Write, demandPath).Demand();
265 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
267 bool r = Win32Native.SetVolumeLabel(Name, value);
269 int errorCode = Marshal.GetLastWin32Error();
270 // Provide better message
271 if (errorCode == Win32Native.ERROR_ACCESS_DENIED)
272 throw new UnauthorizedAccessException(Environment.GetResourceString("InvalidOperation_SetVolumeLabelFailed"));
273 __Error.WinIODriveError(Name, errorCode);
277 Win32Native.SetErrorMode(oldMode);
282 public override String ToString()
287 #if FEATURE_SERIALIZATION
289 [System.Security.SecurityCritical]
290 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
292 // No need for an additional security check - everything is public.
293 info.AddValue(NameField, _name, typeof(String));