cpython: d94d8789e924 (original) (raw)
Mercurial > cpython
changeset 93262:d94d8789e924 3.4
Issue #8876: distutils now falls back to copying files when hard linking doesn't work. This allows use with special filesystems such as VirtualBox shared folders. [#8876]
Antoine Pitrou solipsis@pitrou.net | |
---|---|
date | Thu, 30 Oct 2014 19:37:07 +0100 |
parents | 9dddc95ef31e |
children | ce484e0840e3 1eabc79a713e |
files | Lib/distutils/file_util.py Lib/distutils/tests/test_file_util.py Misc/NEWS |
diffstat | 3 files changed, 55 insertions(+), 13 deletions(-)[+] [-] Lib/distutils/file_util.py 32 Lib/distutils/tests/test_file_util.py 32 Misc/NEWS 4 |
line wrap: on
line diff
--- a/Lib/distutils/file_util.py +++ b/Lib/distutils/file_util.py @@ -80,7 +80,8 @@ def copy_file(src, dst, preserve_mode=1, (os.symlink) instead of copying: set it to "hard" or "sym"; if it is None (the default), files are copied. Don't set 'link' on systems that don't support it: 'copy_file()' doesn't check if hard or symbolic
Under Mac OS, uses the native file copy function in macostools; on other systems, uses '_copy_file_contents()' to copy file contents. @@ -132,24 +133,31 @@ def copy_file(src, dst, preserve_mode=1, # (Unix only, of course, but that's the caller's responsibility) elif link == 'hard': if not (os.path.exists(dst) and os.path.samefile(src, dst)):
os.link(src, dst)[](#l1.17)
try:[](#l1.18)
os.link(src, dst)[](#l1.19)
return (dst, 1)[](#l1.20)
except OSError:[](#l1.21)
# If hard linking fails, fall back on copying file[](#l1.22)
# (some special filesystems don't support hard linking[](#l1.23)
# even under Unix, see issue #8876).[](#l1.24)
elif link == 'sym': if not (os.path.exists(dst) and os.path.samefile(src, dst)): os.symlink(src, dst)pass[](#l1.25)
return (dst, 1)[](#l1.29)
# Otherwise (non-Mac, not linking), copy the file contents and # (optionally) copy the times and mode.
- else:
_copy_file_contents(src, dst)[](#l1.34)
if preserve_mode or preserve_times:[](#l1.35)
st = os.stat(src)[](#l1.36)
# According to David Ascher <da@ski.org>, utime() should be done[](#l1.41)
# before chmod() (at least under NT).[](#l1.42)
if preserve_times:[](#l1.43)
os.utime(dst, (st[ST_ATIME], st[ST_MTIME]))[](#l1.44)
if preserve_mode:[](#l1.45)
os.chmod(dst, S_IMODE(st[ST_MODE]))[](#l1.46)
# According to David Ascher <da@ski.org>, utime() should be done[](#l1.47)
# before chmod() (at least under NT).[](#l1.48)
if preserve_times:[](#l1.49)
os.utime(dst, (st[ST_ATIME], st[ST_MTIME]))[](#l1.50)
if preserve_mode:[](#l1.51)
os.chmod(dst, S_IMODE(st[ST_MODE]))[](#l1.52)
--- a/Lib/distutils/tests/test_file_util.py +++ b/Lib/distutils/tests/test_file_util.py @@ -5,7 +5,7 @@ import shutil import errno from unittest.mock import patch -from distutils.file_util import move_file +from distutils.file_util import move_file, copy_file from distutils import log from distutils.tests import support from distutils.errors import DistutilsFileError @@ -78,6 +78,36 @@ class FileUtilTestCase(support.TempdirMa fobj.write('spam eggs') move_file(self.source, self.target, verbose=0)
- def test_copy_file_hard_link(self):
with open(self.source, 'w') as f:[](#l2.17)
f.write('some content')[](#l2.18)
st = os.stat(self.source)[](#l2.19)
copy_file(self.source, self.target, link='hard')[](#l2.20)
st2 = os.stat(self.source)[](#l2.21)
st3 = os.stat(self.target)[](#l2.22)
self.assertTrue(os.path.samestat(st, st2), (st, st2))[](#l2.23)
self.assertTrue(os.path.samestat(st2, st3), (st2, st3))[](#l2.24)
with open(self.source, 'r') as f:[](#l2.25)
self.assertEqual(f.read(), 'some content')[](#l2.26)
- def test_copy_file_hard_link_failure(self):
# If hard linking fails, copy_file() falls back on copying file[](#l2.29)
# (some special filesystems don't support hard linking even under[](#l2.30)
# Unix, see issue #8876).[](#l2.31)
with open(self.source, 'w') as f:[](#l2.32)
f.write('some content')[](#l2.33)
st = os.stat(self.source)[](#l2.34)
with patch("os.link", side_effect=OSError(0, "linking unsupported")):[](#l2.35)
copy_file(self.source, self.target, link='hard')[](#l2.36)
st2 = os.stat(self.source)[](#l2.37)
st3 = os.stat(self.target)[](#l2.38)
self.assertTrue(os.path.samestat(st, st2), (st, st2))[](#l2.39)
self.assertFalse(os.path.samestat(st2, st3), (st2, st3))[](#l2.40)
for fn in (self.source, self.target):[](#l2.41)
with open(fn, 'r') as f:[](#l2.42)
self.assertEqual(f.read(), 'some content')[](#l2.43)
+ + def test_suite(): return unittest.makeSuite(FileUtilTestCase)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -33,6 +33,10 @@ Core and Builtins Library ------- +- Issue #8876: distutils now falls back to copying files when hard linking