Skip to content

Commit c7e5075

Browse files
[release/6.0] Fix detection of unsupported links (#58399)
* Fix detection of unsupported links * Add Directory.Exists check * Fix CI issue caused by local testing code Co-authored-by: David Cantu <dacantu@microsoft.com>
1 parent 596214e commit c7e5075

4 files changed

Lines changed: 65 additions & 2 deletions

File tree

src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.FileSystem.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections.Generic;
5+
using System.IO.Enumeration;
6+
using System.Linq;
57
using Xunit;
68

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

487+
protected static string? GetAppExecLinkPath()
488+
{
489+
string localAppDataPath = Environment.GetEnvironmentVariable("LOCALAPPDATA");
490+
if (localAppDataPath is null)
491+
{
492+
return null;
493+
}
494+
495+
string windowsAppsDir = Path.Join(localAppDataPath, "Microsoft", "WindowsApps");
496+
497+
if (!Directory.Exists(windowsAppsDir))
498+
{
499+
return null;
500+
}
501+
502+
var opts = new EnumerationOptions { RecurseSubdirectories = true };
503+
504+
return new FileSystemEnumerable<string?>(
505+
windowsAppsDir,
506+
(ref FileSystemEntry entry) => entry.ToFullPath(),
507+
opts)
508+
{
509+
ShouldIncludePredicate = (ref FileSystemEntry entry) =>
510+
FileSystemName.MatchesWin32Expression("*.exe", entry.FileName) &&
511+
(entry.Attributes & FileAttributes.ReparsePoint) != 0
512+
}.FirstOrDefault();
513+
}
514+
485515
public static IEnumerable<object[]> ResolveLinkTarget_PathToTarget_Data
486516
{
487517
get

src/libraries/System.IO.FileSystem/tests/File/SymbolicLinks.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,21 @@ protected override void AssertLinkExists(FileSystemInfo link) =>
4545
public void ResolveLinkTarget_Throws_NotExists() =>
4646
ResolveLinkTarget_Throws_NotExists_Internal<FileNotFoundException>();
4747

48+
[Fact]
49+
[PlatformSpecific(TestPlatforms.Windows)]
50+
public void UnsupportedLink_ReturnsNull()
51+
{
52+
string unsupportedLinkPath = GetAppExecLinkPath();
53+
if (unsupportedLinkPath is null)
54+
{
55+
return;
56+
}
57+
58+
Assert.Null(File.ResolveLinkTarget(unsupportedLinkPath, false));
59+
Assert.Null(File.ResolveLinkTarget(unsupportedLinkPath, true));
60+
}
61+
62+
4863
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
4964
public void CreateSymbolicLink_PathToTarget_RelativeToLinkPath()
5065
{

src/libraries/System.IO.FileSystem/tests/FileInfo/SymbolicLinks.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,24 @@ protected override void AssertLinkExists(FileSystemInfo link) =>
4141
public void ResolveLinkTarget_Throws_NotExists() =>
4242
ResolveLinkTarget_Throws_NotExists_Internal<FileNotFoundException>();
4343

44+
45+
[Fact]
46+
[PlatformSpecific(TestPlatforms.Windows)]
47+
public void UnsupportedLink_ReturnsNull()
48+
{
49+
string unsupportedLinkPath = GetAppExecLinkPath();
50+
if (unsupportedLinkPath is null)
51+
{
52+
return;
53+
}
54+
55+
var info = new FileInfo(unsupportedLinkPath);
56+
57+
Assert.Null(info.LinkTarget);
58+
Assert.Null(info.ResolveLinkTarget(false));
59+
Assert.Null(info.ResolveLinkTarget(true));
60+
}
61+
4462
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
4563
public void CreateSymbolicLink_PathToTarget_RelativeToLinkPath()
4664
{

src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,8 @@ internal static void CreateSymbolicLink(string path, string pathToTarget, bool i
556556
// The file or directory is not a reparse point.
557557
if ((data.dwFileAttributes & (uint)FileAttributes.ReparsePoint) == 0 ||
558558
// Only symbolic links and mount points are supported at the moment.
559-
((data.dwReserved0 & Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK) == 0 &&
560-
(data.dwReserved0 & Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT) == 0))
559+
(data.dwReserved0 != Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK &&
560+
data.dwReserved0 != Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT))
561561
{
562562
return null;
563563
}

0 commit comments

Comments
 (0)