Fix regression in Move-Item to only fallback to CopyAndDelete in specific cases (#16029)

If Move fails, check if known case before attempting CopyAndDelete:

- if an item is attempted to be renamed across filesystem mount boundaries.
- if the source and destination do not have the same root path.
This commit is contained in:
Steve Lee
2021-09-15 11:11:20 -07:00
committed by Aditya Patwardhan
parent 6ebc95e5dd
commit 7c9bf378f0
2 changed files with 24 additions and 3 deletions
@@ -6121,7 +6121,16 @@ namespace Microsoft.PowerShell.Commands
directory.MoveTo(destinationPath);
}
catch (IOException)
#if UNIX
// This is the errno returned by the rename() syscall
// when an item is attempted to be renamed across filesystem mount boundaries.
// 0x80131620 is returned if the source and destination do not have the same root path
catch (IOException e) when (e.HResult == 18 || e.HResult == -2146232800)
#else
// 0x80070005 ACCESS_DENIED is returned when trying to move files across volumes like DFS
// 0x80131620 is returned if the source and destination do not have the same root path
catch (IOException e) when (e.HResult == -2147024891 || e.HResult == -2146232800)
#endif
{
// Rather than try to ascertain whether we can rename a directory ahead of time,
// it's both faster and more correct to try to rename it and fall back to copy/deleting it
@@ -170,11 +170,23 @@ Describe "Basic FileSystem Provider Tests" -Tags "CI" {
}
It "Verify Move-Item will not move to an existing file" {
{ Move-Item -Path $testDir -Destination $testFile -ErrorAction Stop } | Should -Throw -ErrorId 'DirectoryExist,Microsoft.PowerShell.Commands.MoveItemCommand'
$error[0].Exception | Should -BeOfType System.IO.IOException
if ($IsWindows) {
$expectedError = 'MoveDirectoryItemIOError,Microsoft.PowerShell.Commands.MoveItemCommand'
}
else {
$expectedError = 'DirectoryExist,Microsoft.PowerShell.Commands.MoveItemCommand'
}
$e = { Move-Item -Path $testDir -Destination $testFile -ErrorAction Stop } | Should -Throw -ErrorId $expectedError -PassThru
$e.Exception | Should -BeOfType System.IO.IOException
$testDir | Should -Exist
}
It 'Verify Move-Item fails for non-existing destination path' {
$e = { Move-Item -Path $testDir -Destination TestDrive:/0/2/0 -ErrorAction Stop } | Should -Throw -ErrorId 'MoveDirectoryItemIOError,Microsoft.PowerShell.Commands.MoveItemCommand' -PassThru
$e.Exception | Should -BeOfType System.IO.IOException
}
It "Verify Move-Item throws correct error for non-existent source" {
{ Move-Item -Path /does/not/exist -Destination $testFile -ErrorAction Stop } | Should -Throw -ErrorId 'PathNotFound,Microsoft.PowerShell.Commands.MoveItemCommand'
}