gh-88745: Add _winapi.CopyFile2 and update shutil.copy2 to use it (GH-105055)

(cherry picked from commit cda1bd3c9d)

Co-authored-by: Steve Dower <steve.dower@python.org>
This commit is contained in:
Miss Islington (bot) 2023-05-30 12:33:17 -07:00 committed by GitHub
parent aeee5a5756
commit 9ae49e3f3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 1214 additions and 988 deletions

View file

@ -42,6 +42,8 @@ elif _WINDOWS:
if sys.platform == 'win32':
import _winapi
else:
_winapi = None
COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 64 * 1024
# This should never be removed, see rationale in:
@ -435,6 +437,29 @@ def copy2(src, dst, *, follow_symlinks=True):
"""
if os.path.isdir(dst):
dst = os.path.join(dst, os.path.basename(src))
if hasattr(_winapi, "CopyFile2"):
src_ = os.fsdecode(src)
dst_ = os.fsdecode(dst)
flags = _winapi.COPY_FILE_ALLOW_DECRYPTED_DESTINATION # for compat
if not follow_symlinks:
flags |= _winapi.COPY_FILE_COPY_SYMLINK
try:
_winapi.CopyFile2(src_, dst_, flags)
return dst
except OSError as exc:
if (exc.winerror == _winapi.ERROR_PRIVILEGE_NOT_HELD
and not follow_symlinks):
# Likely encountered a symlink we aren't allowed to create.
# Fall back on the old code
pass
elif exc.winerror == _winapi.ERROR_ACCESS_DENIED:
# Possibly encountered a hidden or readonly file we can't
# overwrite. Fall back on old code
pass
else:
raise
copyfile(src, dst, follow_symlinks=follow_symlinks)
copystat(src, dst, follow_symlinks=follow_symlinks)
return dst