Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5a5ce06

Browse files
ZackerySpytzwarsaw
authored andcommitted
bpo-5950: Support reading zips with comments in zipimport (#9548)
* bpo-5950: Support reading zips with comments in zipimport
1 parent 996859a commit 5a5ce06

5 files changed

Lines changed: 1083 additions & 1012 deletions

File tree

Doc/library/zipimport.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ Any files may be present in the ZIP archive, but only files :file:`.py` and
2828
corresponding :file:`.pyc` file, meaning that if a ZIP archive
2929
doesn't contain :file:`.pyc` files, importing may be rather slow.
3030

31-
ZIP archives with an archive comment are currently not supported.
31+
.. versionchanged:: 3.8
32+
Previously, ZIP archives with an archive comment were not supported.
3233

3334
.. seealso::
3435

Lib/test/test_zipimport.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ def makeZip(self, files, zipName=TEMP_ZIP, **kw):
116116
zinfo = ZipInfo(name, time.localtime(mtime))
117117
zinfo.compress_type = self.compression
118118
z.writestr(zinfo, data)
119+
comment = kw.get("comment", None)
120+
if comment is not None:
121+
z.comment = comment
119122

120123
stuff = kw.get("stuff", None)
121124
if stuff is not None:
@@ -665,6 +668,18 @@ def testBytesPath(self):
665668
with self.assertRaises(TypeError):
666669
zipimport.zipimporter(memoryview(os.fsencode(filename)))
667670

671+
def testComment(self):
672+
files = {TESTMOD + ".py": (NOW, test_src)}
673+
self.doTest(".py", files, TESTMOD, comment=b"comment")
674+
675+
def testBeginningCruftAndComment(self):
676+
files = {TESTMOD + ".py": (NOW, test_src)}
677+
self.doTest(".py", files, TESTMOD, stuff=b"cruft" * 64, comment=b"hi")
678+
679+
def testLargestPossibleComment(self):
680+
files = {TESTMOD + ".py": (NOW, test_src)}
681+
self.doTest(".py", files, TESTMOD, comment=b"c" * ((1 << 16) - 1))
682+
668683

669684
@support.requires_zlib
670685
class CompressedZipImportTestCase(UncompressedZipImportTestCase):

Lib/zipimport.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ class ZipImportError(ImportError):
3838

3939
_module_type = type(sys)
4040

41+
END_CENTRAL_DIR_SIZE = 22
42+
STRING_END_ARCHIVE = b'PK\x05\x06'
43+
MAX_COMMENT_LEN = (1 << 16) - 1
4144

4245
class zipimporter:
4346
"""zipimporter(archivepath) -> zipimporter object
@@ -354,16 +357,39 @@ def _read_directory(archive):
354357

355358
with fp:
356359
try:
357-
fp.seek(-22, 2)
360+
fp.seek(-END_CENTRAL_DIR_SIZE, 2)
358361
header_position = fp.tell()
359-
buffer = fp.read(22)
362+
buffer = fp.read(END_CENTRAL_DIR_SIZE)
360363
except OSError:
361364
raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive)
362-
if len(buffer) != 22:
365+
if len(buffer) != END_CENTRAL_DIR_SIZE:
363366
raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive)
364-
if buffer[:4] != b'PK\x05\x06':
367+
if buffer[:4] != STRING_END_ARCHIVE:
365368
# Bad: End of Central Dir signature
366-
raise ZipImportError(f'not a Zip file: {archive!r}', path=archive)
369+
# Check if there's a comment.
370+
try:
371+
fp.seek(0, 2)
372+
file_size = fp.tell()
373+
except OSError:
374+
raise ZipImportError(f"can't read Zip file: {archive!r}",
375+
path=archive)
376+
max_comment_start = max(file_size - MAX_COMMENT_LEN -
377+
END_CENTRAL_DIR_SIZE, 0)
378+
try:
379+
fp.seek(max_comment_start)
380+
data = fp.read()
381+
except OSError:
382+
raise ZipImportError(f"can't read Zip file: {archive!r}",
383+
path=archive)
384+
pos = data.rfind(STRING_END_ARCHIVE)
385+
if pos < 0:
386+
raise ZipImportError(f'not a Zip file: {archive!r}',
387+
path=archive)
388+
buffer = data[pos:pos+END_CENTRAL_DIR_SIZE]
389+
if len(buffer) != END_CENTRAL_DIR_SIZE:
390+
raise ZipImportError(f"corrupt Zip file: {archive!r}",
391+
path=archive)
392+
header_position = file_size - len(data) + pos
367393

368394
header_size = _unpack_uint32(buffer[12:16])
369395
header_offset = _unpack_uint32(buffer[16:20])
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support reading zip files with archive comments in :mod:`zipimport`.

0 commit comments

Comments
 (0)