10000 Fallback to `CopyAndDelete()` when `MoveTo()` fails due to an `IOExce… · PowerShell/PowerShell@5d0dadf · GitHub
[go: up one dir, main page]

Skip to content

Commit 5d0dadf

Browse files
authored
Fallback to CopyAndDelete() when MoveTo() fails due to an IOException (#15077)
1 parent 177921e commit 5d0dadf

File tree

2 files changed

+32
-12
lines changed

2 files changed

+32
-12
lines changed

src/System.Management.Automation/namespaces/FileSystemProvider.cs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,6 @@ public sealed partial class FileSystemProvider : NavigationCmdletProvider,
5151
ISecurityDescriptorCmdletProvider,
5252
ICmdletProviderSupportsHelp
5353
{
54-
#if UNIX
55-
// This is the errno returned by the rename() syscall
56-
// when an item is attempted to be renamed across filesystem mount boundaries.
57-
private const int MOVE_FAILED_ERROR = 18;
58-
#else
59-
// 0x80070005 ACCESS_DENIED is returned when trying to move files across volumes like DFS
60-
private const int MOVE_FAILED_ERROR = -2147024891;
61-
#endif
62-
6354
// 4MB gives the best results without spiking the resources on the remote connection for file transfers between pssessions.
6455
// NOTE: The script used to copy file data from session (PSCopyFromSessionHelper) has a
6556
// maximum fragment size value for security. If FILETRANSFERSIZE changes make sure the
@@ -6078,12 +6069,12 @@ private void MoveDirectoryInfoUnchecked(DirectoryInfo directory, string destinat
60786069
{
60796070
if (InternalTestHooks.ThrowExdevErrorOnMoveDirectory)
60806071
{
6081-
throw new IOException("Invalid cross-device link", hresult: MOVE_FAILED_ERROR);
6072+
throw new IOException("Invalid cross-device link");
60826073
}
60836074

60846075
directory.MoveTo(destinationPath);
60856076
}
6086-
catch (IOException e) when (e.HResult == MOVE_FAILED_ERROR)
6077+
catch (IOException)
60876078
{
60886079
// Rather than try to ascertain whether we can rename a directory ahead of time,
60896080
// it's both faster and more correct to try to rename it and fall back to copy/deleting it

test/powershell/Modules/Microsoft.PowerShell.Management/FileSystem.Tests.ps1

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ Describe "Basic FileSystem Provider Tests" -Tags "CI" {
154154
}
155155

156156
It "Verify Move-Item will not move to an existing file" {
157-
{ Move-Item -Path $testDir -Destination $testFile -ErrorAction Stop } | Should -Throw -ErrorId "MoveDirectoryItemIOError,Microsoft.PowerShell.Commands.MoveItemCommand"
157+
{ Move-Item -Path $testDir -Destination $testFile -ErrorAction Stop } | Should -Throw -ErrorId 'DirectoryExist,Microsoft.PowerShell.Commands.MoveItemCommand'
158158
$error[0].Exception | Should -BeOfType System.IO.IOException
159159
$testDir | Should -Exist
160160
}
@@ -1500,3 +1500,32 @@ Describe "Verify sub-directory creation under root" -Tag 'CI','RequireSudoOnUnix
15001500
$dirPath | Should -Exist
15011501
}
15021502
}
1503+
1504+
Describe "Windows admin tests" -Tag 'RequireAdminOnWindows' {
1505+
It "Verify Move-Item for directory across drives on Windows" -Skip:(!$IsWindows) {
1506+
try {
1507+
# find first available drive letter, unfortunately need to use both function: and Win32_LogicalDisk to cover
1508+
# both subst drives and bitlocker drives
1509+
$drive = Get-ChildItem function:[h-z]: -Name | Where-Object { !(Test-Path -Path $_) -and !(Get-CimInstance Win32_LogicalDisk -Filter "DeviceID='$_'") } | Select-Object -First 1
1510+
if ($null -eq $drive) {
1511+
throw "Test cannot continue as no drive letter available"
1512+
}
1513+
1514+
$dest = (Resolve-Path -Path $TestDrive).ProviderPath
1515+
$null = New-Item -ItemType Directory -Path $dest -Name test
1516+
$out = subst $drive $dest 2>&1
1517+
if ($LASTEXITCODE -ne 0) {
1518+
throw "subst failed with exit code ${LASTEXITCODE} for drive '$drive': $out"
1519+
}
1520+
1521+
$testdir = New-Item -ItemType Directory -Path $drive -Name testmovedir -Force
1522+
1 > $testdir\test.txt
1523+
Move-Item $drive\testmovedir $dest\test
1524+
"$drive\testmovedir" | Should -Not -Exist
1525+
"$dest\test\testmovedir\test.txt" | Should -FileContentMatchExactly 1
1526+
}
1527+
finally {
1528+
subst $drive /d
1529+
}
1530+
}
1531+
}

0 commit comments

Comments
 (0)
0