bpo-37834: Normalise handling of reparse points on Windows (GH-15231)

bpo-37834: Normalise handling of reparse points on Windows
* ntpath.realpath() and nt.stat() will traverse all supported reparse points (previously was mixed)
* nt.lstat() will let the OS traverse reparse points that are not name surrogates (previously would not traverse any reparse point)
* nt.[l]stat() will only set S_IFLNK for symlinks (previous behaviour)
* nt.readlink() will read destinations for symlinks and junction points only

bpo-1311: os.path.exists('nul') now returns True on Windows
* nt.stat('nul').st_mode is now S_IFCHR (previously was an error)
This commit is contained in:
Steve Dower 2019-08-21 15:27:33 -07:00 committed by GitHub
parent bcc446f525
commit df2d4a6f3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 477 additions and 240 deletions

View file

@ -1858,6 +1858,12 @@ features:
.. versionchanged:: 3.6
Accepts a :term:`path-like object` for *src* and *dst*.
.. versionchanged:: 3.8
On Windows, now opens reparse points that represent another path
(name surrogates), including symbolic links and directory junctions.
Other kinds of reparse points are resolved by the operating system as
for :func:`~os.stat`.
.. function:: mkdir(path, mode=0o777, *, dir_fd=None)
@ -2039,6 +2045,10 @@ features:
This function can also support :ref:`paths relative to directory descriptors
<dir_fd>`.
When trying to resolve a path that may contain links, use
:func:`~os.path.realpath` to properly handle recursion and platform
differences.
.. availability:: Unix, Windows.
.. versionchanged:: 3.2
@ -2053,6 +2063,11 @@ features:
.. versionchanged:: 3.8
Accepts a :term:`path-like object` and a bytes object on Windows.
.. versionchanged:: 3.8
Added support for directory junctions, and changed to return the
substitution path (which typically includes ``\\?\`` prefix) rather
than the optional "print name" field that was previously returned.
.. function:: remove(path, *, dir_fd=None)
Remove (delete) the file *path*. If *path* is a directory, an
@ -2366,7 +2381,8 @@ features:
On Unix, this method always requires a system call. On Windows, it
only requires a system call if *follow_symlinks* is ``True`` and the
entry is a symbolic link.
entry is a reparse point (for example, a symbolic link or directory
junction).
On Windows, the ``st_ino``, ``st_dev`` and ``st_nlink`` attributes of the
:class:`stat_result` are always set to zero. Call :func:`os.stat` to
@ -2403,6 +2419,17 @@ features:
This function can support :ref:`specifying a file descriptor <path_fd>` and
:ref:`not following symlinks <follow_symlinks>`.
On Windows, passing ``follow_symlinks=False`` will disable following all
name-surrogate reparse points, which includes symlinks and directory
junctions. Other types of reparse points that do not resemble links or that
the operating system is unable to follow will be opened directly. When
following a chain of multiple links, this may result in the original link
being returned instead of the non-link that prevented full traversal. To
obtain stat results for the final path in this case, use the
:func:`os.path.realpath` function to resolve the path name as far as
possible and call :func:`lstat` on the result. This does not apply to
dangling symlinks or junction points, which will raise the usual exceptions.
.. index:: module: stat
Example::
@ -2427,6 +2454,14 @@ features:
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
.. versionchanged:: 3.8
On Windows, all reparse points that can be resolved by the operating
system are now followed, and passing ``follow_symlinks=False``
disables following all name surrogate reparse points. If the operating
system reaches a reparse point that it is not able to follow, *stat* now
returns the information for the original path as if
``follow_symlinks=False`` had been specified instead of raising an error.
.. class:: stat_result
@ -2578,7 +2613,7 @@ features:
File type.
On Windows systems, the following attribute is also available:
On Windows systems, the following attributes are also available:
.. attribute:: st_file_attributes
@ -2587,6 +2622,12 @@ features:
:c:func:`GetFileInformationByHandle`. See the ``FILE_ATTRIBUTE_*``
constants in the :mod:`stat` module.
.. attribute:: st_reparse_tag
When :attr:`st_file_attributes` has the ``FILE_ATTRIBUTE_REPARSE_POINT``
set, this field contains the tag identifying the type of reparse point.
See the ``IO_REPARSE_TAG_*`` constants in the :mod:`stat` module.
The standard module :mod:`stat` defines functions and constants that are
useful for extracting information from a :c:type:`stat` structure. (On
Windows, some items are filled with dummy values.)
@ -2614,6 +2655,14 @@ features:
.. versionadded:: 3.7
Added the :attr:`st_fstype` member to Solaris/derivatives.
.. versionadded:: 3.8
Added the :attr:`st_reparse_tag` member on Windows.
.. versionchanged:: 3.8
On Windows, the :attr:`st_mode` member now identifies special
files as :const:`S_IFCHR`, :const:`S_IFIFO` or :const:`S_IFBLK`
as appropriate.
.. function:: statvfs(path)
Perform a :c:func:`statvfs` system call on the given path. The return value is

View file

@ -304,6 +304,10 @@ Directory and files operations
Added a symlink attack resistant version that is used automatically
if platform supports fd-based functions.
.. versionchanged:: 3.8
On Windows, will no longer delete the contents of a directory junction
before removing the junction.
.. attribute:: rmtree.avoids_symlink_attacks
Indicates whether the current platform and implementation provides a

View file

@ -425,3 +425,13 @@ for more detail on the meaning of these constants.
FILE_ATTRIBUTE_VIRTUAL
.. versionadded:: 3.5
On Windows, the following constants are available for comparing against the
``st_reparse_tag`` member returned by :func:`os.lstat`. These are well-known
constants, but are not an exhaustive list.
.. data:: IO_REPARSE_TAG_SYMLINK
IO_REPARSE_TAG_MOUNT_POINT
IO_REPARSE_TAG_APPEXECLINK
.. versionadded:: 3.8