summaryrefslogtreecommitdiff
path: root/Lib
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2019-05-13 22:30:22 -0700
committerGiampaolo Rodola <g.rodola@gmail.com>2019-05-14 13:30:22 +0800
commit0a5b88e7f23b671d63896619b13148b0e4e2b5dd (patch)
treeefd4fa070f4f951fafb751e5a6a50223038e4768 /Lib
parentda86bf7396c6509534a94407fe83e7106c9d5959 (diff)
downloadcpython-git-0a5b88e7f23b671d63896619b13148b0e4e2b5dd.tar.gz
bpo-24538: Fix bug in shutil involving the copying of xattrs to read-only files. (PR-13212) (#13234)
Extended attributes can only be set on user-writeable files, but shutil previously first chmod()ed the destination file to the source's permissions and then tried to copy xattrs. This will cause failures if attempting to copy read-only files with xattrs, as occurs with Git clones on Lustre FS. (cherry picked from commit 79efbb719383386051c72f2ee932eeca8e033e6b) Co-authored-by: Olexa Bilaniuk <obilaniu@users.noreply.github.com>
Diffstat (limited to 'Lib')
-rw-r--r--Lib/shutil.py4
-rw-r--r--Lib/test/test_shutil.py8
2 files changed, 11 insertions, 1 deletions
diff --git a/Lib/shutil.py b/Lib/shutil.py
index b0a53dba3a..4c6fdd7d33 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -203,6 +203,9 @@ def copystat(src, dst, *, follow_symlinks=True):
mode = stat.S_IMODE(st.st_mode)
lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
follow_symlinks=follow)
+ # 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)
try:
lookup("chmod")(dst, mode, follow_symlinks=follow)
except NotImplementedError:
@@ -226,7 +229,6 @@ def copystat(src, dst, *, follow_symlinks=True):
break
else:
raise
- _copyxattr(src, dst, follow_symlinks=follow)
def copy(src, dst, *, follow_symlinks=True):
"""Copy data and mode bits ("cp src dst"). Return the file's destination.
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index 197dd130a9..ef9323962c 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -464,12 +464,20 @@ class TestShutil(unittest.TestCase):
# test that shutil.copystat copies xattrs
src = os.path.join(tmp_dir, 'the_original')
+ srcro = os.path.join(tmp_dir, 'the_original_ro')
write_file(src, src)
+ write_file(srcro, srcro)
os.setxattr(src, 'user.the_value', b'fiddly')
+ os.setxattr(srcro, 'user.the_value', b'fiddly')
+ os.chmod(srcro, 0o444)
dst = os.path.join(tmp_dir, 'the_copy')
+ dstro = os.path.join(tmp_dir, 'the_copy_ro')
write_file(dst, dst)
+ write_file(dstro, dstro)
shutil.copystat(src, dst)
+ shutil.copystat(srcro, dstro)
self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
+ self.assertEqual(os.getxattr(dstro, 'user.the_value'), b'fiddly')
@support.skip_unless_symlink
@support.skip_unless_xattr