From d72cedd70bff63c6ced2f2ea2588f999fb5c1c94 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Mon, 25 Jul 2022 15:07:26 -0700 Subject: [PATCH] Fix `FileSystemProvider` to work with volume and pipe paths (#15873) --- .../engine/Utils.cs | 6 +++--- .../namespaces/FileSystemProvider.cs | 17 +++++++++-------- .../Get-ChildItem.Tests.ps1 | 12 ++++++++++++ 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 16ac72bfb1..eb6adb8b7a 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1281,7 +1281,7 @@ namespace System.Management.Automation return false; } - internal static bool PathIsUnc(string path) + internal static bool PathIsUnc(string path, bool networkOnly = false) { #if UNIX return false; @@ -1291,8 +1291,8 @@ namespace System.Management.Automation return false; } - // handle special cases like \\wsl$\ubuntu which isn't a UNC path, but we can say it is so the filesystemprovider can use it - if (path.StartsWith(WslRootPath, StringComparison.OrdinalIgnoreCase)) + // handle special cases like '\\wsl$\ubuntu', '\\?\', and '\\.\pipe\' which aren't a UNC path, but we can say it is so the filesystemprovider can use it + if (!networkOnly && (path.StartsWith(WslRootPath, StringComparison.OrdinalIgnoreCase) || path.StartsWith("\\\\?\\") || path.StartsWith("\\\\.\\"))) { return true; } diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 84cc0d4782..3d28b5bb7c 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -132,20 +132,21 @@ namespace Microsoft.PowerShell.Commands itemsToSkip = 4; } - foreach (string item in path.Split(StringLiterals.DefaultPathSeparator)) + var items = path.Split(StringLiterals.DefaultPathSeparator); + for (int i = 0; i < items.Length; i++) { if (itemsToSkip-- > 0) { // This handles the UNC server and share and 8.3 short path syntax - exactPath += item + StringLiterals.DefaultPathSeparator; + exactPath += items[i] + StringLiterals.DefaultPathSeparator; continue; } else if (string.IsNullOrEmpty(exactPath)) { // This handles the drive letter or / root path start - exactPath = item + StringLiterals.DefaultPathSeparator; + exactPath = items[i] + StringLiterals.DefaultPathSeparator; } - else if (string.IsNullOrEmpty(item)) + else if (string.IsNullOrEmpty(items[i]) && i == items.Length - 1) { // This handles the trailing slash case if (!exactPath.EndsWith(StringLiterals.DefaultPathSeparator)) @@ -155,17 +156,17 @@ namespace Microsoft.PowerShell.Commands break; } - else if (item.Contains('~')) + else if (items[i].Contains('~')) { // This handles short path names - exactPath += StringLiterals.DefaultPathSeparator + item; + exactPath += StringLiterals.DefaultPathSeparator + items[i]; } else { // Use GetFileSystemEntries to get the correct casing of this element try { - var entries = Directory.GetFileSystemEntries(exactPath, item); + var entries = Directory.GetFileSystemEntries(exactPath, items[i]); if (entries.Length > 0) { exactPath = entries[0]; @@ -7257,7 +7258,7 @@ namespace Microsoft.PowerShell.Commands return false; } - if (Utils.PathIsUnc(path)) + if (Utils.PathIsUnc(path, networkOnly : true)) { return true; } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 index a5d06df0b4..5ab0a043f0 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 @@ -228,6 +228,18 @@ Describe "Get-ChildItem" -Tags "CI" { $barFiles = Get-ChildItem -Path testdrive:/foo/bar -Recurse $barFiles.Count | Should -Be 2 } + + It 'Works with Windows volume paths' -Skip:(!$IsWindows) { + $volume = (Get-Volume -DriveLetter $env:SystemDrive[0]).Path + $items = Get-ChildItem -LiteralPath "${volume}Windows" + $items[0].Parent | Should -BeExactly "${volume}Windows" + $items | Should -HaveCount (Get-ChildItem $env:SystemRoot).Count + } + + It 'Works with Windows pipes' -Skip:(!$IsWindows) { + $out = pwsh -noprofile -custompipename myTestPipe { Get-ChildItem \\.\pipe\myTestPipe } + $out.Name | Should -BeExactly 'myTestPipe' + } } Context 'Env: Provider' {