diff options
Diffstat (limited to 'src/mscorlib/src/System/IO/DriveInfo.cs')
-rw-r--r-- | src/mscorlib/src/System/IO/DriveInfo.cs | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/IO/DriveInfo.cs b/src/mscorlib/src/System/IO/DriveInfo.cs new file mode 100644 index 0000000000..be75e8979d --- /dev/null +++ b/src/mscorlib/src/System/IO/DriveInfo.cs @@ -0,0 +1,281 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================ +** +** +** +** +** +** Purpose: Exposes routines for exploring a drive. +** +** +===========================================================*/ + +using System; +using System.Text; +using System.Runtime.InteropServices; +using Microsoft.Win32; +using System.Security.Permissions; +using System.Runtime.Serialization; +using System.Runtime.Versioning; +using System.Diagnostics.Contracts; + +namespace System.IO +{ + // Matches Win32's DRIVE_XXX #defines from winbase.h + [Serializable] +[System.Runtime.InteropServices.ComVisible(true)] + public enum DriveType + { + Unknown = 0, + NoRootDirectory = 1, + Removable = 2, + Fixed = 3, + Network = 4, + CDRom = 5, + Ram = 6 + } + + // Ideally we'll get a better security permission, but possibly + // not for Whidbey. +#if FEATURE_SERIALIZATION + [Serializable] +#endif + [ComVisible(true)] + public sealed class DriveInfo +#if FEATURE_SERIALIZATION + : ISerializable +#endif + { + private String _name; + + private const String NameField = "_name"; // For serialization + + [System.Security.SecuritySafeCritical] // auto-generated + public DriveInfo(String driveName) + { + if (driveName == null) + throw new ArgumentNullException("driveName"); + Contract.EndContractBlock(); + if (driveName.Length == 1) + _name = driveName + ":\\"; + else { + // GetPathRoot does not check all invalid characters + Path.CheckInvalidPathChars(driveName); + _name = Path.GetPathRoot(driveName); + // Disallow null or empty drive letters and UNC paths + if (_name == null || _name.Length == 0 || _name.StartsWith("\\\\", StringComparison.Ordinal)) + throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDriveLetterOrRootDir")); + } + // We want to normalize to have a trailing backslash so we don't have two equivalent forms and + // because some Win32 API don't work without it. + if (_name.Length == 2 && _name[1] == ':') { + _name = _name + "\\"; + } + + // Now verify that the drive letter could be a real drive name. + // On Windows this means it's between A and Z, ignoring case. + // On a Unix platform, perhaps this should be a device name with + // a partition like /dev/hdc0, or possibly a mount point. + char letter = driveName[0]; + if (!((letter >= 'A' && letter <= 'Z') || (letter >= 'a' && letter <= 'z'))) + throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDriveLetterOrRootDir")); + + // Now do a security check. + String demandPath = _name + '.'; + new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPath).Demand(); + } + + [System.Security.SecurityCritical] // auto-generated + private DriveInfo(SerializationInfo info, StreamingContext context) + { + // Need to add in a security check here once it has been spec'ed. + _name = (String) info.GetValue(NameField, typeof(String)); + + // Now do a security check. + String demandPath = _name + '.'; + new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPath).Demand(); + } + + public String Name { + get { return _name; } + } + + public DriveType DriveType { + [System.Security.SecuritySafeCritical] // auto-generated + get { + // GetDriveType can't fail + return (DriveType) Win32Native.GetDriveType(Name); + } + } + + public String DriveFormat { + [System.Security.SecuritySafeCritical] // auto-generated + get { + const int volNameLen = 50; + StringBuilder volumeName = new StringBuilder(volNameLen); + const int fileSystemNameLen = 50; + StringBuilder fileSystemName = new StringBuilder(fileSystemNameLen); + int serialNumber, maxFileNameLen, fileSystemFlags; + + int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS); + try { + bool r = Win32Native.GetVolumeInformation(Name, volumeName, volNameLen, out serialNumber, out maxFileNameLen, out fileSystemFlags, fileSystemName, fileSystemNameLen); + if (!r) { + int errorCode = Marshal.GetLastWin32Error(); + __Error.WinIODriveError(Name, errorCode); + } + } + finally { + Win32Native.SetErrorMode(oldMode); + } + return fileSystemName.ToString(); + } + } + + public bool IsReady { + [System.Security.SecuritySafeCritical] // auto-generated + get { + return Directory.InternalExists(Name); + } + } + + public long AvailableFreeSpace { + [System.Security.SecuritySafeCritical] // auto-generated + get { + long userBytes, totalBytes, freeBytes; + int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS); + try { + bool r = Win32Native.GetDiskFreeSpaceEx(Name, out userBytes, out totalBytes, out freeBytes); + if (!r) + __Error.WinIODriveError(Name); + } + finally { + Win32Native.SetErrorMode(oldMode); + } + return userBytes; + } + } + + public long TotalFreeSpace { + [System.Security.SecuritySafeCritical] // auto-generated + get { + long userBytes, totalBytes, freeBytes; + int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS); + try { + bool r = Win32Native.GetDiskFreeSpaceEx(Name, out userBytes, out totalBytes, out freeBytes); + if (!r) + __Error.WinIODriveError(Name); + } + finally { + Win32Native.SetErrorMode(oldMode); + } + return freeBytes; + } + } + + public long TotalSize { + [System.Security.SecuritySafeCritical] // auto-generated + get { + // Don't cache this, to handle variable sized floppy drives + // or other various removable media drives. + long userBytes, totalBytes, freeBytes; + int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS); + try { + bool r = Win32Native.GetDiskFreeSpaceEx(Name, out userBytes, out totalBytes, out freeBytes); + if (!r) + __Error.WinIODriveError(Name); + } + finally { + Win32Native.SetErrorMode(oldMode); + } + return totalBytes; + } + } + + public static DriveInfo[] GetDrives() + { + // Directory.GetLogicalDrives demands unmanaged code permission + String[] drives = Directory.GetLogicalDrives(); + DriveInfo[] di = new DriveInfo[drives.Length]; + for(int i=0; i<drives.Length; i++) + di[i] = new DriveInfo(drives[i]); + return di; + } + + public DirectoryInfo RootDirectory { + get { + return new DirectoryInfo(Name); + } + } + + // Null is a valid volume label. + public String VolumeLabel { + [System.Security.SecuritySafeCritical] // auto-generated + get { + // NTFS uses a limit of 32 characters for the volume label, + // as of Windows Server 2003. + const int volNameLen = 50; + StringBuilder volumeName = new StringBuilder(volNameLen); + const int fileSystemNameLen = 50; + StringBuilder fileSystemName = new StringBuilder(fileSystemNameLen); + int serialNumber, maxFileNameLen, fileSystemFlags; + + int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS); + try { + bool r = Win32Native.GetVolumeInformation(Name, volumeName, volNameLen, out serialNumber, out maxFileNameLen, out fileSystemFlags, fileSystemName, fileSystemNameLen); + if (!r) { + int errorCode = Marshal.GetLastWin32Error(); + // Win9x appears to return ERROR_INVALID_DATA when a + // drive doesn't exist. + if (errorCode == Win32Native.ERROR_INVALID_DATA) + errorCode = Win32Native.ERROR_INVALID_DRIVE; + __Error.WinIODriveError(Name, errorCode); + } + } + finally { + Win32Native.SetErrorMode(oldMode); + } + return volumeName.ToString(); + } + [System.Security.SecuritySafeCritical] // auto-generated + set { + String demandPath = _name + '.'; + new FileIOPermission(FileIOPermissionAccess.Write, demandPath).Demand(); + + int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS); + try { + bool r = Win32Native.SetVolumeLabel(Name, value); + if (!r) { + int errorCode = Marshal.GetLastWin32Error(); + // Provide better message + if (errorCode == Win32Native.ERROR_ACCESS_DENIED) + throw new UnauthorizedAccessException(Environment.GetResourceString("InvalidOperation_SetVolumeLabelFailed")); + __Error.WinIODriveError(Name, errorCode); + } + } + finally { + Win32Native.SetErrorMode(oldMode); + } + } + } + + public override String ToString() + { + return Name; + } + +#if FEATURE_SERIALIZATION + /// <internalonly/> + [System.Security.SecurityCritical] + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + // No need for an additional security check - everything is public. + info.AddValue(NameField, _name, typeof(String)); + } +#endif + + } +} |