-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Re-enable Windows test that verifies DriveInfo.VolumeLabel setter fails on SUBST'd drive #59850
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
148 changes: 148 additions & 0 deletions
148
src/libraries/Common/tests/System/IO/VirtualDriveHelper.Windows.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
| using System.Linq; | ||
| using System.Runtime.Versioning; | ||
|
|
||
| namespace System.IO | ||
| { | ||
| // Adds test helper APIs to manipulate Windows virtual drives via SUBST. | ||
| [SupportedOSPlatform("windows")] | ||
| public class VirtualDriveHelper : IDisposable | ||
| { | ||
| // Temporary Windows directory that can be mounted to a drive letter using the subst command | ||
| private string? _virtualDriveTargetDir = null; | ||
| // Windows drive letter that points to a mounted directory using the subst command | ||
| private char _virtualDriveLetter = default; | ||
|
|
||
| /// <summary> | ||
| /// If there is a SUBST'ed drive, Dispose unmounts it to free the drive letter. | ||
| /// </summary> | ||
| public void Dispose() | ||
| { | ||
| try | ||
| { | ||
| if (VirtualDriveLetter != default) | ||
| { | ||
| DeleteVirtualDrive(VirtualDriveLetter); | ||
| Directory.Delete(VirtualDriveTargetDir, recursive: true); | ||
| } | ||
| } | ||
| catch { } // avoid exceptions on dispose | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Returns the path of a folder that is to be mounted using SUBST. | ||
| /// </summary> | ||
| public string VirtualDriveTargetDir | ||
| { | ||
| get | ||
| { | ||
| if (_virtualDriveTargetDir == null) | ||
| { | ||
| // Create a folder inside the temp directory so that it can be mounted to a drive letter with subst | ||
| _virtualDriveTargetDir = Path.Join(Path.GetTempPath(), Path.GetRandomFileName()); | ||
| Directory.CreateDirectory(_virtualDriveTargetDir); | ||
| } | ||
|
|
||
| return _virtualDriveTargetDir; | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Returns the drive letter of a drive letter that represents a mounted folder using SUBST. | ||
| /// </summary> | ||
| public char VirtualDriveLetter | ||
| { | ||
| get | ||
| { | ||
| if (_virtualDriveLetter == default) | ||
| { | ||
| // Mount the folder to a drive letter | ||
| _virtualDriveLetter = CreateVirtualDrive(VirtualDriveTargetDir); | ||
| } | ||
| return _virtualDriveLetter; | ||
| } | ||
| } | ||
|
|
||
| ///<summary> | ||
| /// On Windows, mounts a folder to an assigned virtual drive letter using the subst command. | ||
| /// subst is not available in Windows Nano. | ||
| /// </summary> | ||
| private static char CreateVirtualDrive(string targetDir) | ||
| { | ||
| char driveLetter = GetNextAvailableDriveLetter(); | ||
| bool success = RunProcess(CreateProcessStartInfo("cmd", "/c", SubstPath, $"{driveLetter}:", targetDir)); | ||
| if (!success || !DriveInfo.GetDrives().Any(x => x.Name[0] == driveLetter)) | ||
| { | ||
| throw new InvalidOperationException($"Could not create virtual drive {driveLetter}: with subst"); | ||
| } | ||
| return driveLetter; | ||
|
|
||
| // Finds the next unused drive letter and returns it. | ||
| char GetNextAvailableDriveLetter() | ||
| { | ||
| List<char> existingDrives = DriveInfo.GetDrives().Select(x => x.Name[0]).ToList(); | ||
|
|
||
| // A,B are reserved, C is usually reserved | ||
| IEnumerable<int> range = Enumerable.Range('D', 'Z' - 'D'); | ||
| IEnumerable<char> castRange = range.Select(x => Convert.ToChar(x)); | ||
| IEnumerable<char> allDrivesLetters = castRange.Except(existingDrives); | ||
|
|
||
| if (!allDrivesLetters.Any()) | ||
| { | ||
| throw new ArgumentOutOfRangeException("No drive letters available"); | ||
| } | ||
|
|
||
| return allDrivesLetters.First(); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// On Windows, unassigns the specified virtual drive letter from its mounted folder. | ||
| /// </summary> | ||
| private static void DeleteVirtualDrive(char driveLetter) | ||
| { | ||
| bool success = RunProcess(CreateProcessStartInfo("cmd", "/c", SubstPath, "/d", $"{driveLetter}:")); | ||
| if (!success || DriveInfo.GetDrives().Any(x => x.Name[0] == driveLetter)) | ||
| { | ||
| throw new InvalidOperationException($"Could not delete virtual drive {driveLetter}: with subst"); | ||
| } | ||
| } | ||
|
|
||
| private static ProcessStartInfo CreateProcessStartInfo(string fileName, params string[] arguments) | ||
| { | ||
| var info = new ProcessStartInfo | ||
| { | ||
| FileName = fileName, | ||
| UseShellExecute = false, | ||
| RedirectStandardOutput = true | ||
| }; | ||
|
|
||
| foreach (var argument in arguments) | ||
| { | ||
| info.ArgumentList.Add(argument); | ||
| } | ||
|
|
||
| return info; | ||
| } | ||
|
|
||
| private static bool RunProcess(ProcessStartInfo startInfo) | ||
| { | ||
| using var process = Process.Start(startInfo); | ||
| process.WaitForExit(); | ||
| return process.ExitCode == 0; | ||
| } | ||
|
|
||
| private static string SubstPath | ||
| { | ||
| get | ||
| { | ||
| string systemRoot = Environment.GetEnvironmentVariable("SystemRoot") ?? @"C:\Windows"; | ||
| return Path.Join(systemRoot, "System32", "subst.exe"); | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
src/libraries/System.IO.FileSystem.DriveInfo/tests/VirtualDrives.Windows.Tests.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Runtime.InteropServices; | ||
| using System.Security; | ||
| using System.Text; | ||
| using Xunit; | ||
|
|
||
| namespace System.IO.FileSystem.Tests | ||
| { | ||
| // Separate class from the rest of the DriveInfo tests to prevent adding an extra virtual drive to GetDrives(). | ||
| public class DriveInfoVirtualDriveTests | ||
| { | ||
| // Cannot set the volume label on a SUBST'ed folder | ||
| [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsSubstAvailable))] | ||
| [PlatformSpecific(TestPlatforms.Windows)] | ||
| public void SetVolumeLabel_OnVirtualDrive_Throws() | ||
| { | ||
| using VirtualDriveHelper virtualDrive = new(); | ||
| char letter = virtualDrive.VirtualDriveLetter; // Trigger calling subst | ||
| DriveInfo drive = DriveInfo.GetDrives().Where(d => d.RootDirectory.FullName[0] == letter).FirstOrDefault(); | ||
| Assert.NotNull(drive); | ||
| Assert.Throws<IOException>(() => drive.VolumeLabel = "impossible"); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.