Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8e7069a
Add mount point support to link APIs.
carlossanlop Aug 24, 2021
11960b4
Add junction and virtual drive tests.
carlossanlop Aug 24, 2021
e59f2b2
Move PrintName comment outside of if else of reparseTag check.
carlossanlop Aug 24, 2021
2923c9e
Add Windows platform specific attribute to junction and virtual drive…
carlossanlop Aug 24, 2021
b6cf857
Revert FILE_NAME_OPENED to FILE_NAME_NORMALIZED
carlossanlop Aug 24, 2021
3ef33c2
Revert addition of FILE_NAME_OPENED const.
carlossanlop Aug 24, 2021
bc12ecf
Remove unnecessary enumeration junction test.
carlossanlop Aug 25, 2021
8957765
Rename GetNewCwdPath to ChangeCurrentDirectory
carlossanlop Aug 25, 2021
ce2aa86
Make Junction_ResolveLinkTarget a theory and test both resolveFinalTa…
carlossanlop Aug 25, 2021
999cddc
Shorter name for targetPath string. Typo in comment. Fix Debug.Assert.
carlossanlop Aug 25, 2021
42fb3a0
Clarify test comment. Change PlatformDetection for OperatingSystem ch…
carlossanlop Aug 25, 2021
ca1f2b2
Cleaner unit tests for virtual drive, add indirection test
carlossanlop Aug 26, 2021
6f6d368
Skip virtual drive tests in Windows Nano (subst not available). Small…
carlossanlop Aug 26, 2021
ec8000b
Simplify Junctions tests, add indirection test
carlossanlop Aug 26, 2021
7df549e
Address test suggestions.
carlossanlop Aug 26, 2021
be9e582
Revert MountHelper.CreateSymbolicLink changes. Unrelated, and will be…
carlossanlop Aug 27, 2021
d33bda3
Add dwReserved0 check for mount points in GetFinalLinkTarget.
carlossanlop Aug 27, 2021
244246b
Use Yoda we don't.
carlossanlop Aug 27, 2021
bd7e9cc
Fix CI issues
jozkee Aug 27, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Revert MountHelper.CreateSymbolicLink changes. Unrelated, and will be…
… refactored/removed in the future.

Detect if SUBST is available in Windows machine, to bring back Nano.
  • Loading branch information
carlossanlop committed Aug 27, 2021
commit be9e582750ff6298bda7d2c479320ef9372f3d7f
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,28 @@ private static bool GetStaticNonPublicBooleanPropertyValue(string typeName, stri
public static bool IsIcuGlobalization => ICUVersion > new Version(0,0,0,0);
public static bool IsNlsGlobalization => IsNotInvariantGlobalization && !IsIcuGlobalization;

public static bool IsSubstAvailable
{
get
{
try
{
if (OperatingSystem.IsWindows())
{
string systemRoot = Environment.GetEnvironmentVariable("SystemRoot");
if (string.IsNullOrWhiteSpace(systemRoot))
{
return false;
}
string system32 = Path.Join(systemRoot, "System32");
return File.Exists(Path.Join(system32, "subst.exe"));
}
}
catch { }
return false;
}
}

private static Version GetICUVersion()
{
int version = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,23 @@ public static class MountHelper
/// <summary>Creates a symbolic link using command line tools.</summary>
public static bool CreateSymbolicLink(string linkPath, string targetPath, bool isDirectory)
{
string fileName;
string[] arguments;
Process symLinkProcess = new Process();
if (OperatingSystem.IsWindows())
{
fileName = "cmd";
arguments = new[] { "/c", "mklink", isDirectory ? "/D" : "", linkPath, targetPath };
symLinkProcess.StartInfo.FileName = "cmd";
symLinkProcess.StartInfo.Arguments = string.Format("/c mklink{0} \"{1}\" \"{2}\"", isDirectory ? " /D" : "", linkPath, targetPath);
}
else
{
fileName = "/bin/ln";
arguments = new[] { "-s", targetPath, linkPath };
symLinkProcess.StartInfo.FileName = "/bin/ln";
symLinkProcess.StartInfo.Arguments = string.Format("-s \"{0}\" \"{1}\"", targetPath, linkPath);
}
symLinkProcess.StartInfo.UseShellExecute = false;
symLinkProcess.StartInfo.RedirectStandardOutput = true;
symLinkProcess.Start();

return RunProcess(CreateStartInfo(fileName, arguments));
symLinkProcess.WaitForExit();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the code above was not modified, but we should rather refactor it as well:

Depeneding on your personal preferences it could be:

public static bool CreateSymbolicLink(string linkPath, string targetPath, bool isDirectory)
{
    ProcessStartInfo startInfo = OperatingSystem.IsWindows()
        ? CreateStartInfo("cmd", "/c", "mklink", isDirectory ? "/D" : "", linkPath, targetPath)
        : CreateStartInfo("/bin/ln",  "-s", targetPath, linkPath);

    return RunProcess(startInfo);
}

Or

public static bool CreateSymbolicLink(string linkPath, string targetPath, bool isDirectory)
    => RunProcess(OperatingSystem.IsWindows()
        ? CreateStartInfo("cmd", "/c", "mklink", isDirectory ? "/D" : "", linkPath, targetPath)
        : CreateStartInfo("/bin/ln",  "-s", targetPath, linkPath));

Copy link
Contributor Author

@carlossanlop carlossanlop Aug 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also refactored it, initially. I used the code you shared the first time. It caused all the symlink enumeration tests to fail. It was taking me too long to figure out why so I decided to revert it and the tests passed again.
I can take a look again in the related PR for AppExecLinks, if you don't mind.

return (0 == symLinkProcess.ExitCode);
}

/// <summary>On Windows, creates a junction using command line tools.</summary>
Expand All @@ -55,7 +58,7 @@ public static bool CreateJunction(string junctionPath, string targetPath)
throw new PlatformNotSupportedException();
}

return RunProcess(CreateStartInfo("cmd", "/c", "mklink", "/J", junctionPath, targetPath));
return RunProcess(CreateProcessStartInfo("cmd", "/c", "mklink", "/J", junctionPath, targetPath));
}

///<summary>
Expand All @@ -70,7 +73,7 @@ public static char CreateVirtualDrive(string targetDir)
}

char driveLetter = GetNextAvailableDriveLetter();
bool success = RunProcess(CreateStartInfo("subst", $"{driveLetter}:", targetDir));
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");
Expand Down Expand Up @@ -106,7 +109,7 @@ public static void DeleteVirtualDrive(char driveLetter)
throw new PlatformNotSupportedException();
}

bool success = RunProcess(CreateStartInfo("subst", "/d", $"{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");
Expand Down Expand Up @@ -146,7 +149,7 @@ public static void Unmount(string mountPoint)
throw new Exception(string.Format("Win32 error: {0}", Marshal.GetLastPInvokeError()));
}

private static ProcessStartInfo CreateStartInfo(string fileName, params string[] arguments)
private static ProcessStartInfo CreateProcessStartInfo(string fileName, params string[] arguments)
{
var info = new ProcessStartInfo
{
Expand All @@ -170,6 +173,21 @@ private static bool RunProcess(ProcessStartInfo startInfo)
return process.ExitCode == 0;
}

private static string SubstPath
{
get
{
if (!OperatingSystem.IsWindows())
{
throw new PlatformNotSupportedException();
}

string systemRoot = Environment.GetEnvironmentVariable("SystemRoot") ?? @"C:\Windows";
string system32 = Path.Join(systemRoot, "System32");
return Path.Join(system32, "subst.exe");
}
}

/// For standalone debugging help. Change Main0 to Main
public static void Main0(string[] args)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace System.IO.Tests
// Need to reuse the same virtual drive for all the test methods.
// Creating and disposing one virtual drive per class achieves this.
[PlatformSpecific(TestPlatforms.Windows)]
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsSubstAvailable))]
public class VirtualDrive_SymbolicLinks : BaseSymbolicLinks
{
protected override void Dispose(bool disposing)
Expand Down