The Labs \ Source Viewer \ SSCLI \ System.IO \ DriveType

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  DriveInfo
  18. **
  19. **
  20. ** Purpose: Exposes routines for exploring a drive.
  21. **
  22. **
  23. ===========================================================*/
  24. using System;
  25. using System.Text;
  26. using System.Runtime.InteropServices;
  27. using Microsoft.Win32;
  28. using System.Security.Permissions;
  29. using System.Runtime.Serialization;
  30. using System.Runtime.Versioning;
  31. namespace System.IO
  32. {
  33.     // Matches Win32's DRIVE_XXX #defines from winbase.h
  34.     [Serializable()]
  35.     [System.Runtime.InteropServices.ComVisible(true)]
  36.     public enum DriveType
  37.     {
  38.         Unknown = 0,
  39.         NoRootDirectory = 1,
  40.         Removable = 2,
  41.         Fixed = 3,
  42.         Network = 4,
  43.         CDRom = 5,
  44.         Ram = 6
  45.     }
  46.    
  47.     [Serializable()]
  48.     [ComVisible(true)]
  49.     public sealed class DriveInfo : ISerializable
  50.     {
  51.         private string _name;
  52.        
  53.         private const string NameField = "_name";
  54.         // For serialization
  55.         public DriveInfo(string driveName)
  56.         {
  57.             if (driveName == null)
  58.                 throw new ArgumentNullException("driveName");
  59.             if (driveName.Length == 1)
  60.                 _name = driveName + ":\\";
  61.             else {
  62.                 // GetPathRoot does not check all invalid characters
  63.                 Path.CheckInvalidPathChars(driveName);
  64.                 _name = Path.GetPathRoot(driveName);
  65.                 // Disallow null or empty drive letters and UNC paths
  66.                 if (_name == null || _name.Length == 0 || _name.StartsWith("\\\\", StringComparison.Ordinal))
  67.                     throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDriveLetterOrRootDir"));
  68.             }
  69.             if (_name.Length == 2 && _name[1] == ':') {
  70.                 _name = _name + "\\";
  71.             }
  72.            
  73.             // Now verify that the drive letter could be a real drive name.
  74.             // On Windows this means it's between A and Z, ignoring case.
  75.             // On a Unix platform, perhaps this should be a device name with
  76.             // a partition like /dev/hdc0, or possibly a mount point.
  77.             char letter = driveName[0];
  78.             if (!((letter >= 'A' && letter <= 'Z') || (letter >= 'a' && letter <= 'z')))
  79.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDriveLetterOrRootDir"));
  80.            
  81.             // Now do a security check.
  82.             string demandPath = _name + '.';
  83.             new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPath).Demand();
  84.         }
  85.        
  86.         private DriveInfo(SerializationInfo info, StreamingContext context)
  87.         {
  88.             // Need to add in a security check here once it has been spec'ed.
  89.             _name = (string)info.GetValue(NameField, typeof(string));
  90.            
  91.             // Now do a security check.
  92.             string demandPath = _name + '.';
  93.             new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPath).Demand();
  94.         }
  95.        
  96.         public string Name {
  97.             get { return _name; }
  98.         }
  99.        
  100.         public DriveType DriveType {
  101. // GetDriveType can't fail
  102.             get { return (DriveType)Win32Native.GetDriveType(Name); }
  103.         }
  104.        
  105.         public string DriveFormat {
  106.             [ResourceExposure(ResourceScope.None)]
  107.             [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  108.             get {
  109.                 const int volNameLen = 50;
  110.                 StringBuilder volumeName = new StringBuilder(volNameLen);
  111.                 const int fileSystemNameLen = 50;
  112.                 StringBuilder fileSystemName = new StringBuilder(fileSystemNameLen);
  113.                 int serialNumber;
  114.                 int maxFileNameLen;
  115.                 int fileSystemFlags;
  116.                
  117.                 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
  118.                 try {
  119.                     bool r = Win32Native.GetVolumeInformation(Name, volumeName, volNameLen, out serialNumber, out maxFileNameLen, out fileSystemFlags, fileSystemName, fileSystemNameLen);
  120.                     if (!r) {
  121.                         int errorCode = Marshal.GetLastWin32Error();
  122.                         // Win9x appears to return ERROR_INVALID_DATA when a
  123.                         // drive doesn't exist.
  124.                         if (errorCode == Win32Native.ERROR_INVALID_DATA)
  125.                             errorCode = Win32Native.ERROR_INVALID_DRIVE;
  126.                         __Error.WinIODriveError(Name, errorCode);
  127.                     }
  128.                 }
  129.                 finally {
  130.                     Win32Native.SetErrorMode(oldMode);
  131.                 }
  132.                 return fileSystemName.ToString();
  133.             }
  134.         }
  135.        
  136.         public bool IsReady {
  137.             [ResourceExposure(ResourceScope.None)]
  138.             [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  139.             get { return Directory.InternalExists(Name); }
  140.         }
  141.        
  142.         public long AvailableFreeSpace {
  143.             [ResourceExposure(ResourceScope.None)]
  144.             [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  145.             get {
  146.                 long userBytes;
  147.                 long totalBytes;
  148.                 long freeBytes;
  149.                 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
  150.                 try {
  151.                     bool r = Win32Native.GetDiskFreeSpaceEx(Name, out userBytes, out totalBytes, out freeBytes);
  152.                     if (!r)
  153.                         __Error.WinIODriveError(Name);
  154.                 }
  155.                 finally {
  156.                     Win32Native.SetErrorMode(oldMode);
  157.                 }
  158.                 return userBytes;
  159.             }
  160.         }
  161.        
  162.         public long TotalFreeSpace {
  163.             [ResourceExposure(ResourceScope.None)]
  164.             [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  165.             get {
  166.                 long userBytes;
  167.                 long totalBytes;
  168.                 long freeBytes;
  169.                 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
  170.                 try {
  171.                     bool r = Win32Native.GetDiskFreeSpaceEx(Name, out userBytes, out totalBytes, out freeBytes);
  172.                     if (!r)
  173.                         __Error.WinIODriveError(Name);
  174.                 }
  175.                 finally {
  176.                     Win32Native.SetErrorMode(oldMode);
  177.                 }
  178.                 return freeBytes;
  179.             }
  180.         }
  181.        
  182.         public long TotalSize {
  183.             [ResourceExposure(ResourceScope.None)]
  184.             [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  185.             get {
  186.                 // Don't cache this, to handle variable sized floppy drives
  187.                 // or other various removable media drives.
  188.                 long userBytes;
  189.                 long totalBytes;
  190.                 long freeBytes;
  191.                 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
  192.                 try {
  193.                     bool r = Win32Native.GetDiskFreeSpaceEx(Name, out userBytes, out totalBytes, out freeBytes);
  194.                     if (!r)
  195.                         __Error.WinIODriveError(Name);
  196.                 }
  197.                 finally {
  198.                     Win32Native.SetErrorMode(oldMode);
  199.                 }
  200.                 return totalBytes;
  201.             }
  202.         }
  203.        
  204.         [ResourceExposure(ResourceScope.Machine)]
  205.         [ResourceConsumption(ResourceScope.Machine)]
  206.         public static DriveInfo[] GetDrives()
  207.         {
  208.             // Directory.GetLogicalDrives demands unmanaged code permission
  209.             string[] drives = Directory.GetLogicalDrives();
  210.             DriveInfo[] di = new DriveInfo[drives.Length];
  211.             for (int i = 0; i < drives.Length; i++)
  212.                 di[i] = new DriveInfo(drives[i]);
  213.             return di;
  214.         }
  215.        
  216.         public DirectoryInfo RootDirectory {
  217.             [ResourceExposure(ResourceScope.Machine)]
  218.             [ResourceConsumption(ResourceScope.Machine)]
  219.             get { return new DirectoryInfo(Name); }
  220.         }
  221.        
  222.         // Null is a valid volume label.
  223.         public string VolumeLabel {
  224.             [ResourceExposure(ResourceScope.None)]
  225.             [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  226.             get {
  227.                 // NTFS uses a limit of 32 characters for the volume label,
  228.                 // as of Windows Server 2003.
  229.                 const int volNameLen = 50;
  230.                 StringBuilder volumeName = new StringBuilder(volNameLen);
  231.                 const int fileSystemNameLen = 50;
  232.                 StringBuilder fileSystemName = new StringBuilder(fileSystemNameLen);
  233.                 int serialNumber;
  234.                 int maxFileNameLen;
  235.                 int fileSystemFlags;
  236.                
  237.                 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
  238.                 try {
  239.                     bool r = Win32Native.GetVolumeInformation(Name, volumeName, volNameLen, out serialNumber, out maxFileNameLen, out fileSystemFlags, fileSystemName, fileSystemNameLen);
  240.                     if (!r) {
  241.                         int errorCode = Marshal.GetLastWin32Error();
  242.                         // Win9x appears to return ERROR_INVALID_DATA when a
  243.                         // drive doesn't exist.
  244.                         if (errorCode == Win32Native.ERROR_INVALID_DATA)
  245.                             errorCode = Win32Native.ERROR_INVALID_DRIVE;
  246.                         __Error.WinIODriveError(Name, errorCode);
  247.                     }
  248.                 }
  249.                 finally {
  250.                     Win32Native.SetErrorMode(oldMode);
  251.                 }
  252.                 return volumeName.ToString();
  253.             }
  254.             [ResourceExposure(ResourceScope.None)]
  255.             [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  256.             set {
  257.                 string demandPath = _name + '.';
  258.                 new FileIOPermission(FileIOPermissionAccess.Write, demandPath).Demand();
  259.                
  260.                 int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
  261.                 try {
  262.                     bool r = Win32Native.SetVolumeLabel(Name, value);
  263.                     if (!r) {
  264.                         int errorCode = Marshal.GetLastWin32Error();
  265.                         // Provide better message
  266.                         if (errorCode == Win32Native.ERROR_ACCESS_DENIED)
  267.                             throw new UnauthorizedAccessException(Environment.GetResourceString("InvalidOperation_SetVolumeLabelFailed"));
  268.                         __Error.WinIODriveError(Name, errorCode);
  269.                     }
  270.                 }
  271.                 finally {
  272.                     Win32Native.SetErrorMode(oldMode);
  273.                 }
  274.             }
  275.         }
  276.        
  277.         public override string ToString()
  278.         {
  279.             return Name;
  280.         }
  281.        
  282.         /// <internalonly/>
  283.         // No need for LinkDemand of SerializationFormatter here as this is a interface private
  284.         // methodimpl and the linkdeamand specified on ISerializable will cover this.
  285.         void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
  286.         {
  287.             // No need for an additional security check - everything is public.
  288.             info.AddValue(NameField, _name, typeof(string));
  289.         }
  290.     }
  291. }

Developer Fusion