Skip to content

Conversation

@SteveL-MSFT
Copy link
Member

@SteveL-MSFT SteveL-MSFT commented Feb 20, 2021

PR Summary

The FileSystemProvider treats all reparsepoints as symlinks (files) so that trying to recursively remove a directory from OneDrive fails as it won't recurse and thus fails because the directory is not empty. Fix is to don't treat reparse points as files if it is also a directory and also pass the recurse flag to the Directory.Remove() overload only if -Force is specified.

The breaking change behavior is that if you use -Recurse -Force -Confirm then it will now only confirm the top level folder before removing compared to the previous behavior (for a non-Onedrive folder) which prompts to confirm for every item within the folder.

Manually validated that removing nested non-empty folder on OneDrive works and also removing a directory symlink removes the symlink and not the target.

PR Context

Fix #9246

PR Checklist

Copy link
Collaborator

@iSazonov iSazonov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description does more confuse then explain. :-)

{
System.IO.DirectoryInfo di = new(providerPath);
if (di != null && (di.Attributes & System.IO.FileAttributes.ReparsePoint) != 0)
if (di != null && di.Attributes.HasFlag(System.IO.FileAttributes.ReparsePoint) && (di.Attributes.HasFlag(System.IO.FileAttributes.Directory) && !shouldRecurse))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why do we need the code at all if now FileSystemProvider correctly process all cases? (We can remove the code block from line 2696 to line 2713.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code was added to make remove-item -literalpath * work for Registry provider. I'll add to the comment.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registry provider? In line 2697 we check FileSystemProvider.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code is relying on DirectoryInfo class to determine if the path is a directory and this would only work with FileSystemProvider so this code is skipped for other providers (like Registry Provider where it would fail). The way to think about this is if the path is FileSystemProvider path and a Directory, we do additional checks like reparse point to determine if the item should be treated as a file or not. For other providers, these API calls would fail so they are skipped.

// but the .NET API here does not allow us to distinguish them.
// We may need to revisit using p/Invokes here to get the right behavior
directory.Delete();
directory.Delete(recursive: recurse);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a comment that the API correctly works with non named surrogates like a directory on OneDrive. This could help code readers to understand the code path more deeply.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, will add a comment why this is needed.

@iSazonov iSazonov added the CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log label Feb 22, 2021
@SteveL-MSFT SteveL-MSFT added Breaking-Change breaking change that may affect users Review - Committee The PR/Issue needs a review from the PowerShell Committee labels Feb 22, 2021
@SteveL-MSFT
Copy link
Member Author

@PowerShell/powershell-committee reviewed this, there is a concern regarding breaking existing confirm behavior which prompts for every item, but ok with a minor break if -Force is specified. Also a concern with side effects with other reparse point types so suggestion was to wrap this as an experimental feature

@SteveL-MSFT SteveL-MSFT added Committee-Reviewed PS-Committee has reviewed this and made a decision and removed Review - Committee The PR/Issue needs a review from the PowerShell Committee labels Feb 23, 2021
@iSazonov
Copy link
Collaborator

This is that rare case when several problems intersected in one place and everyone was confused. :-)

Compare:
image
and
image

The screenshots explicitly say that there was a bug in .Net 3. Now the bug is fixed in .Net 5.0.
So we can close #9246 as external and fixed in .Net 5.0 (PowerShell 7.1).


How we work with OneDrive it is another issue.
Previously we enhanced how we enumerate a file system to support OneDrive (and AppExecLink too). It was in IsReparsePointWithTarget() method.
More later discussion with @rjmholt is in #11331

I think current fix is not right - we should change a behavior only for non-named surrogates - and this can not be a breaking change - it should be classified as new behavior or bug fix.

Right fix is to use IsReparsePointWithTarget() and get the same behavior for OneDrive as for regular directory.

@SteveL-MSFT
Copy link
Member Author

@iSazonov do you want to submit a new PR based on your proposal and I'll close this one?

@iSazonov
Copy link
Collaborator

@SteveL-MSFT Will do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Breaking-Change breaking change that may affect users CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log Committee-Reviewed PS-Committee has reviewed this and made a decision

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6.2.0-rc.1 Remove-Item -Recurse broken for reparse points

3 participants