From b18eacaa831cef05bd97ef2ae557cab4eabd5e9e Mon Sep 17 00:00:00 2001 From: Matej Kafka <6414091+MatejKafka@users.noreply.github.com> Date: Wed, 4 Dec 2024 00:00:00 +0100 Subject: [PATCH] Resolve symbolic link target relative to the symbolic link instead of the working directory (#15235) (#20943) --- .../namespaces/FileSystemProvider.cs | 16 ++++----- .../FileSystem.Tests.ps1 | 33 +++++++++++++++++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index d22fcdc88f..d23c8ebead 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -2258,16 +2258,14 @@ namespace Microsoft.PowerShell.Commands { exists = true; - var normalizedTargetPath = strTargetPath; - if (strTargetPath.StartsWith(".\\", StringComparison.OrdinalIgnoreCase) || - strTargetPath.StartsWith("./", StringComparison.OrdinalIgnoreCase)) - { - normalizedTargetPath = Path.Join(SessionState.Internal.CurrentLocation.ProviderPath, strTargetPath.AsSpan(2)); - } - - GetFileSystemInfo(normalizedTargetPath, out isDirectory); - + // unify directory separators to be consistent with the rest of PowerShell even on non-Windows platforms; + // do this before resolving the target, otherwise e.g. `.\test` would break on Linux, since the combined + // path below would be something like `/path/to/cwd/.\test` strTargetPath = strTargetPath.Replace(StringLiterals.AlternatePathSeparator, StringLiterals.DefaultPathSeparator); + + // check if the target is a file or directory + var normalizedTargetPath = Path.Combine(Path.GetDirectoryName(path), strTargetPath); + GetFileSystemInfo(normalizedTargetPath, out isDirectory); } else { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 index b43d7033ca..b365862f9d 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 @@ -1,5 +1,8 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. + +Import-Module HelpersCommon + Describe "Basic FileSystem Provider Tests" -Tags "CI" { BeforeAll { $testDir = "TestDir" @@ -621,6 +624,11 @@ Describe "Hard link and symbolic link tests" -Tags "CI", "RequireAdminOnWindows" } Context "New-Item and hard/symbolic links" { + AfterEach { + # clean up created links after each test + Remove-Item -Exclude (Split-Path -Leaf $realFile, $realDir, $realDir2) -Recurse $TestPath/* + } + It "New-Item can create a hard link to a file" { New-Item -ItemType HardLink -Path $hardLinkToFile -Value $realFile > $null Test-Path $hardLinkToFile | Should -BeTrue @@ -664,6 +672,31 @@ Describe "Hard link and symbolic link tests" -Tags "CI", "RequireAdminOnWindows" $link.LinkType | Should -BeExactly "SymbolicLink" $link.Target | Should -BeExactly $real.ToString() } + + It "New-Item can create a directory symbolic link to a directory using a relative path" -Skip:(-Not $IsWindows) { + $target = Split-Path -Leaf $realDir + New-Item -ItemType SymbolicLink -Path $symLinkToDir -Value $target > $null + Test-Path $symLinkToDir | Should -BeTrue + $real = Get-Item -Path $realDir + $link = Get-Item -Path $symLinkToDir + $link | Should -BeOfType System.IO.DirectoryInfo + $link.LinkType | Should -BeExactly "SymbolicLink" + $link.ResolvedTarget | Should -BeExactly $real.ToString() + $link.Target | Should -BeExactly $target + } + + It "New-Item can create a directory symbolic link to a directory using a relative path with .\" -Skip:(-Not $IsWindows) { + $target = ".\$(Split-Path -Leaf $realDir)" + New-Item -ItemType SymbolicLink -Path $symLinkToDir -Value $target > $null + Test-Path $symLinkToDir | Should -BeTrue + $real = Get-Item -Path $realDir + $link = Get-Item -Path $symLinkToDir + $link | Should -BeOfType System.IO.DirectoryInfo + $link.LinkType | Should -BeExactly "SymbolicLink" + $link.ResolvedTarget | Should -BeExactly $real.ToString() + $link.Target | Should -BeExactly $target + } + It "New-Item can create a directory junction to a directory" -Skip:(-Not $IsWindows) { New-Item -ItemType Junction -Path $junctionToDir -Value $realDir > $null Test-Path $junctionToDir | Should -BeTrue