summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/shutil.py7
-rw-r--r--Lib/test/test_shutil.py25
-rw-r--r--Misc/NEWS.d/next/Library/2023-12-15-20-29-49.gh-issue-113188.AvoraB.rst6
3 files changed, 24 insertions, 14 deletions
diff --git a/Lib/shutil.py b/Lib/shutil.py
index dc3aac3..c40f6dd 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -306,7 +306,12 @@ def copymode(src, dst, *, follow_symlinks=True):
else:
return
else:
- stat_func, chmod_func = _stat, os.chmod
+ stat_func = _stat
+ if os.name == 'nt' and os.path.islink(dst):
+ def chmod_func(*args):
+ os.chmod(*args, follow_symlinks=True)
+ else:
+ chmod_func = os.chmod
st = stat_func(src)
chmod_func(dst, stat.S_IMODE(st.st_mode))
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index 5ce8e5d..cc5459a 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -1101,19 +1101,18 @@ class TestCopy(BaseTest, unittest.TestCase):
shutil.copymode(src, dst)
self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
# On Windows, os.chmod does not follow symlinks (issue #15411)
- if os.name != 'nt':
- # follow src link
- os.chmod(dst, stat.S_IRWXO)
- shutil.copymode(src_link, dst)
- self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
- # follow dst link
- os.chmod(dst, stat.S_IRWXO)
- shutil.copymode(src, dst_link)
- self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
- # follow both links
- os.chmod(dst, stat.S_IRWXO)
- shutil.copymode(src_link, dst_link)
- self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
+ # follow src link
+ os.chmod(dst, stat.S_IRWXO)
+ shutil.copymode(src_link, dst)
+ self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
+ # follow dst link
+ os.chmod(dst, stat.S_IRWXO)
+ shutil.copymode(src, dst_link)
+ self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
+ # follow both links
+ os.chmod(dst, stat.S_IRWXO)
+ shutil.copymode(src_link, dst_link)
+ self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
@unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
@os_helper.skip_unless_symlink
diff --git a/Misc/NEWS.d/next/Library/2023-12-15-20-29-49.gh-issue-113188.AvoraB.rst b/Misc/NEWS.d/next/Library/2023-12-15-20-29-49.gh-issue-113188.AvoraB.rst
new file mode 100644
index 0000000..17c6957
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-12-15-20-29-49.gh-issue-113188.AvoraB.rst
@@ -0,0 +1,6 @@
+Fix :func:`shutil.copymode` and :func:`shutil.copystat` on Windows.
+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 not modify the permission bits if
+*follow_symlinks* is false and *src* is a symbolic link.