diff --git a/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.FileSystem.cs b/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.FileSystem.cs index 9f61e73a36a6b1..e3b9027234a985 100644 --- a/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.FileSystem.cs +++ b/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.FileSystem.cs @@ -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 @@ -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( + 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 ResolveLinkTarget_PathToTarget_Data { get diff --git a/src/libraries/System.IO.FileSystem/tests/File/SymbolicLinks.cs b/src/libraries/System.IO.FileSystem/tests/File/SymbolicLinks.cs index 4c41fa7bb16576..e879cb353af73d 100644 --- a/src/libraries/System.IO.FileSystem/tests/File/SymbolicLinks.cs +++ b/src/libraries/System.IO.FileSystem/tests/File/SymbolicLinks.cs @@ -45,6 +45,21 @@ protected override void AssertLinkExists(FileSystemInfo link) => public void ResolveLinkTarget_Throws_NotExists() => ResolveLinkTarget_Throws_NotExists_Internal(); + [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() { diff --git a/src/libraries/System.IO.FileSystem/tests/FileInfo/SymbolicLinks.cs b/src/libraries/System.IO.FileSystem/tests/FileInfo/SymbolicLinks.cs index fa334dd1ca376d..914edd06a1ba65 100644 --- a/src/libraries/System.IO.FileSystem/tests/FileInfo/SymbolicLinks.cs +++ b/src/libraries/System.IO.FileSystem/tests/FileInfo/SymbolicLinks.cs @@ -41,6 +41,24 @@ protected override void AssertLinkExists(FileSystemInfo link) => public void ResolveLinkTarget_Throws_NotExists() => ResolveLinkTarget_Throws_NotExists_Internal(); + + [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() { diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs index d2bde47c3134b6..223117e34e6603 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs @@ -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; }