DriveInfoInternal.Windows.cs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Diagnostics;
  5. using System.Text;
  6. namespace System.IO
  7. {
  8. /// <summary>Contains internal volume helpers that are shared between many projects.</summary>
  9. internal static partial class DriveInfoInternal
  10. {
  11. public static string[] GetLogicalDrives()
  12. {
  13. int drives = Interop.Kernel32.GetLogicalDrives();
  14. if (drives == 0)
  15. {
  16. throw Win32Marshal.GetExceptionForLastWin32Error();
  17. }
  18. // GetLogicalDrives returns a bitmask starting from
  19. // position 0 "A" indicating whether a drive is present.
  20. // Loop over each bit, creating a string for each one
  21. // that is set.
  22. uint d = (uint)drives;
  23. int count = 0;
  24. while (d != 0)
  25. {
  26. if (((int)d & 1) != 0) count++;
  27. d >>= 1;
  28. }
  29. string[] result = new string[count];
  30. Span<char> root = stackalloc char[] { 'A', ':', '\\' };
  31. d = (uint)drives;
  32. count = 0;
  33. while (d != 0)
  34. {
  35. if (((int)d & 1) != 0)
  36. {
  37. result[count++] = root.ToString();
  38. }
  39. d >>= 1;
  40. root[0]++;
  41. }
  42. return result;
  43. }
  44. public static string NormalizeDriveName(string driveName)
  45. {
  46. Debug.Assert(driveName != null);
  47. string name;
  48. if (driveName.Length == 1)
  49. {
  50. name = driveName + ":\\";
  51. }
  52. else
  53. {
  54. name = Path.GetPathRoot(driveName);
  55. // Disallow null or empty drive letters and UNC paths
  56. if (string.IsNullOrEmpty(name) || name.StartsWith("\\\\", StringComparison.Ordinal))
  57. {
  58. throw new ArgumentException(SR.Arg_MustBeDriveLetterOrRootDir, nameof(driveName));
  59. }
  60. }
  61. // We want to normalize to have a trailing backslash so we don't have two equivalent forms and
  62. // because some Win32 API don't work without it.
  63. if (name.Length == 2 && name[1] == ':')
  64. {
  65. name = name + "\\";
  66. }
  67. // Now verify that the drive letter could be a real drive name.
  68. // On Windows this means it's between A and Z, ignoring case.
  69. char letter = driveName[0];
  70. if (!((letter >= 'A' && letter <= 'Z') || (letter >= 'a' && letter <= 'z')))
  71. {
  72. throw new ArgumentException(SR.Arg_MustBeDriveLetterOrRootDir, nameof(driveName));
  73. }
  74. return name;
  75. }
  76. }
  77. }