[3.8] bpo-38688, shutil.copytree: consume iterator and create list of entries to prevent infinite recursion (GH-17397)
(cherry picked from commit 9bbcbc9f6d
)
Co-authored-by: Bruno P. Kinoshita <kinow@users.noreply.github.com>
This commit is contained in:
parent
a9c86f5e1a
commit
65c92c5870
|
@ -442,7 +442,7 @@ def ignore_patterns(*patterns):
|
|||
def _copytree(entries, src, dst, symlinks, ignore, copy_function,
|
||||
ignore_dangling_symlinks, dirs_exist_ok=False):
|
||||
if ignore is not None:
|
||||
ignored_names = ignore(src, set(os.listdir(src)))
|
||||
ignored_names = ignore(src, {x.name for x in entries})
|
||||
else:
|
||||
ignored_names = set()
|
||||
|
||||
|
@ -543,11 +543,12 @@ def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
|
|||
|
||||
"""
|
||||
sys.audit("shutil.copytree", src, dst)
|
||||
with os.scandir(src) as entries:
|
||||
return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
|
||||
ignore=ignore, copy_function=copy_function,
|
||||
ignore_dangling_symlinks=ignore_dangling_symlinks,
|
||||
dirs_exist_ok=dirs_exist_ok)
|
||||
with os.scandir(src) as itr:
|
||||
entries = list(itr)
|
||||
return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
|
||||
ignore=ignore, copy_function=copy_function,
|
||||
ignore_dangling_symlinks=ignore_dangling_symlinks,
|
||||
dirs_exist_ok=dirs_exist_ok)
|
||||
|
||||
if hasattr(os.stat_result, 'st_file_attributes'):
|
||||
# Special handling for directory junctions to make them behave like
|
||||
|
|
|
@ -1605,6 +1605,18 @@ class TestShutil(unittest.TestCase):
|
|||
rv = shutil.copytree(src_dir, dst_dir)
|
||||
self.assertEqual(['foo'], os.listdir(rv))
|
||||
|
||||
def test_copytree_subdirectory(self):
|
||||
# copytree where dst is a subdirectory of src, see Issue 38688
|
||||
base_dir = self.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base_dir, ignore_errors=True)
|
||||
src_dir = os.path.join(base_dir, "t", "pg")
|
||||
dst_dir = os.path.join(src_dir, "somevendor", "1.0")
|
||||
os.makedirs(src_dir)
|
||||
src = os.path.join(src_dir, 'pol')
|
||||
write_file(src, 'pol')
|
||||
rv = shutil.copytree(src_dir, dst_dir)
|
||||
self.assertEqual(['pol'], os.listdir(rv))
|
||||
|
||||
|
||||
class TestWhich(unittest.TestCase):
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
Calling func:`shutil.copytree` to copy a directory tree from one directory
|
||||
to another subdirectory resulted in an endless loop and a RecursionError. A
|
||||
fix was added to consume an iterator and create the list of the entries to
|
||||
be copied, avoiding the recursion for newly created directories. Patch by
|
||||
Bruno P. Kinoshita.
|
Loading…
Reference in New Issue