diff options
author | Barney Gale <barney.gale@gmail.com> | 2024-07-03 03:30:29 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-03 03:30:29 (GMT) |
commit | f09d184821efd9438d092643881e28bdf8de4de5 (patch) | |
tree | 1aa17585a9a686154135ef1f9305c0a4a5984234 /Lib/pathlib/_os.py | |
parent | 089835469d5efbea4793cd611b43cb8387f2e7e5 (diff) | |
download | cpython-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.py | 27 |
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 |