This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eryksun
Recipients eryksun, paul.moore, steve.dower, tim.golden, vidartf, zach.ware
Date 2019-08-09.18:44:41
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1565376281.54.0.588812248045.issue31226@roundup.psfhosted.org>
In-reply-to
Content
> Thanks for the detailed explanation Eryk. While it is a little 
> annoying that it comes 2 years after the initial proposed 
> solution, I'll happily take that if the end result is a better fix :)

Mea culpa. I am sorry about that. I do respect your time and the work you've invested into this issue. I'm guilty of procrastination here. Plus we're in murky waters, and I'm worried about getting it wrong -- again. A lot of misleading information has been published about filesystem junctions. And Microsoft's documentation on the subject of reparse points and the expected behavior of symlinks, junctions, and other "name surrogates" is too brief, incomplete or just wrong.

> this fix seems quite a bit more involved to implement than the 
> previous one.

I was painting a broad picture of what it might look if we had general support for "name surrogate" reparse points. I went out of my way to use conditional tense, with "could" and "would" used extensively. I wanted to get that part covered upfront to be able to present a generic alternative solution to the rmtree() problem before digressing into the subject of junction and symlink behavior.

For just this issue, we could use a local solution for Windows. One option would be to add an nt._getattrtaginfo function that calls CreateFileW and GetFileInformationByHandleEx: FileAttributeTagInfo, with a fallback to FindFirstFileW if that fails for a downlevel filesystem. Then wrap the os.scandir call with a function that checks for a name-surrogate tag. 

For example:

    if not _WINDOWS:
        _rmtree_unsafe_scandir = os.scandir
    else:
        import contextlib

        def _rmtree_unsafe_scandir(path):
            try:
                attr, tag = nt._getattrtaginfo(path)
            except OSError:
                attr = tag = 0
            if (attr & stat.FILE_ATTRIBUTE_DIRECTORY
                  and attr & stat.FILE_ATTRIBUTE_REPARSE_POINT
                  and tag & 0x2000_0000): # IsReparseTagNameSurrogate
                return contextlib.nullcontext([])
            else:
                return os.scandir(path)
History
Date User Action Args
2019-08-09 18:44:41eryksunsetrecipients: + eryksun, paul.moore, tim.golden, zach.ware, steve.dower, vidartf
2019-08-09 18:44:41eryksunsetmessageid: <1565376281.54.0.588812248045.issue31226@roundup.psfhosted.org>
2019-08-09 18:44:41eryksunlinkissue31226 messages
2019-08-09 18:44:41eryksuncreate