-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Add internal junction support to link APIs #57996
Changes from 4 commits
8e7069a
11960b4
e59f2b2
2923c9e
b6cf857
3ef33c2
bc12ecf
8957765
ce2aa86
999cddc
42fb3a0
ca1f2b2
6f6d368
ec8000b
7df549e
be9e582
d33bda3
244246b
bd7e9cc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// 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.Linq; | ||
using Xunit; | ||
|
||
namespace System.IO.Tests | ||
{ | ||
[PlatformSpecific(TestPlatforms.Windows)] | ||
public abstract class BaseJunctions_FileSystem : BaseSymbolicLinks | ||
{ | ||
protected DirectoryInfo CreateJunction(string junctionPath, string targetPath) | ||
{ | ||
Assert.True(MountHelper.CreateJunction(junctionPath, targetPath)); | ||
DirectoryInfo junctionInfo = new(junctionPath); | ||
return junctionInfo; | ||
} | ||
|
||
protected abstract DirectoryInfo CreateDirectory(string path); | ||
carlossanlop marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
protected abstract FileSystemInfo ResolveLinkTarget(string junctionPath, bool returnFinalTarget); | ||
|
||
protected abstract void VerifyEnumerateMethods(string junctionPath, string[] expectedFiles, string[] expectedDirectories, string[] expectedEntries); | ||
carlossanlop marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
protected void VerifyEnumeration(IEnumerable<string> expectedEnumeration, IEnumerable<string> actualEnumeration) | ||
{ | ||
foreach (string expectedItem in expectedEnumeration) | ||
{ | ||
Assert.True(actualEnumeration.Contains(expectedItem)); | ||
} | ||
carlossanlop marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
[Fact] | ||
public void Junction_ResolveLinkTarget() | ||
{ | ||
string junctionPath = GetRandomLinkPath(); | ||
string targetPath = GetRandomDirPath(); | ||
|
||
CreateDirectory(targetPath); | ||
DirectoryInfo junctionInfo = CreateJunction(junctionPath, targetPath); | ||
|
||
FileSystemInfo? actualTargetInfo = ResolveLinkTarget(junctionPath, returnFinalTarget: false); | ||
carlossanlop marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Assert.True(actualTargetInfo is DirectoryInfo); | ||
Assert.Equal(targetPath, actualTargetInfo.FullName); | ||
Assert.Equal(targetPath, junctionInfo.LinkTarget); | ||
} | ||
|
||
[Fact] | ||
public void Junction_EnumerateFileSystemEntries() | ||
{ | ||
// Root | ||
string targetPath = GetRandomDirPath(); | ||
Directory.CreateDirectory(targetPath); | ||
|
||
string fileName = GetRandomFileName(); | ||
string subDirName = GetRandomDirName(); | ||
string subFileName = Path.Join(subDirName, GetRandomFileName()); | ||
|
||
string filePath = Path.Join(targetPath, fileName); | ||
string subDirPath = Path.Join(targetPath, subDirName); | ||
string subFilePath = Path.Join(targetPath, subFileName); | ||
|
||
File.Create(filePath).Dispose(); | ||
Directory.CreateDirectory(subDirPath); | ||
File.Create(subFilePath).Dispose(); | ||
|
||
string junctionPath = GetRandomLinkPath(); | ||
CreateJunction(junctionPath, targetPath); | ||
|
||
string jFilePath = Path.Join(junctionPath, fileName); | ||
string jSubDirPath = Path.Join(junctionPath, subDirName); | ||
string jSubFilePath = Path.Join(junctionPath, subFileName); | ||
|
||
string[] expectedFiles = new[] { jFilePath, jSubFilePath }; | ||
string[] expectedDirectories = new[] { jSubDirPath }; | ||
string[] expectedEntries = new[] { jFilePath, jSubDirPath, jSubFilePath }; | ||
|
||
VerifyEnumerateMethods(junctionPath, expectedFiles, expectedDirectories, expectedEntries); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,6 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Buffers; | ||
using System.Diagnostics; | ||
using System.Runtime.InteropServices; | ||
using Microsoft.Win32.SafeHandles; | ||
using Xunit; | ||
|
||
namespace System.IO.Tests | ||
|
@@ -36,5 +32,19 @@ protected DirectoryInfo CreateSelfReferencingSymbolicLink() | |
protected string GetRandomDirPath() => Path.Join(ActualTestDirectory.Value, GetRandomDirName()); | ||
|
||
private Lazy<string> ActualTestDirectory => new Lazy<string>(() => GetTestDirectoryActualCasing()); | ||
|
||
/// <summary> | ||
/// Changes the current working directory path to a new temporary directory. | ||
/// Important: Make sure to call this inside a remote executor to avoid changing the cwd for all tests in same process. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there a way to ensure that it's called from Remote Executor? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if we can add such a check here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it would have to be something like this |
||
/// </summary> | ||
/// <returns>The path of the new cwd.</returns> | ||
protected string GetNewCwdPath() | ||
{ | ||
string tempCwd = GetRandomDirPath(); | ||
Directory.CreateDirectory(tempCwd); | ||
Directory.SetCurrentDirectory(tempCwd); | ||
return tempCwd; | ||
} | ||
|
||
carlossanlop marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using Xunit; | ||
|
||
namespace System.IO.Tests | ||
{ | ||
[PlatformSpecific(TestPlatforms.Windows)] | ||
public class Directory_Junctions : BaseJunctions_FileSystem | ||
{ | ||
protected override DirectoryInfo CreateDirectory(string path) => | ||
Directory.CreateDirectory(path); | ||
|
||
protected override FileSystemInfo? ResolveLinkTarget(string junctionPath, bool returnFinalTarget) => | ||
Directory.ResolveLinkTarget(junctionPath, returnFinalTarget); | ||
|
||
protected override void VerifyEnumerateMethods(string junctionPath, string[] expectedFiles, string[] expectedDirectories, string[] expectedEntries) | ||
{ | ||
EnumerationOptions options = new() { RecurseSubdirectories = true }; | ||
|
||
VerifyEnumeration( | ||
Directory.EnumerateFiles(junctionPath, "*", options), | ||
expectedFiles); | ||
|
||
VerifyEnumeration( | ||
Directory.EnumerateDirectories(junctionPath, "*", options), | ||
expectedDirectories); | ||
|
||
VerifyEnumeration( | ||
Directory.EnumerateFileSystemEntries(junctionPath, "*", options), | ||
expectedEntries); | ||
|
||
VerifyEnumeration( | ||
Directory.GetFiles(junctionPath, "*", options), | ||
expectedFiles); | ||
|
||
VerifyEnumeration( | ||
Directory.GetDirectories(junctionPath, "*", options), | ||
expectedDirectories); | ||
|
||
VerifyEnumeration( | ||
Directory.GetFileSystemEntries(junctionPath, "*", options), | ||
expectedEntries); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Linq; | ||
using Xunit; | ||
|
||
namespace System.IO.Tests | ||
{ | ||
[PlatformSpecific(TestPlatforms.Windows)] | ||
public class DirectoryInfo_Junctions : BaseJunctions_FileSystem | ||
{ | ||
protected override DirectoryInfo CreateDirectory(string path) | ||
{ | ||
DirectoryInfo dirInfo = new(path); | ||
dirInfo.Create(); | ||
return dirInfo; | ||
} | ||
|
||
protected override FileSystemInfo? ResolveLinkTarget(string junctionPath, bool returnFinalTarget) => | ||
new DirectoryInfo(junctionPath).ResolveLinkTarget(returnFinalTarget); | ||
|
||
protected override void VerifyEnumerateMethods(string junctionPath, string[] expectedFiles, string[] expectedDirectories, string[] expectedEntries) | ||
{ | ||
EnumerationOptions options = new() { RecurseSubdirectories = true }; | ||
|
||
DirectoryInfo info = new(junctionPath); | ||
|
||
VerifyEnumeration( | ||
info.EnumerateFiles("*", options).Select(x => x.FullName), | ||
expectedFiles); | ||
|
||
VerifyEnumeration( | ||
info.EnumerateDirectories("*", options).Select(x => x.FullName), | ||
expectedDirectories); | ||
|
||
VerifyEnumeration( | ||
info.EnumerateFileSystemInfos("*", options).Select(x => x.FullName), | ||
expectedEntries); | ||
|
||
VerifyEnumeration( | ||
info.GetFiles("*", options).Select(x => x.FullName), | ||
expectedFiles); | ||
|
||
VerifyEnumeration( | ||
info.GetDirectories("*", options).Select(x => x.FullName), | ||
expectedDirectories); | ||
|
||
VerifyEnumeration( | ||
info.GetFileSystemInfos("*", options).Select(x => x.FullName), | ||
expectedEntries); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I renamed this to match the names that were provided in the
DUMMYUNIONNAME
section of the official Windows docs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, the structs are not nested. This is how PowerShell had it already: https://github.com/PowerShell/PowerShell/blob/56d22bc3865fca445145fd685d6d6f6d63194701/src/System.Management.Automation/namespaces/FileSystemProvider.cs#L7957-L7985