From 8fa712735bcd6709c13f0e73683bc3932d3e05d5 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Fri, 29 Sep 2017 21:17:19 -0700 Subject: [PATCH 1/4] [feature] support folders and files with colon in name --- .../namespaces/LocationGlobber.cs | 8 +++++--- .../FileSystem.Tests.ps1 | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/namespaces/LocationGlobber.cs b/src/System.Management.Automation/namespaces/LocationGlobber.cs index 16168a60753..b32ce0d159e 100644 --- a/src/System.Management.Automation/namespaces/LocationGlobber.cs +++ b/src/System.Management.Automation/namespaces/LocationGlobber.cs @@ -1649,6 +1649,7 @@ internal static bool IsAbsolutePath(string path) } int index = path.IndexOf(":", StringComparison.Ordinal); + int separator = path.IndexOf(StringLiterals.DefaultPathSeparatorString, StringComparison.Ordinal); if (index == -1) { @@ -1663,7 +1664,7 @@ internal static bool IsAbsolutePath(string path) // must assume that it is part of the path, and not // delimiting the drive name. - if (index > 0) + if (index > 0 && index < separator) { // We must have a drive specified @@ -3404,11 +3405,12 @@ private static string RemoveDriveQualifier(string path) string result = path; - // Find the drive separator + // Find the drive separator only if it's before a path separator int index = path.IndexOf(":", StringComparison.Ordinal); + int separator = path.IndexOf(StringLiterals.DefaultPathSeparatorString, StringComparison.Ordinal); - if (index != -1) + if (index != -1 && index < separator) { // Remove the \ or / if it follows the drive indicator diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 index 909cc24de08..4daf7bf9baf 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 @@ -199,6 +199,23 @@ Describe "Basic FileSystem Provider Tests" -Tags "CI" { New-Item -Path $testFile -ItemType File -Force -ErrorAction SilentlyContinue } } + + It "Set-Location on Unix succeeds with folder with colon" -Skip:($IsWindows) { + New-Item -Path "$testdrive/hello:world" -ItemType Directory > $null + Set-Location "$testdrive" + Set-Location "./hello:world" + (Get-Location).Path | Should Be "$testdrive/hello:world" + } + + It "Get-Content on Unix succeeds with folder and file with colon" -Skip:($IsWindows) { + $testPath = "$testdrive/hello:world" + New-Item -Path $testPath -ItemType Directory > $null + Set-Content -Path "$testPath/foo:bar.txt" -Value "Hello" + $files = Get-ChildItem "$testPath" + $files.Count | Should Be 1 + $files[0].Name | Should BeExactly "foo:bar.txt" + $files[0] | Get-Content | Should BeExactly "Hello" + } } Context "Validate behavior when access is denied" { From 5a62062116ce68da3f8c90976d4082bf70d138fd Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Sat, 30 Sep 2017 07:04:37 -0700 Subject: [PATCH 2/4] [feature] only check separator in relation to colon if a colon is found --- .../namespaces/LocationGlobber.cs | 39 ++++++++++++------- .../FileSystem.Tests.ps1 | 6 +-- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/System.Management.Automation/namespaces/LocationGlobber.cs b/src/System.Management.Automation/namespaces/LocationGlobber.cs index b32ce0d159e..5088afc62db 100644 --- a/src/System.Management.Automation/namespaces/LocationGlobber.cs +++ b/src/System.Management.Automation/namespaces/LocationGlobber.cs @@ -1649,7 +1649,6 @@ internal static bool IsAbsolutePath(string path) } int index = path.IndexOf(":", StringComparison.Ordinal); - int separator = path.IndexOf(StringLiterals.DefaultPathSeparatorString, StringComparison.Ordinal); if (index == -1) { @@ -1664,11 +1663,18 @@ internal static bool IsAbsolutePath(string path) // must assume that it is part of the path, and not // delimiting the drive name. - if (index > 0 && index < separator) + if (index > 0) { - // We must have a drive specified - - result = true; + int separator = path.IndexOf(StringLiterals.DefaultPathSeparator, 0, index); + if (separator == -1) + { + separator = path.IndexOf(StringLiterals.AlternatePathSeparator, 0, index); + } + if (separator == -1 || index < separator) + { + // We must have a drive specified + result = true; + } } } while (false); @@ -3408,19 +3414,24 @@ private static string RemoveDriveQualifier(string path) // Find the drive separator only if it's before a path separator int index = path.IndexOf(":", StringComparison.Ordinal); - int separator = path.IndexOf(StringLiterals.DefaultPathSeparatorString, StringComparison.Ordinal); - - if (index != -1 && index < separator) + if (index != -1) { - // Remove the \ or / if it follows the drive indicator - - if (path[index + 1] == '\\' || - path[index + 1] == '/') + int separator = path.IndexOf(StringLiterals.DefaultPathSeparator, 0, index); + if (separator == -1) { - ++index; + separator = path.IndexOf(StringLiterals.AlternatePathSeparator, 0, index); } + if (separator == -1 || index < separator) + { + // Remove the \ or / if it follows the drive indicator + if (path[index + 1] == '\\' || + path[index + 1] == '/') + { + ++index; + } - result = path.Substring(index + 1); + result = path.Substring(index + 1); + } } return result; diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 index 4daf7bf9baf..46e7ce678b1 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 @@ -201,16 +201,16 @@ Describe "Basic FileSystem Provider Tests" -Tags "CI" { } It "Set-Location on Unix succeeds with folder with colon" -Skip:($IsWindows) { - New-Item -Path "$testdrive/hello:world" -ItemType Directory > $null + New-Item -Path "$testdrive\hello:world" -ItemType Directory > $null Set-Location "$testdrive" - Set-Location "./hello:world" + Set-Location ".\hello:world" (Get-Location).Path | Should Be "$testdrive/hello:world" } It "Get-Content on Unix succeeds with folder and file with colon" -Skip:($IsWindows) { $testPath = "$testdrive/hello:world" New-Item -Path $testPath -ItemType Directory > $null - Set-Content -Path "$testPath/foo:bar.txt" -Value "Hello" + Set-Content -Path "$testPath\foo:bar.txt" -Value "Hello" $files = Get-ChildItem "$testPath" $files.Count | Should Be 1 $files[0].Name | Should BeExactly "foo:bar.txt" From a8600119fe5d947f97151198c0698f1017a03e37 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Tue, 3 Oct 2017 18:34:08 -0700 Subject: [PATCH 3/4] [feature] added comment to clarify algorithm --- .../namespaces/LocationGlobber.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/namespaces/LocationGlobber.cs b/src/System.Management.Automation/namespaces/LocationGlobber.cs index 5088afc62db..718052aa123 100644 --- a/src/System.Management.Automation/namespaces/LocationGlobber.cs +++ b/src/System.Management.Automation/namespaces/LocationGlobber.cs @@ -1665,13 +1665,15 @@ internal static bool IsAbsolutePath(string path) if (index > 0) { - int separator = path.IndexOf(StringLiterals.DefaultPathSeparator, 0, index); + // see if there are any path separators before the colon which would mean the + // colon is part of a file or folder name and not a drive: ./foo:bar vs foo:bar + int separator = path.IndexOf(StringLiterals.DefaultPathSeparator, 0, index-1); if (separator == -1) { - separator = path.IndexOf(StringLiterals.AlternatePathSeparator, 0, index); + separator = path.IndexOf(StringLiterals.AlternatePathSeparator, 0, index-1); } if (separator == -1 || index < separator) - { + { // We must have a drive specified result = true; } From 000a29c4f92dde205ab70618c787a9cec5c4c2cb Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Wed, 4 Oct 2017 07:32:33 -0700 Subject: [PATCH 4/4] added more tests --- .../FileSystem.Tests.ps1 | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 index 46e7ce678b1..afe6aa0d858 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1 @@ -200,21 +200,41 @@ Describe "Basic FileSystem Provider Tests" -Tags "CI" { } } - It "Set-Location on Unix succeeds with folder with colon" -Skip:($IsWindows) { - New-Item -Path "$testdrive\hello:world" -ItemType Directory > $null - Set-Location "$testdrive" - Set-Location ".\hello:world" - (Get-Location).Path | Should Be "$testdrive/hello:world" + It "Set-Location on Unix succeeds with folder with colon: " -Skip:($IsWindows) -TestCases @( + @{path="\hello:world"}, + @{path="\:world"}, + @{path="/hello:"} + ) { + param($path) + try { + New-Item -Path "$testdrive$path" -ItemType Directory > $null + Set-Location "$testdrive" + Set-Location ".$path" + (Get-Location).Path | Should Be "$testdrive/$($path.Substring(1,$path.Length-1))" + } + finally { + Remove-Item -Path "$testdrive$path" -ErrorAction SilentlyContinue + } } - It "Get-Content on Unix succeeds with folder and file with colon" -Skip:($IsWindows) { - $testPath = "$testdrive/hello:world" - New-Item -Path $testPath -ItemType Directory > $null - Set-Content -Path "$testPath\foo:bar.txt" -Value "Hello" - $files = Get-ChildItem "$testPath" - $files.Count | Should Be 1 - $files[0].Name | Should BeExactly "foo:bar.txt" - $files[0] | Get-Content | Should BeExactly "Hello" + It "Get-Content on Unix succeeds with folder and file with colon: " -Skip:($IsWindows) -TestCases @( + @{path="\foo:bar.txt"}, + @{path="/foo:"}, + @{path="\:bar"} + ) { + param($path) + try { + $testPath = "$testdrive/hello:world" + New-Item -Path "$testPath" -ItemType Directory > $null + Set-Content -Path "$testPath$path" -Value "Hello" + $files = Get-ChildItem "$testPath" + $files.Count | Should Be 1 + $files[0].Name | Should BeExactly $path.Substring(1,$path.Length-1) + $files[0] | Get-Content | Should BeExactly "Hello" + } + finally { + Remove-Item -Path $testPath -Recurse -Force -ErrorAction SilentlyContinue + } } }