Skip to content

Commit 2f87f80

Browse files
authored
[3.15] gh-161112: Fix shutil.make_archive() adding a zip archive to itself (GH-161113) (#161140)
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. (cherry picked from commit 521e15c)
1 parent 762ea8b commit 2f87f80

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
@@ -1101,6 +1101,7 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0,
11011101
if root_dir is not None:
11021102
base_dir = os.path.join(root_dir, base_dir)
11031103
base_dir = os.path.normpath(base_dir)
1104+
zip_stat = os.stat(zip_filename)
11041105
if arcname != os.curdir:
11051106
zf.write(base_dir, arcname)
11061107
if logger is not None:
@@ -1119,7 +1120,13 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0,
11191120
for name in filenames:
11201121
path = os.path.join(dirpath, name)
11211122
path = os.path.normpath(path)
1122-
if os.path.isfile(path):
1123+
try:
1124+
st = os.stat(path)
1125+
except OSError:
1126+
continue
1127+
# Do not add the archive to itself.
1128+
if (stat.S_ISREG(st.st_mode) and
1129+
not os.path.samestat(st, zip_stat)):
11231130
arcname = os.path.join(arcdirpath, name)
11241131
zf.write(path, arcname)
11251132
if logger is not None:

‎Lib/test/test_shutil.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,6 +2072,21 @@ def test_make_zipfile_in_curdir(self):
20722072
# root_dir must be None, so the archive path is relative.
20732073
self.assertEqual(make_archive('test', 'zip'), 'test.zip')
20742074
self.assertTrue(os.path.isfile('test.zip'))
2075+
# The archive does not contain itself.
2076+
with zipfile.ZipFile('test.zip') as zf:
2077+
self.assertEqual(zf.namelist(), [])
2078+
2079+
@support.requires_zlib()
2080+
@os_helper.skip_unless_symlink
2081+
def test_make_zipfile_symlink_to_archive(self):
2082+
root_dir, base_dir = self._create_files('')
2083+
os.symlink('archive.zip', os.path.join(root_dir, 'link'))
2084+
base_name = os.path.join(root_dir, 'archive')
2085+
with no_chdir:
2086+
archive = make_archive(base_name, 'zip', root_dir)
2087+
with zipfile.ZipFile(archive) as zf:
2088+
self.assertCountEqual(zf.namelist(),
2089+
['sub/', 'sub2/', 'file1', 'file2', 'sub/file3'])
20752090

20762091
def test_make_archive_pathlike_cwd_default(self):
20772092
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)