summaryrefslogtreecommitdiffstats
path: root/Lib/shutil.py
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2023-12-23 10:53:48 (GMT)
committerGitHub <noreply@github.com>2023-12-23 10:53:48 (GMT)
commit80b2bad2c2c4e34ee6bd8e6f1f9360f97aed6551 (patch)
tree1b7e6af21d25b0cabeb7beff843f86c3923471fd /Lib/shutil.py
parent0bd134d15f48dc5e284f13f1545548cabf50c792 (diff)
downloadcpython-80b2bad2c2c4e34ee6bd8e6f1f9360f97aed6551.zip
cpython-80b2bad2c2c4e34ee6bd8e6f1f9360f97aed6551.tar.gz
cpython-80b2bad2c2c4e34ee6bd8e6f1f9360f97aed6551.tar.bz2
[3.11] gh-113188: Fix shutil.copymode() and shutil.copystat() on Windows (GH-113285) (GH-113426)
Previously they worked differenly if dst is a symbolic link: they modified the permission bits of dst itself rather than the file it points to if follow_symlinks is true or src is not a symbolic link, and did nothing if follow_symlinks is false and src is a symbolic link. (cherry picked from commit c7874bb56f862dd96a9a74b809dbea5688fa6c1c) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Diffstat (limited to 'Lib/shutil.py')
-rw-r--r--Lib/shutil.py16
1 files changed, 14 insertions, 2 deletions
diff --git a/Lib/shutil.py b/Lib/shutil.py
index cae65a3..eecc4be 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -298,11 +298,15 @@ def copymode(src, dst, *, follow_symlinks=True):
sys.audit("shutil.copymode", src, dst)
if not follow_symlinks and _islink(src) and os.path.islink(dst):
- if hasattr(os, 'lchmod'):
+ if os.name == 'nt':
+ stat_func, chmod_func = os.lstat, os.chmod
+ elif hasattr(os, 'lchmod'):
stat_func, chmod_func = os.lstat, os.lchmod
else:
return
else:
+ if os.name == 'nt' and os.path.islink(dst):
+ dst = os.path.realpath(dst, strict=True)
stat_func, chmod_func = _stat, os.chmod
st = stat_func(src)
@@ -378,8 +382,16 @@ def copystat(src, dst, *, follow_symlinks=True):
# We must copy extended attributes before the file is (potentially)
# chmod()'ed read-only, otherwise setxattr() will error with -EACCES.
_copyxattr(src, dst, follow_symlinks=follow)
+ _chmod = lookup("chmod")
+ if os.name == 'nt':
+ if follow:
+ if os.path.islink(dst):
+ dst = os.path.realpath(dst, strict=True)
+ else:
+ def _chmod(*args, **kwargs):
+ os.chmod(*args)
try:
- lookup("chmod")(dst, mode, follow_symlinks=follow)
+ _chmod(dst, mode, follow_symlinks=follow)
except NotImplementedError:
# if we got a NotImplementedError, it's because
# * follow_symlinks=False,