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 79efbb7193)

Co-authored-by: Olexa Bilaniuk <obilaniu@users.noreply.github.com>
This commit is contained in:
Miss Islington (bot) 2019-05-13 22:30:22 -07:00 committed by Giampaolo Rodola
parent da86bf7396
commit 0a5b88e7f2
4 changed files with 15 additions and 1 deletions

View file

@ -203,6 +203,9 @@ def lookup(name):
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 lookup(name):
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.

View file

@ -464,12 +464,20 @@ def _raise_on_src(fname, *, follow_symlinks=True):
# 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

View file

@ -147,6 +147,7 @@ Stephen Bevan
Ron Bickers
Natalia B. Bidart
Adrian von Bidder
Olexa Bilaniuk
David Binger
Dominic Binks
Philippe Biondi

View file

@ -0,0 +1,3 @@
In `shutil.copystat()`, first copy extended file attributes and then file
permissions, since extended attributes can only be set on the destination
while it is still writeable.