mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
Merge 53f91b2b23 into 7099af8f5e
This commit is contained in:
commit
b6da2fed95
3 changed files with 56 additions and 2 deletions
|
|
@ -443,8 +443,13 @@ def lookup(name):
|
|||
else:
|
||||
st = lookup("stat")(src, follow_symlinks=follow)
|
||||
mode = stat.S_IMODE(st.st_mode)
|
||||
lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
|
||||
follow_symlinks=follow)
|
||||
try:
|
||||
lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
|
||||
follow_symlinks=follow)
|
||||
except OSError as e:
|
||||
# Ignore permission errors when setting file times (gh-42948).
|
||||
if e.errno not in (errno.EPERM, errno.EACCES):
|
||||
raise
|
||||
# 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)
|
||||
|
|
|
|||
|
|
@ -1251,6 +1251,52 @@ def _chflags_raiser(path, flags, *, follow_symlinks=True):
|
|||
finally:
|
||||
os.chflags = old_chflags
|
||||
|
||||
def test_copystat_handles_utime_errors(self):
|
||||
# gh-42948: copystat should ignore permission errors when setting times
|
||||
tmpdir = self.mkdtemp()
|
||||
file1 = os.path.join(tmpdir, 'file1')
|
||||
file2 = os.path.join(tmpdir, 'file2')
|
||||
create_file(file1, 'xxx')
|
||||
create_file(file2, 'xxx')
|
||||
|
||||
def make_utime_raiser(err):
|
||||
def _utime_raiser(path, times=None, *, ns=None, dir_fd=None,
|
||||
follow_symlinks=True):
|
||||
ex = OSError()
|
||||
ex.errno = err
|
||||
raise ex
|
||||
return _utime_raiser
|
||||
|
||||
for err in errno.EPERM, errno.EACCES:
|
||||
with unittest.mock.patch('os.utime', side_effect=make_utime_raiser(err)):
|
||||
shutil.copystat(file1, file2)
|
||||
|
||||
with unittest.mock.patch('os.utime', side_effect=make_utime_raiser(errno.EINVAL)):
|
||||
self.assertRaises(OSError, shutil.copystat, file1, file2)
|
||||
|
||||
@mock_rename
|
||||
def test_move_handles_utime_errors(self):
|
||||
# gh-42948: move should succeed despite utime permission errors
|
||||
src_dir = self.mkdtemp()
|
||||
dst_dir = self.mkdtemp()
|
||||
src_file = os.path.join(src_dir, 'file')
|
||||
dst_file = os.path.join(dst_dir, 'file')
|
||||
create_file(src_file, 'content')
|
||||
|
||||
def _utime_raiser(path, times=None, *, ns=None, dir_fd=None,
|
||||
follow_symlinks=True):
|
||||
ex = OSError()
|
||||
ex.errno = errno.EPERM
|
||||
raise ex
|
||||
|
||||
with unittest.mock.patch('os.utime', side_effect=_utime_raiser):
|
||||
result = shutil.move(src_file, dst_file)
|
||||
self.assertEqual(result, dst_file)
|
||||
self.assertTrue(os.path.exists(dst_file))
|
||||
self.assertFalse(os.path.exists(src_file))
|
||||
with open(dst_file) as f:
|
||||
self.assertEqual(f.read(), 'content')
|
||||
|
||||
### shutil.copyxattr
|
||||
|
||||
@os_helper.skip_unless_xattr
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
:func:`shutil.copystat` now ignores permission errors when setting file
|
||||
times. This fixes :func:`shutil.move` failures on filesystems where the user
|
||||
has write access but is not the owner. Patch by Shamil Abdulaev.
|
||||
Loading…
Add table
Add a link
Reference in a new issue