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, mliska, paul.moore, steve.dower, tim.golden, zach.ware
Date 2017-12-29.08:43:18
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1514536999.38.0.213398074469.issue32434@psf.upfronthosting.co.za>
In-reply-to
Content
resolve() has additional problems, which possibly could be addressed all at once because it's a small method and the problems are closely related.

For an empty path it returns os.getcwd(). I don't think this case is possible in the normal way a Path gets constructed. Anyway, returning the unresolved working directory is incorrect. Windows is not a POSIX OS. WinAPI [Set,Get]CurrentDirectory does not ensure the working directory is a resolved path. An empty path should be replaced with "." and processed normally.

It fails when access is denied. _getfinalpathname needs to open a handle, and CreateFile requires at least the right to read file attributes and synchronize. For example, resolve() fails for a path in another user's profile, which grants access only to the user, system, and administrators.

It doesn't keep the "\\\\?\\" extended-path prefix when the source path already has it. It should only strip the prefix if the source path doesn't have it. That said, the resolved path may actually require it (i.e. long paths, DOS device names, trailing spaces), so maybe it should  never be removed.

Its behavior is inconsistent for invalid paths. For example, if "C:/Temp" exists and "C:/Spam" does not, then resolving "C:/Temp/bad?" raises whereas "C:/Spam/bad?" does not. IMO, it's simpler if neither raises in non-strict mode, at least not in _WindowsFlavour.resolve. Malformed paths will slip through, but raising an exception in those cases should be the job of the constructor. 

It fails to handle device paths. For example, C:/Temp/nul" resolves to the "NUL" device if "C:/Temp" exists. In this case _getfinalpathname will typically fail, either due to an invalid function or an invalid parameter. These errors, along with the error for an invalid filename, get lumped into the CRT's default EINVAL error code.

Also, GetFinalPathNameByHandle was added in Vista, so _getfinalpathname is always available in 3.5+. There's no need to use it conditionally.

Here's a prototype that addresses these issues:

    import nt
    import os
    import errno

    def _is_extended(path):
        return path.startswith('\\\\?\\')

    def _extended_to_normal(path):
        if _is_extended(path):
            path = path[4:]
            if path.startswith('UNC\\'):
                path = '\\' + path[3:]
        return path

    def _getfinalpathname(path):
        if not path:
            path = '.'
        elif _is_extended(path):
            return nt._getfinalpathname(path)
        return _extended_to_normal(nt._getfinalpathname(path))

    def resolve(path, strict=False):
        s = str(path)
        if strict:
            return _getfinalpathname(s)
        # Non-strict mode resolves as much as possible while retaining
        # tail components that cannot be resolved if they're missing,
        # inaccessible, or invalid.
        tail_parts = []
        while True:
            try:
                s = _getfinalpathname(s)
                break
            except OSError as e:
                if not (isinstance(e, (FileNotFoundError, PermissionError)) or
                        e.errno == errno.EINVAL):
                    raise
            head, tail = os.path.split(s)
            if head == s:
                return path.absolute()
            s = head
            tail_parts.append(tail)
        if tail_parts:
            s = os.path.join(s, *reversed(tail_parts))
        return s
History
Date User Action Args
2017-12-29 08:43:19eryksunsetrecipients: + eryksun, paul.moore, tim.golden, zach.ware, steve.dower, mliska
2017-12-29 08:43:19eryksunsetmessageid: <1514536999.38.0.213398074469.issue32434@psf.upfronthosting.co.za>
2017-12-29 08:43:19eryksunlinkissue32434 messages
2017-12-29 08:43:18eryksuncreate