diff options
author | Berker Peksag <berker.peksag@gmail.com> | 2014-12-10 02:50:32 +0200 |
---|---|---|
committer | Berker Peksag <berker.peksag@gmail.com> | 2014-12-10 02:50:32 +0200 |
commit | a28683895d2f1e43dfbe4e5a7f83cb8152254aa8 (patch) | |
tree | 0b4226faba4e5413eb552bfeaf063f8d82de03cd /Lib | |
parent | 48244ec44c4934d3b9d87f8d39b51f3cc036e44c (diff) | |
download | cpython-a28683895d2f1e43dfbe4e5a7f83cb8152254aa8.tar.gz |
Issue #21775: shutil.copytree(): fix crash when copying to VFAT
An exception handler assumed that that OSError objects always have a
'winerror' attribute. That is not the case, so the exception handler
itself raised AttributeError when run on Linux (and, presumably, any
other non-Windows OS).
Patch by Greg Ward.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/shutil.py | 2 | ||||
-rw-r--r-- | Lib/test/test_shutil.py | 15 |
2 files changed, 16 insertions, 1 deletions
diff --git a/Lib/shutil.py b/Lib/shutil.py index 22958f4204..ac06ae5e6c 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -337,7 +337,7 @@ def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, copystat(src, dst) except OSError as why: # Copying file access times may fail on Windows - if why.winerror is None: + if getattr(why, 'winerror', None) is None: errors.append((src, dst, str(why))) if errors: raise Error(errors) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 349036291b..9325bc7dc1 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1,6 +1,7 @@ # Copyright (C) 2003 Python Software Foundation import unittest +import unittest.mock import shutil import tempfile import sys @@ -758,6 +759,20 @@ class TestShutil(unittest.TestCase): self.assertEqual(os.stat(restrictive_subdir).st_mode, os.stat(restrictive_subdir_dst).st_mode) + @unittest.mock.patch('os.chmod') + def test_copytree_winerror(self, mock_patch): + # When copying to VFAT, copystat() raises OSError. On Windows, the + # exception object has a meaningful 'winerror' attribute, but not + # on other operating systems. Do not assume 'winerror' is set. + src_dir = tempfile.mkdtemp() + dst_dir = os.path.join(tempfile.mkdtemp(), 'destination') + self.addCleanup(shutil.rmtree, src_dir) + self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir)) + + mock_patch.side_effect = PermissionError('ka-boom') + with self.assertRaises(shutil.Error): + shutil.copytree(src_dir, dst_dir) + @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows') @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link') def test_dont_copy_file_onto_link_to_itself(self): |