Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.IO.Enumeration;
using System.Linq;
using Xunit;

namespace System.IO.Tests
Expand Down Expand Up @@ -482,6 +484,34 @@ protected void CreateSymbolicLink_PathToTarget_RelativeToLinkPath_Internal(bool
Assert.Equal(Path.GetDirectoryName(linkInfo.FullName), Path.GetDirectoryName(targetInfo.FullName));
}

protected static string? GetAppExecLinkPath()
{
string localAppDataPath = Environment.GetEnvironmentVariable("LOCALAPPDATA");
if (localAppDataPath is null)
{
return null;
}

string windowsAppsDir = Path.Join(localAppDataPath, "Microsoft", "WindowsApps");

if (!Directory.Exists(windowsAppsDir))
{
return null;
}

var opts = new EnumerationOptions { RecurseSubdirectories = true };

return new FileSystemEnumerable<string?>(
windowsAppsDir,
(ref FileSystemEntry entry) => entry.ToFullPath(),
opts)
{
ShouldIncludePredicate = (ref FileSystemEntry entry) =>
FileSystemName.MatchesWin32Expression("*.exe", entry.FileName) &&
(entry.Attributes & FileAttributes.ReparsePoint) != 0
}.FirstOrDefault();
}

public static IEnumerable<object[]> ResolveLinkTarget_PathToTarget_Data
{
get
Expand Down
15 changes: 15 additions & 0 deletions src/libraries/System.IO.FileSystem/tests/File/SymbolicLinks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ protected override void AssertLinkExists(FileSystemInfo link) =>
public void ResolveLinkTarget_Throws_NotExists() =>
ResolveLinkTarget_Throws_NotExists_Internal<FileNotFoundException>();

[Fact]
[PlatformSpecific(TestPlatforms.Windows)]
public void UnsupportedLink_ReturnsNull()
{
string unsupportedLinkPath = GetAppExecLinkPath();
if (unsupportedLinkPath is null)
{
return;
}

Assert.Null(File.ResolveLinkTarget(unsupportedLinkPath, false));
Assert.Null(File.ResolveLinkTarget(unsupportedLinkPath, true));
}


[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void CreateSymbolicLink_PathToTarget_RelativeToLinkPath()
{
Expand Down
18 changes: 18 additions & 0 deletions src/libraries/System.IO.FileSystem/tests/FileInfo/SymbolicLinks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ protected override void AssertLinkExists(FileSystemInfo link) =>
public void ResolveLinkTarget_Throws_NotExists() =>
ResolveLinkTarget_Throws_NotExists_Internal<FileNotFoundException>();


[Fact]
[PlatformSpecific(TestPlatforms.Windows)]
public void UnsupportedLink_ReturnsNull()
{
string unsupportedLinkPath = GetAppExecLinkPath();
if (unsupportedLinkPath is null)
{
return;
}

var info = new FileInfo(unsupportedLinkPath);

Assert.Null(info.LinkTarget);
Assert.Null(info.ResolveLinkTarget(false));
Assert.Null(info.ResolveLinkTarget(true));
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void CreateSymbolicLink_PathToTarget_RelativeToLinkPath()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -556,8 +556,8 @@ internal static void CreateSymbolicLink(string path, string pathToTarget, bool i
// The file or directory is not a reparse point.
if ((data.dwFileAttributes & (uint)FileAttributes.ReparsePoint) == 0 ||
// Only symbolic links and mount points are supported at the moment.
((data.dwReserved0 & Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK) == 0 &&
(data.dwReserved0 & Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT) == 0))
(data.dwReserved0 != Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK &&
data.dwReserved0 != Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT))
{
return null;
}
Expand Down