-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Fix Move-Item for FileSystemProvider to use copy-delete instead of move for DFS paths
#14913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…move for UNC paths
|
Going to change this to try Move() first, then if AccessDenied, then try CopyDelete(). |
src/System.Management.Automation/namespaces/FileSystemProvider.cs
Outdated
Show resolved
Hide resolved
|
Making this a draft PR for now, the customer tried a private and still had initial problem after latest change. Trying to determine if they got a different HResult. |
|
Looking Directory.MoveTo() implementation https://github.com/dotnet/runtime/blob/79ae74f5ca5c8a6fe3a48935e85bd7374959c570/src/libraries/System.IO.FileSystem/src/System/IO/FileSystem.Windows.cs#L119-L137 |
|
@iSazonov Looks like there can be different HResult for DFS, so can't rely on that. Based on https://github.com/dotnet/runtime/blob/79ae74f5ca5c8a6fe3a48935e85bd7374959c570/src/libraries/System.IO.FileSystem/src/System/IO/FileSystem.Windows.cs#L133, I think we can just try copydelete on an IOException. |
|
If we look GetExceptionForWin32Error()
|
|
@iSazonov I see, that makes sense, will update. |
|
Need to think about this some more, the FQErrorID is now different on Linux vs Windows which is not acceptable. Maybe I can find out if there is a limited set of HResult we can check against. |
|
We already discussed this with @rjmholt . See https://github.com/PowerShell/PowerShell/pull/13044/files#r446770600 I guess .Net unify the behavior (exceptions) and we can have one code path for all platforms. I see the test
|
…nied for Windows to use CopyAndDelete()
|
@iSazonov can you be specific on your concerns about that test? |
I'd expect And I guess .Net team unified exceptions in the API for all platforms and we could have one code path here. Both return codes fall in IOException and we need only to ignore FileNotFoundException, DirectoryNotFoundException, PathTooLongException. We must take into account that there are many ways to mount a different file system / volume and they may have different return codes. |
|
@iSazonov so that test case relies on a testhook to simulate doing a move across devices/volumes. It succeeds because the test hook forces it to throw the exception that results in CopyAndDelete() to be used. In one of my commits, I tried the approach of ignoring FileNotFoundException, DirectoryNotFoundException, PathTooLongException but that resulted in another FullyQualifiedErrorId to change whereas the current implementation checking for specific HResult which is specific to the Unix error of moving across devices and Windows error of moving across volumes has less impact. I was also concerned that other specific IOExceptions beyond those ignored types would fallback to CopyAndDelete() when it didn't in the past and might cause unintended side effects. |
Sorry, my bad. With
We had similar discussion in #13634 (comment) My proposal: private void MoveDirectoryInfoUnchecked(DirectoryInfo directory, string destinationPath, bool force)
{
try
{
if (InternalTestHooks.ThrowExdevErrorOnMoveDirectory)
{
throw new IOException("Invalid cross-device link", hresult: TEST_CODE);
}
directory.MoveTo(destinationPath);
}
catch (Exception exception)
{
switch (exception)
{
case FileNotFoundException:
case DirectoryNotFoundException:
case PathTooLongException:
throw;
case IOException:
CopyAndDelete(directory, destinationPath, force);
break;
default:
throw;
}
}
} |
anmenaga
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the current implementation checking for specific HResult which is specific to the Unix error of moving across devices and Windows error of moving across volumes has less impact. I was also concerned that other specific IOExceptions beyond those ignored types would fallback to CopyAndDelete() when it didn't in the past and might cause unintended side effects.
I agree with this.
|
🎉 Handy links: |
PR Summary
When using
Move-Itembetween DFS paths, the FileSystemProvider will decide whether to use the .NETMove()or aCopy()andDelete()operation based on comparing the root path of the source and destination. This will work whenever the source and destination are on the same volume, but results in an Access Denied error message if not. In the case of DFS paths, they look like SMB share paths but typically are on different volumes so the move fails with Access Denied.There is a Win32 API that could be used to determine if a UNC path is DFS, but it appears there is a timeout of around 1 second when the path is NOT DFS, so that's too big of an impact for normal usage.
Fix is to try
MoveTo()as that is much faster on the same volume. If that fails, we check the HResult to see if it's Access Denied (0x80070005) and if so (as this is what is returned in DFS scenario) we fallback toCopyAndDelete().Tested manually on a VM with DFS shares.
PR Context
Reported through Microsoft customer support
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:or[ WIP ]to the beginning of the title (theWIPbot will keep its status check atPendingwhile the prefix is present) and remove the prefix when the PR is ready.(which runs in a different PS Host).