cpython: 9a99a88301ef (original) (raw)
Mercurial > cpython
changeset 104353:9a99a88301ef 2.7
Issue #26293: Fixed writing ZIP files that starts not from the start of the file. Offsets in ZIP file now are relative to the start of the archive in conforming to the specification. [#26293]
Serhiy Storchaka storchaka@gmail.com | |
---|---|
date | Fri, 07 Oct 2016 23:12:53 +0300 |
parents | 47d5bf5a846f |
children | ba76dd106e66 |
files | Lib/test/test_zipfile.py Lib/zipfile.py Misc/NEWS |
diffstat | 3 files changed, 62 insertions(+), 13 deletions(-)[+] [-] Lib/test/test_zipfile.py 43 Lib/zipfile.py 28 Misc/NEWS 4 |
line wrap: on
line diff
--- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -344,6 +344,49 @@ class TestsWithSourceFile(unittest.TestC f.seek(len(data)) with zipfile.ZipFile(f, "r") as zipfp: self.assertEqual(zipfp.namelist(), [TESTFN])
self.assertEqual(zipfp.read(TESTFN), self.data)[](#l1.7)
with open(TESTFN2, 'rb') as f:[](#l1.8)
self.assertEqual(f.read(len(data)), data)[](#l1.9)
zipfiledata = f.read()[](#l1.10)
with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp:[](#l1.11)
self.assertEqual(zipfp.namelist(), [TESTFN])[](#l1.12)
self.assertEqual(zipfp.read(TESTFN), self.data)[](#l1.13)
- def test_read_concatenated_zip_file(self):
with io.BytesIO() as bio:[](#l1.16)
with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp:[](#l1.17)
zipfp.write(TESTFN, TESTFN)[](#l1.18)
zipfiledata = bio.getvalue()[](#l1.19)
data = b'I am not a ZipFile!'*10[](#l1.20)
with open(TESTFN2, 'wb') as f:[](#l1.21)
f.write(data)[](#l1.22)
f.write(zipfiledata)[](#l1.23)
with zipfile.ZipFile(TESTFN2) as zipfp:[](#l1.25)
self.assertEqual(zipfp.namelist(), [TESTFN])[](#l1.26)
self.assertEqual(zipfp.read(TESTFN), self.data)[](#l1.27)
- def test_append_to_concatenated_zip_file(self):
with io.BytesIO() as bio:[](#l1.30)
with zipfile.ZipFile(bio, 'w', zipfile.ZIP_STORED) as zipfp:[](#l1.31)
zipfp.write(TESTFN, TESTFN)[](#l1.32)
zipfiledata = bio.getvalue()[](#l1.33)
data = b'I am not a ZipFile!'*1000000[](#l1.34)
with open(TESTFN2, 'wb') as f:[](#l1.35)
f.write(data)[](#l1.36)
f.write(zipfiledata)[](#l1.37)
with zipfile.ZipFile(TESTFN2, 'a') as zipfp:[](#l1.39)
self.assertEqual(zipfp.namelist(), [TESTFN])[](#l1.40)
zipfp.writestr('strfile', self.data)[](#l1.41)
with open(TESTFN2, 'rb') as f:[](#l1.43)
self.assertEqual(f.read(len(data)), data)[](#l1.44)
zipfiledata = f.read()[](#l1.45)
with io.BytesIO(zipfiledata) as bio, zipfile.ZipFile(bio) as zipfp:[](#l1.46)
self.assertEqual(zipfp.namelist(), [TESTFN, 'strfile'])[](#l1.47)
self.assertEqual(zipfp.read(TESTFN), self.data)[](#l1.48)
self.assertEqual(zipfp.read('strfile'), self.data)[](#l1.49)
def test_ignores_newline_at_end(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
--- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -772,6 +772,7 @@ class ZipFile(object): # set the modified flag so central directory gets written # even if no files are added to the archive self._didModify = True
self._start_disk = self.fp.tell()[](#l2.7) elif key == 'a':[](#l2.8) try:[](#l2.9) # See if file is a zip file[](#l2.10)
@@ -785,6 +786,7 @@ class ZipFile(object): # set the modified flag so central directory gets written # even if no files are added to the archive self._didModify = True
self._start_disk = self.fp.tell()[](#l2.15) else:[](#l2.16) raise RuntimeError('Mode must be "r", "w" or "a"')[](#l2.17) except:[](#l2.18)
@@ -815,17 +817,18 @@ class ZipFile(object): offset_cd = endrec[_ECD_OFFSET] # offset of central directory self._comment = endrec[_ECD_COMMENT] # archive comment
# "concat" is zero, unless zip was concatenated to another file[](#l2.23)
concat = endrec[_ECD_LOCATION] - size_cd - offset_cd[](#l2.24)
# self._start_disk: Position of the start of ZIP archive[](#l2.25)
# It is zero, unless ZIP was concatenated to another file[](#l2.26)
self._start_disk = endrec[_ECD_LOCATION] - size_cd - offset_cd[](#l2.27) if endrec[_ECD_SIGNATURE] == stringEndArchive64:[](#l2.28) # If Zip64 extension structures are present, account for them[](#l2.29)
concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator)[](#l2.30)
self._start_disk -= (sizeEndCentDir64 + sizeEndCentDir64Locator)[](#l2.31)
inferred = concat + offset_cd[](#l2.34)
print "given, inferred, offset", offset_cd, inferred, concat[](#l2.35)
inferred = self._start_disk + offset_cd[](#l2.36)
print "given, inferred, offset", offset_cd, inferred, self._start_disk[](#l2.37) # self.start_dir: Position of start of central directory[](#l2.38)
self.start_dir = offset_cd + concat[](#l2.39)
self.start_dir = offset_cd + self._start_disk[](#l2.40) fp.seek(self.start_dir, 0)[](#l2.41) data = fp.read(size_cd)[](#l2.42) fp = cStringIO.StringIO(data)[](#l2.43)
@@ -855,7 +858,7 @@ class ZipFile(object): t>>11, (t>>5)&0x3F, (t&0x1F) * 2 ) x._decodeExtra()
x.header_offset = x.header_offset + concat[](#l2.48)
x.header_offset = x.header_offset + self._start_disk[](#l2.49) x.filename = x._decodeFilename()[](#l2.50) self.filelist.append(x)[](#l2.51) self.NameToInfo[x.filename] = x[](#l2.52)
@@ -1198,7 +1201,7 @@ class ZipFile(object): raise RuntimeError('Compressed size larger than uncompressed size') # Seek backwards and write file header (which will now include # correct CRC and file sizes)
position = self.fp.tell() # Preserve current position in file[](#l2.57)
position = self.fp.tell() # Preserve current position in file[](#l2.58) self.fp.seek(zinfo.header_offset, 0)[](#l2.59) self.fp.write(zinfo.FileHeader(zip64))[](#l2.60) self.fp.seek(position, 0)[](#l2.61)
@@ -1284,11 +1287,10 @@ class ZipFile(object): file_size = zinfo.file_size compress_size = zinfo.compress_size
if zinfo.header_offset > ZIP64_LIMIT:[](#l2.66)
extra.append(zinfo.header_offset)[](#l2.67)
header_offset = zinfo.header_offset - self._start_disk[](#l2.68)
if header_offset > ZIP64_LIMIT:[](#l2.69)
extra.append(header_offset)[](#l2.70) header_offset = 0xffffffffL[](#l2.71)
else:[](#l2.72)
header_offset = zinfo.header_offset[](#l2.73)
extra_data = zinfo.extra if extra: @@ -1332,7 +1334,7 @@ class ZipFile(object): # Write end-of-zip-archive record centDirCount = len(self.filelist) centDirSize = pos2 - pos1
centDirOffset = pos1[](#l2.81)
centDirOffset = pos1 - self._start_disk[](#l2.82) requires_zip64 = None[](#l2.83) if centDirCount > ZIP_FILECOUNT_LIMIT:[](#l2.84) requires_zip64 = "Files count"[](#l2.85)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,10 @@ Core and Builtins Library ------- +- Issue #26293: Fixed writing ZIP files that starts not from the start of the