From b101d523346abebc2d2a9ef6e230f544d7c11eb7 Mon Sep 17 00:00:00 2001 From: Matthew Bobke Date: Sun, 8 Apr 2018 22:14:49 -0700 Subject: [PATCH 1/9] Fix for files/folders not created when given path is drive root (#5228) [Feature] Checks to see if the root of a PSDrive was given as the Path argument to a parameter that supports it. If so, returns the current context's Drive's Root. --- .../namespaces/LocationGlobber.cs | 32 ++++++++++++++---- .../New-Item.Tests.ps1 | 33 ++++++++++++++++++- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/src/System.Management.Automation/namespaces/LocationGlobber.cs b/src/System.Management.Automation/namespaces/LocationGlobber.cs index 584e2d904c2..daff55a468c 100644 --- a/src/System.Management.Automation/namespaces/LocationGlobber.cs +++ b/src/System.Management.Automation/namespaces/LocationGlobber.cs @@ -2013,6 +2013,9 @@ internal string GetDriveRootRelativePathFromPSPath( // Check to see if the path is relative or absolute bool isPathForCurrentDrive = false; + // Check to see if the path is to the root of a drive + bool isPathForRootOfDrive = false; + if (IsAbsolutePath(path, out driveName)) { Dbg.Diagnostics.Assert( @@ -2080,6 +2083,12 @@ internal string GetDriveRootRelativePathFromPSPath( // this is the default behavior for all windows drives, and all non-filesystem // drives on non-windows path = path.Substring(driveName.Length + 1); + + if (String.IsNullOrEmpty(path)) + { + // path was to the root of a drive such as 'c:' + isPathForRootOfDrive = true; + } } } } @@ -2111,14 +2120,23 @@ internal string GetDriveRootRelativePathFromPSPath( // have access to it. context.Drive = workingDriveForPath; - string relativePath = - GenerateRelativePath( - workingDriveForPath, - path, - escapeCurrentLocation, - providerInstance, - context); + string relativePath = String.Empty; + if (isPathForRootOfDrive) + { + relativePath = context.Drive.Root; + } + else + { + relativePath = + GenerateRelativePath( + workingDriveForPath, + path, + escapeCurrentLocation, + providerInstance, + context); + } + return relativePath; } catch (PSNotSupportedException) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 index 5ec37f99cfa..34b1672ce96 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 @@ -117,6 +117,37 @@ Describe "New-Item" -Tags "CI" { $fileInfo.Target | Should -BeNullOrEmpty $fileInfo.LinkType | Should -BeExactly "HardLink" } + + It "Should create a file at the root of the drive while the current working directory is not the root" { + try { + Push-Location -Path "TestDrive:\" + New-Item -Name $testfolder -Path "TestDrive:\" -ItemType directory > $null + Push-Location -Path "TestDrive:\$testfolder" + New-Item -Name $testfile -Path "TestDrive:\" -ItemType file > $null + $FullyQualifiedFile | Should -Exist + } + finally { + Pop-Location + Pop-Location + } + } + + It "Should create a folder at the root of the drive while the current working directory is not the root" { + $testfolder2 = "newDirectory2" + $FullyQualifiedFolder2 = Join-Path -Path $tmpDirectory -ChildPath $testfolder2 + + try { + Push-Location -Path "TestDrive:\" + New-Item -Name $testfolder -Path "TestDrive:\" -ItemType directory > $null + Push-Location -Path "TestDrive:\$testfolder" + New-Item -Name $testfolder2 -Path "TestDrive:\" -ItemType directory > $null + $FullyQualifiedFolder2 | Should -Exist + } + finally { + Pop-Location + Pop-Location + } + } } # More precisely these tests require SeCreateSymbolicLinkPrivilege. @@ -186,7 +217,7 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') { } It "New-Item -ItemType SymbolicLink should understand directory path ending with slash" { - $folderName = [System.IO.Path]::GetRandomFileName() + $folderName = [System.IO.Path]::GetRandomFileName() $symbolicLinkPath = New-Item -ItemType SymbolicLink -Path "$tmpDirectory/$folderName/" -Value "/bar/" $symbolicLinkPath | Should -Not -BeNullOrEmpty } From c8cef800d4f7fedd94a64c019b4d306ad770d3fe Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 24 Apr 2018 16:51:38 -0700 Subject: [PATCH 2/9] [Feature] Remove unneeded push/pop-location --- .../Microsoft.PowerShell.Management/New-Item.Tests.ps1 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 index 34b1672ce96..0b3453b8f8a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 @@ -120,7 +120,6 @@ Describe "New-Item" -Tags "CI" { It "Should create a file at the root of the drive while the current working directory is not the root" { try { - Push-Location -Path "TestDrive:\" New-Item -Name $testfolder -Path "TestDrive:\" -ItemType directory > $null Push-Location -Path "TestDrive:\$testfolder" New-Item -Name $testfile -Path "TestDrive:\" -ItemType file > $null @@ -128,7 +127,6 @@ Describe "New-Item" -Tags "CI" { } finally { Pop-Location - Pop-Location } } @@ -137,7 +135,6 @@ Describe "New-Item" -Tags "CI" { $FullyQualifiedFolder2 = Join-Path -Path $tmpDirectory -ChildPath $testfolder2 try { - Push-Location -Path "TestDrive:\" New-Item -Name $testfolder -Path "TestDrive:\" -ItemType directory > $null Push-Location -Path "TestDrive:\$testfolder" New-Item -Name $testfolder2 -Path "TestDrive:\" -ItemType directory > $null @@ -145,7 +142,6 @@ Describe "New-Item" -Tags "CI" { } finally { Pop-Location - Pop-Location } } } From 4488c63238f50d8fbe82995b90fa1d5a14afa91e Mon Sep 17 00:00:00 2001 From: Matthew Bobke Date: Sun, 29 Apr 2018 03:07:54 -0700 Subject: [PATCH 3/9] [Feature] Change path to absolute path to drive's current location If given path is a colon-terminated drive --- .../engine/SessionStateLocationAPIs.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs index e304d2d219f..c62e2e2268a 100644 --- a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs @@ -266,6 +266,16 @@ internal PathInfo SetLocation(string path, CmdletProviderContext context) PSDriveInfo newWorkingDrive = GetDrive(driveName); CurrentDrive = newWorkingDrive; + // If the path is simply a colon-terminated drive, + // not a slash-terminated path to the root of a drive, + // set the path to the current working directory of that drive. + + string colonTerminatedVolume = CurrentDrive.Name + ':'; + if (CurrentDrive.VolumeSeparatedByColon && (path.Length == colonTerminatedVolume.Length)) + { + path = CurrentDrive.Root + CurrentDrive.CurrentLocation; + } + // Now that the current working drive is set, // process the rest of the path as a relative path. } From 669af06b45c0b13a3bb571e0650cdf46abc78e50 Mon Sep 17 00:00:00 2001 From: Matthew Bobke Date: Mon, 30 Apr 2018 00:04:39 -0700 Subject: [PATCH 4/9] [Feature] Initial test written --- .../Set-Location.Tests.ps1 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 index 2d297a84485..354cd93cbfa 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 @@ -67,4 +67,19 @@ Describe "Set-Location" -Tags "CI" { (Get-Location).Path | Should -BeExactly (Get-PSProvider FileSystem).Home } } + + It "Should set location to new drive's current working directory when path is the colon-terminated name of a different drive" { + Set-Location 'TestDrive:\' + New-Item -Path '.' -Name 'Directory1' -ItemType Directory + New-PSDrive -Name 'Z' -PSProvider FileSystem -Root 'TestDrive:\Directory1' + New-Item -Path 'Z:\' -Name 'Directory2' -ItemType Directory + + Set-Location '.\Directory1' + Set-Location 'Z:\Directory2' + + Set-Location 'TestDrive:' + (Get-Location).Path | Should -BeExactly 'TestDrive:\Directory1' + Set-LocalGroup 'Z:' + (Get-Location).Path | Should -BeExactly 'Z:\Directory2' + } } From 7818da827fab0ef07844b927d6f546cf13362577 Mon Sep 17 00:00:00 2001 From: Matthew Bobke Date: Mon, 30 Apr 2018 01:50:35 -0700 Subject: [PATCH 5/9] [Feature] Created test variables and using Path.Combine() --- .../engine/SessionStateLocationAPIs.cs | 3 ++- .../Set-Location.Tests.ps1 | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs index c62e2e2268a..d7f597f7879 100644 --- a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; +using System.IO; using System.Management.Automation.Provider; using Dbg = System.Management.Automation; @@ -273,7 +274,7 @@ internal PathInfo SetLocation(string path, CmdletProviderContext context) string colonTerminatedVolume = CurrentDrive.Name + ':'; if (CurrentDrive.VolumeSeparatedByColon && (path.Length == colonTerminatedVolume.Length)) { - path = CurrentDrive.Root + CurrentDrive.CurrentLocation; + path = Path.Combine((colonTerminatedVolume + "\\"), CurrentDrive.CurrentLocation); } // Now that the current working drive is set, diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 index 354cd93cbfa..7d83b17c9d8 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 @@ -75,11 +75,13 @@ Describe "Set-Location" -Tags "CI" { New-Item -Path 'Z:\' -Name 'Directory2' -ItemType Directory Set-Location '.\Directory1' + $pathToTest1 = (Get-Location).Path Set-Location 'Z:\Directory2' + $pathToTest2 = (Get-Location).Path Set-Location 'TestDrive:' - (Get-Location).Path | Should -BeExactly 'TestDrive:\Directory1' - Set-LocalGroup 'Z:' - (Get-Location).Path | Should -BeExactly 'Z:\Directory2' + (Get-Location).Path | Should -BeExactly $pathToTest1 + Set-Location 'Z:' + (Get-Location).Path | Should -BeExactly $pathToTest2 } } From 594eacf2748ef238144a5cdce262f43716d51c1f Mon Sep 17 00:00:00 2001 From: Matthew Bobke Date: Mon, 30 Apr 2018 09:15:43 -0700 Subject: [PATCH 6/9] [Feature] Wrapped test in try/finally and ensured drive removal --- .../Set-Location.Tests.ps1 | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 index 7d83b17c9d8..489f8990bfa 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 @@ -69,19 +69,27 @@ Describe "Set-Location" -Tags "CI" { } It "Should set location to new drive's current working directory when path is the colon-terminated name of a different drive" { - Set-Location 'TestDrive:\' - New-Item -Path '.' -Name 'Directory1' -ItemType Directory - New-PSDrive -Name 'Z' -PSProvider FileSystem -Root 'TestDrive:\Directory1' - New-Item -Path 'Z:\' -Name 'Directory2' -ItemType Directory - - Set-Location '.\Directory1' - $pathToTest1 = (Get-Location).Path - Set-Location 'Z:\Directory2' - $pathToTest2 = (Get-Location).Path - - Set-Location 'TestDrive:' - (Get-Location).Path | Should -BeExactly $pathToTest1 - Set-Location 'Z:' - (Get-Location).Path | Should -BeExactly $pathToTest2 + try + { + Set-Location 'TestDrive:\' + New-Item -Path 'TestDrive:\' -Name 'Directory1' -ItemType Directory + New-PSDrive -Name 'Z' -PSProvider FileSystem -Root 'TestDrive:\Directory1' + New-Item -Path 'Z:\' -Name 'Directory2' -ItemType Directory + + Set-Location 'TestDrive:\Directory1' + $pathToTest1 = (Get-Location).Path + Set-Location 'Z:\Directory2' + $pathToTest2 = (Get-Location).Path + + Set-Location 'TestDrive:' + (Get-Location).Path | Should -BeExactly $pathToTest1 + Set-Location 'Z:' + (Get-Location).Path | Should -BeExactly $pathToTest2 + } + finally + { + Set-Location 'TestDrive:\' + Remove-PSDrive -Name 'Z' + } } } From 578494db91cc4557e2e9d54c740e4edc89756973 Mon Sep 17 00:00:00 2001 From: Matthew Bobke Date: Thu, 3 May 2018 02:07:38 -0700 Subject: [PATCH 7/9] [Feature] Restore original location regardless of test failure --- .../Microsoft.PowerShell.Management/Set-Location.Tests.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 index 489f8990bfa..74f59ffa60c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Set-Location.Tests.ps1 @@ -71,6 +71,7 @@ Describe "Set-Location" -Tags "CI" { It "Should set location to new drive's current working directory when path is the colon-terminated name of a different drive" { try { + $oldLocation = Get-Location Set-Location 'TestDrive:\' New-Item -Path 'TestDrive:\' -Name 'Directory1' -ItemType Directory New-PSDrive -Name 'Z' -PSProvider FileSystem -Root 'TestDrive:\Directory1' @@ -88,7 +89,7 @@ Describe "Set-Location" -Tags "CI" { } finally { - Set-Location 'TestDrive:\' + Set-Location $oldLocation Remove-PSDrive -Name 'Z' } } From 9697c0221f1b28aec193f83eaaf8c548d0ed6d90 Mon Sep 17 00:00:00 2001 From: Matthew Bobke Date: Sat, 12 May 2018 02:54:50 -0700 Subject: [PATCH 8/9] [Feature] Removed newlines to avoid floating comments --- .../engine/SessionStateLocationAPIs.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs index d7f597f7879..5c7233fc5c5 100644 --- a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs @@ -263,14 +263,12 @@ internal PathInfo SetLocation(string path, CmdletProviderContext context) // Since the path is an absolute path // we need to change the current working // drive - PSDriveInfo newWorkingDrive = GetDrive(driveName); CurrentDrive = newWorkingDrive; // If the path is simply a colon-terminated drive, // not a slash-terminated path to the root of a drive, // set the path to the current working directory of that drive. - string colonTerminatedVolume = CurrentDrive.Name + ':'; if (CurrentDrive.VolumeSeparatedByColon && (path.Length == colonTerminatedVolume.Length)) { From 1c4b2ca5b015503daacb31a297e524a94f555024 Mon Sep 17 00:00:00 2001 From: Matthew Bobke Date: Wed, 16 May 2018 01:05:03 -0700 Subject: [PATCH 9/9] [Feature] Using Path.DirectorySeparatorChar in place of '\\' --- .../engine/SessionStateLocationAPIs.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs index 5c7233fc5c5..c05460c3bbd 100644 --- a/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateLocationAPIs.cs @@ -272,7 +272,7 @@ internal PathInfo SetLocation(string path, CmdletProviderContext context) string colonTerminatedVolume = CurrentDrive.Name + ':'; if (CurrentDrive.VolumeSeparatedByColon && (path.Length == colonTerminatedVolume.Length)) { - path = Path.Combine((colonTerminatedVolume + "\\"), CurrentDrive.CurrentLocation); + path = Path.Combine((colonTerminatedVolume + Path.DirectorySeparatorChar), CurrentDrive.CurrentLocation); } // Now that the current working drive is set,