-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
System.IO.Directory.Delete should check for the name surrogate bit on reparse tags before deciding if it should enumerate directories with reparse points #23646
Comments
@danmosemsft Another fungible one that needs to be done. |
existing code // Reparse point, don't recurse, just remove. (dwReserved0 is documented for this flag)
if (findData.dwReserved0 == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT)
{
// Mount point. Unmount using full path plus a trailing '\'.
// (Note: This doesn't remove the underlying directory)
...
if (!Interop.Kernel32.DeleteVolumeMountPoint(mountPoint) && exception == null)
{
...
}
} This seems wrong in the first place because MSDN says we should first check for FILE_ATTRIBUTE_REPARSE_POINT and we're not.
It looks like the IsReparseTagNameSurrogate behavior is sufficiently documented for us to use. So it seems we should add a check for FILE_ATTRIBUTE_REPARSE_POINT. If it is true then check for IsReparseTagNameSurrogate (the 29th bit, so just Is that correct @JeremyKuhne ? If I understand correctly these directory placeholders are not name surrogates and we are expected to enumerate through them. |
@maryamariyan another one for you I think. |
@danmosemsft We do check above the code you mentioned: The answer is, yes, we need to check the flag on any reparse point and just delete (without recursing) if it is a name surrogate. Note that we do another check for reparse point status at the top level entry point for directory deletion. |
@maryamariyan not sure how you'd test this, perhaps a little pinvoking to make a temporary reparse point of each flavor. |
I don't think we can create any of the non-surrogate type outside of OneDrive folders, which you'd have to set up and manually test. Hard and symbolic links are the only ones I know how to create programmatically and they are surrogates. You might want to contact Christian Allred (mentioned above) to see if they have any suggestions. |
@maryamariyan I spoke with @danmosemsft- I'm going to take this back as we want to get the change into the system soon. |
…ative Win32 APIs on Windows: svn_io_check_path() svn_io_check_resolved_path() svn_io_check_special_path() This changeset aims for two distinct things: 1) First of all, starting from r1833621, these functions were patched to stop checking symlinks on Windows. The root cause for this change has been an incorrect implementation of stat in APR that didn't properly distinguish between various types of reparse points, some of which are not symlinks. Providing the custom implementation allows us to remove the hack and properly handle such reparse points irrespectively of the APR version in use. Additional details on the core of the issue can be found here: - golang/go#23684 - https://github.com/dotnet/corefx/issues/24250 2) These APIs are used in various performance-critical code paths such as in the core part of `svn st`. On Win32 the necessary answers for these particular functions can be obtained with a single call to GetFileAttributes(), which is much faster than using the generic stat implementations from APR 1.6.x and 1.7.x (I believe that it would be even slower in the latter case). A couple of quick tests show about 20%-25% improvement in the speed of `svn st` for a large working copy. The improvement may be more significant with indexers or virus scanners, as just asking for file attributes may completely avoid opening a file (by retrieving the result through the fast I/O QueryOpen). * subversion/libsvn_subr/io.c (FILE_ATTRIBUTE_TAG_INFO, FileAttributeTagInfo): Add these definitions for old versions of Windows SDK. (typedef GetFileInformationByHandleEx_t, get_file_information_by_handle_ex_proc): New. (win_init_dynamic_imports): Import `GetFileInformationByHandleEx()`. (win32_get_file_information_by_handle): New helper function. (io_win_check_path): New helper with the Win32 implementation required for the "check path" functions. (svn_io_check_path, svn_io_check_resolved_path, svn_io_check_special_path): Invoke the new helper. (io_check_path): Undo the workaround from r1833621 that stopped passing APR_FINFO_LINK when performing a stat. git-svn-id: https://svn.apache.org/repos/asf/subversion/trunk@1859732 13f79535-47bb-0310-9956-ffa450edef68
Copied from internal bug 402782
System.IO.Directory.Delete recursive delete will not recurse through directory placeholders as it should (directory placeholders are a feature of GvFlt and the
container filter).
Christian Allred [callred] found that the Delete code "will avoid trying to enumerate directories that are any kind of reparse point, rather than just name surrogates ... It should be fixed to check for the name surrogate bit on the reparse tag, same as rmdir /s does"
See: http://ddindex/?rightProject=mscorlib&file=system%5cio%5cdirectory.cs&line=1324)
rmdir code
...
Rmdir /s checks the name surrogate bit using IsReparseTagNameSurrogate, which is in ntifs.h. It is defined as:
#define IsReparseTagNameSurrogate(_tag) (
((_tag) & 0x20000000)
)
If you're doing a FindFirst/FindNext, the _tag value is the dwReserved0 field of the WIN32_FIND_DATA structure. That is how rmdir /s does its check:
...
Forgot to mention, the name surrogate bit is set on directory junctions, symlinks, etc. So having this check correctly identifies other types of reparse points that a recursive delete would not want to recurse in to.
The text was updated successfully, but these errors were encountered: