Skip to content

Commit

Permalink
Fix regression in Move-Item to only fallback to CopyAndDelete in sp…
Browse files Browse the repository at this point in the history
…ecific cases (PowerShell#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.
  • Loading branch information
SteveL-MSFT committed Sep 8, 2021
1 parent 1e823e6 commit 5872e47
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6121,7 +6121,16 @@ private void MoveDirectoryInfoUnchecked(DirectoryInfo directory, string destinat

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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}
Expand Down

0 comments on commit 5872e47

Please sign in to comment.