summaryrefslogtreecommitdiffstats
path: root/Lib/pathlib/_os.py
diff options
context:
space:
mode:
authorBarney Gale <barney.gale@gmail.com>2024-07-03 03:30:29 (GMT)
committerGitHub <noreply@github.com>2024-07-03 03:30:29 (GMT)
commitf09d184821efd9438d092643881e28bdf8de4de5 (patch)
tree1aa17585a9a686154135ef1f9305c0a4a5984234 /Lib/pathlib/_os.py
parent089835469d5efbea4793cd611b43cb8387f2e7e5 (diff)
downloadcpython-f09d184821efd9438d092643881e28bdf8de4de5.zip
cpython-f09d184821efd9438d092643881e28bdf8de4de5.tar.gz
cpython-f09d184821efd9438d092643881e28bdf8de4de5.tar.bz2
GH-73991: Support copying directory symlinks on older Windows (#120807)
Check for `ERROR_INVALID_PARAMETER` when calling `_winapi.CopyFile2()` and raise `UnsupportedOperation`. In `Path.copy()`, handle this exception and fall back to the `PathBase.copy()` implementation.
Diffstat (limited to 'Lib/pathlib/_os.py')
-rw-r--r--Lib/pathlib/_os.py27
1 files changed, 24 insertions, 3 deletions
diff --git a/Lib/pathlib/_os.py b/Lib/pathlib/_os.py
index bbb019b..61923b5 100644
--- a/Lib/pathlib/_os.py
+++ b/Lib/pathlib/_os.py
@@ -20,6 +20,15 @@ except ImportError:
_winapi = None
+__all__ = ["UnsupportedOperation"]
+
+
+class UnsupportedOperation(NotImplementedError):
+ """An exception that is raised when an unsupported operation is attempted.
+ """
+ pass
+
+
def get_copy_blocksize(infd):
"""Determine blocksize for fastcopying on Linux.
Hopefully the whole file will be copied in a single call.
@@ -106,18 +115,30 @@ if _winapi and hasattr(_winapi, 'CopyFile2') and hasattr(os.stat_result, 'st_fil
Copy from one file to another using CopyFile2 (Windows only).
"""
if follow_symlinks:
- flags = 0
+ _winapi.CopyFile2(source, target, 0)
else:
+ # Use COPY_FILE_COPY_SYMLINK to copy a file symlink.
flags = _winapi.COPY_FILE_COPY_SYMLINK
try:
_winapi.CopyFile2(source, target, flags)
return
except OSError as err:
# Check for ERROR_ACCESS_DENIED
- if err.winerror != 5 or not _is_dirlink(source):
+ if err.winerror == 5 and _is_dirlink(source):
+ pass
+ else:
raise
+
+ # Add COPY_FILE_DIRECTORY to copy a directory symlink.
flags |= _winapi.COPY_FILE_DIRECTORY
- _winapi.CopyFile2(source, target, flags)
+ try:
+ _winapi.CopyFile2(source, target, flags)
+ except OSError as err:
+ # Check for ERROR_INVALID_PARAMETER
+ if err.winerror == 87:
+ raise UnsupportedOperation(err) from None
+ else:
+ raise
else:
copyfile = None