Skip to content

Commit 521e15c

Browse files
authored
gh-161112: Fix shutil.make_archive() adding a zip archive to itself (GH-161113)
Skip any walked file that is the archive being written, whether it is created inside the archived tree or a symlink in the tree points at it.
1 parent 6e6e83e commit 521e15c

3 files changed

Lines changed: 26 additions & 1 deletion

File tree

‎Lib/shutil.py‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,7 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0,
11291129
if root_dir is not None:
11301130
base_dir = os.path.join(root_dir, base_dir)
11311131
base_dir = os.path.normpath(base_dir)
1132+
zip_stat = os.stat(zip_filename)
11321133
if arcname != os.curdir:
11331134
zf.write(base_dir, arcname)
11341135
if logger is not None:
@@ -1147,7 +1148,13 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0,
11471148
for name in filenames:
11481149
path = os.path.join(dirpath, name)
11491150
path = os.path.normpath(path)
1150-
if os.path.isfile(path):
1151+
try:
1152+
st = os.stat(path)
1153+
except OSError:
1154+
continue
1155+
# Do not add the archive to itself.
1156+
if (stat.S_ISREG(st.st_mode) and
1157+
not os.path.samestat(st, zip_stat)):
11511158
arcname = os.path.join(arcdirpath, name)
11521159
zf.write(path, arcname)
11531160
if logger is not None:

‎Lib/test/test_shutil.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2189,6 +2189,21 @@ def test_make_zipfile_in_curdir(self):
21892189
# root_dir must be None, so the archive path is relative.
21902190
self.assertEqual(make_archive('test', 'zip'), 'test.zip')
21912191
self.assertTrue(os.path.isfile('test.zip'))
2192+
# The archive does not contain itself.
2193+
with zipfile.ZipFile('test.zip') as zf:
2194+
self.assertEqual(zf.namelist(), [])
2195+
2196+
@support.requires_zlib()
2197+
@os_helper.skip_unless_symlink
2198+
def test_make_zipfile_symlink_to_archive(self):
2199+
root_dir, base_dir = self._create_files('')
2200+
os.symlink('archive.zip', os.path.join(root_dir, 'link'))
2201+
base_name = os.path.join(root_dir, 'archive')
2202+
with no_chdir:
2203+
archive = make_archive(base_name, 'zip', root_dir)
2204+
with zipfile.ZipFile(archive) as zf:
2205+
self.assertCountEqual(zf.namelist(),
2206+
['sub/', 'sub2/', 'file1', 'file2', 'sub/file3'])
21922207

21932208
def test_make_archive_pathlike_cwd_default(self):
21942209
called_args = []
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :func:`shutil.make_archive` adding the zip archive being created to itself
2+
when it is written inside the directory being archived or a symbolic link in
3+
that directory refers to it.

0 commit comments

Comments
 (0)