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 5 using System; 6 using System.Collections.Generic; 7 using System.IO; 8 using System.Linq; 9 using System.Runtime.InteropServices; 10 using System.Text; 11 using System.Threading.Tasks; 12 using Xunit; 13 14 internal class IOServices 15 { GetReadyDrives()16 public static IEnumerable<string> GetReadyDrives() 17 { 18 foreach (string drive in GetLogicalDrives()) 19 { 20 if (IsReady(drive)) 21 yield return drive; 22 } 23 } 24 GetNotReadyDrive()25 public static string GetNotReadyDrive() 26 { 27 string[] drives = GetLogicalDrives(); 28 foreach (string drive in drives) 29 { 30 if (!IsReady(drive)) 31 return drive; 32 } 33 34 return null; 35 } 36 GetNonExistentDrive()37 public static string GetNonExistentDrive() 38 { 39 string[] availableDrives = GetLogicalDrives(); 40 41 for (char drive = 'A'; drive <= 'Z'; drive++) 42 { 43 if (!availableDrives.Contains(drive + @":\")) 44 return drive + @":\"; 45 } 46 47 return null; 48 } 49 GetNtfsDriveOtherThanCurrent()50 public static string GetNtfsDriveOtherThanCurrent() 51 { 52 return GetNtfsDriveOtherThan(GetCurrentDrive()); 53 } 54 GetNtfsDriveOtherThan(string drive)55 public static string GetNtfsDriveOtherThan(string drive) 56 { 57 foreach (string otherDrive in GetLogicalDrives()) 58 { 59 if (string.Equals(drive, otherDrive, StringComparison.OrdinalIgnoreCase)) 60 continue; 61 62 if (!IsFixed(otherDrive)) 63 continue; 64 65 if (!IsReady(otherDrive)) 66 continue; 67 68 if (IsDriveNTFS(otherDrive)) 69 return otherDrive; 70 } 71 72 return null; 73 } 74 GetNonNtfsDriveOtherThanCurrent()75 public static string GetNonNtfsDriveOtherThanCurrent() 76 { 77 return GetNonNtfsDriveOtherThan(GetCurrentDrive()); 78 } 79 GetNonNtfsDriveOtherThan(string drive)80 public static string GetNonNtfsDriveOtherThan(string drive) 81 { 82 foreach (string otherDrive in GetLogicalDrives()) 83 { 84 if (string.Equals(drive, otherDrive, StringComparison.OrdinalIgnoreCase)) 85 continue; 86 87 if (!IsReady(otherDrive)) 88 continue; 89 90 if (!IsDriveNTFS(otherDrive)) 91 return otherDrive; 92 } 93 94 return null; 95 } 96 GetPath(string rootPath, int characterCount, bool extended)97 public static string GetPath(string rootPath, int characterCount, bool extended) 98 { 99 if (extended) 100 rootPath = IOInputs.ExtendedPrefix + rootPath; 101 return GetPath(rootPath, characterCount); 102 } 103 GetPath(string rootPath, int characterCount)104 public static string GetPath(string rootPath, int characterCount) 105 { 106 rootPath = rootPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); 107 108 StringBuilder path = new StringBuilder(characterCount); 109 path.Append(rootPath); 110 111 while (path.Length < characterCount) 112 { 113 // Add directory seperator after each dir but not at the end of the path 114 path.Append(Path.DirectorySeparatorChar); 115 116 // Continue adding unique path segments until the character count is hit 117 int remainingChars = characterCount - path.Length; 118 string guid = Guid.NewGuid().ToString("N"); // No dashes 119 if (remainingChars < guid.Length) 120 { 121 path.Append(guid.Substring(0, remainingChars)); 122 } 123 else 124 { 125 // Long paths can be over 32K characters. Given that a guid is just 36 chars, this 126 // can lead to crazy 800+ recursive call depths. We'll create large segments to 127 // make tests more manageable. 128 129 path.Append(guid); 130 remainingChars = characterCount - path.Length; 131 path.Append('g', Math.Min(remainingChars, 200)); 132 } 133 134 if (path.Length + 1 == characterCount) 135 { 136 // If only one character is missing add a k! 137 path.Append('k'); 138 } 139 } 140 141 Assert.Equal(path.Length, characterCount); 142 143 return path.ToString(); 144 } 145 CreateDirectories(string rootPath, params string[] names)146 public static IEnumerable<string> CreateDirectories(string rootPath, params string[] names) 147 { 148 List<string> paths = new List<string>(); 149 150 foreach (string name in names) 151 { 152 string path = Path.Combine(rootPath, name); 153 154 Directory.CreateDirectory(path); 155 156 paths.Add(path); 157 } 158 159 return paths; 160 } 161 CreateFiles(string rootPath, params string[] names)162 public static IEnumerable<string> CreateFiles(string rootPath, params string[] names) 163 { 164 List<string> paths = new List<string>(); 165 166 foreach (string name in names) 167 { 168 string path = Path.Combine(rootPath, name); 169 170 FileStream stream = File.Create(path); 171 stream.Dispose(); 172 173 paths.Add(path); 174 } 175 176 return paths; 177 } 178 AddTrailingSlashIfNeeded(string path)179 public static string AddTrailingSlashIfNeeded(string path) 180 { 181 if (path.Length > 0 && path[path.Length - 1] != Path.DirectorySeparatorChar && path[path.Length - 1] != Path.AltDirectorySeparatorChar) 182 { 183 path = path + Path.DirectorySeparatorChar; 184 } 185 186 return path; 187 } 188 RemoveTrailingSlash(string path)189 public static string RemoveTrailingSlash(string path) 190 { 191 return path.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); 192 } 193 GetLogicalDrives()194 private static string[] GetLogicalDrives() 195 { // From .NET Framework's Directory.GetLogicalDrives 196 int drives = DllImports.GetLogicalDrives(); 197 if (drives == 0) 198 throw new InvalidOperationException(); 199 200 uint d = (uint)drives; 201 int count = 0; 202 while (d != 0) 203 { 204 if (((int)d & 1) != 0) count++; 205 d >>= 1; 206 } 207 string[] result = new string[count]; 208 char[] root = new char[] { 'A', ':', '\\' }; 209 d = (uint)drives; 210 count = 0; 211 while (d != 0) 212 { 213 if (((int)d & 1) != 0) 214 { 215 result[count++] = new string(root); 216 } 217 d >>= 1; 218 root[0]++; 219 } 220 221 return result; 222 } 223 GetCurrentDrive()224 public static string GetCurrentDrive() 225 { 226 return Path.GetPathRoot(Directory.GetCurrentDirectory()); 227 } 228 IsDriveNTFS(string drive)229 public static bool IsDriveNTFS(string drive) 230 { 231 if (PlatformDetection.IsInAppContainer) 232 { 233 // we cannot determine filesystem so assume NTFS 234 return true; 235 } 236 237 var di = new DriveInfo(drive); 238 239 return string.Equals(di.DriveFormat, "NTFS", StringComparison.OrdinalIgnoreCase); 240 } 241 GetAvailableFreeBytes(string drive)242 public static long GetAvailableFreeBytes(string drive) 243 { 244 long ignored; 245 long userBytes; 246 if (!DllImports.GetDiskFreeSpaceEx(drive, out userBytes, out ignored, out ignored)) 247 { 248 throw new IOException("DriveName: " + drive + " ErrorCode:" + Marshal.GetLastWin32Error()); 249 } 250 251 return userBytes; 252 } 253 IsReady(string drive)254 private static bool IsReady(string drive) 255 { 256 const int ERROR_NOT_READY = 0x00000015; 257 258 long ignored; 259 if (!DllImports.GetDiskFreeSpaceEx(drive, out ignored, out ignored, out ignored)) 260 { 261 return Marshal.GetLastWin32Error() != ERROR_NOT_READY; 262 } 263 264 return true; 265 } 266 IsFixed(string drive)267 private static bool IsFixed(string drive) 268 { 269 return DllImports.GetDriveType(drive) == 3; 270 } 271 } 272 273