summaryrefslogtreecommitdiffstats
path: root/Lib/shutil.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/shutil.py')
-rw-r--r--Lib/shutil.py25
1 files changed, 25 insertions, 0 deletions
diff --git a/Lib/shutil.py b/Lib/shutil.py
index 7d1a3d0..3f2864a 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -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