|
|
|
@ -316,7 +316,7 @@ class ZipInfo (object): |
|
|
|
# compress_size Size of the compressed file |
|
|
|
# file_size Size of the uncompressed file |
|
|
|
|
|
|
|
def FileHeader(self): |
|
|
|
def FileHeader(self, zip64=None): |
|
|
|
"""Return the per-file header as a string.""" |
|
|
|
dt = self.date_time |
|
|
|
dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2] |
|
|
|
@ -331,12 +331,17 @@ class ZipInfo (object): |
|
|
|
|
|
|
|
extra = self.extra |
|
|
|
|
|
|
|
if file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT: |
|
|
|
# File is larger than what fits into a 4 byte integer, |
|
|
|
# fall back to the ZIP64 extension |
|
|
|
if zip64 is None: |
|
|
|
zip64 = file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT |
|
|
|
if zip64: |
|
|
|
fmt = '<HHQQ' |
|
|
|
extra = extra + struct.pack(fmt, |
|
|
|
1, struct.calcsize(fmt)-4, file_size, compress_size) |
|
|
|
if file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT: |
|
|
|
if not zip64: |
|
|
|
raise LargeZipFile("Filesize would require ZIP64 extensions") |
|
|
|
# File is larger than what fits into a 4 byte integer, |
|
|
|
# fall back to the ZIP64 extension |
|
|
|
file_size = 0xffffffff |
|
|
|
compress_size = 0xffffffff |
|
|
|
self.extract_version = max(45, self.extract_version) |
|
|
|
@ -1113,20 +1118,23 @@ class ZipFile(object): |
|
|
|
zinfo.CRC = 0 |
|
|
|
self.filelist.append(zinfo) |
|
|
|
self.NameToInfo[zinfo.filename] = zinfo |
|
|
|
self.fp.write(zinfo.FileHeader()) |
|
|
|
self.fp.write(zinfo.FileHeader(False)) |
|
|
|
return |
|
|
|
|
|
|
|
with open(filename, "rb") as fp: |
|
|
|
# Must overwrite CRC and sizes with correct data later |
|
|
|
zinfo.CRC = CRC = 0 |
|
|
|
zinfo.compress_size = compress_size = 0 |
|
|
|
zinfo.file_size = file_size = 0 |
|
|
|
self.fp.write(zinfo.FileHeader()) |
|
|
|
# Compressed size can be larger than uncompressed size |
|
|
|
zip64 = self._allowZip64 and \ |
|
|
|
zinfo.file_size * 1.05 > ZIP64_LIMIT |
|
|
|
self.fp.write(zinfo.FileHeader(zip64)) |
|
|
|
if zinfo.compress_type == ZIP_DEFLATED: |
|
|
|
cmpr = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, |
|
|
|
zlib.DEFLATED, -15) |
|
|
|
else: |
|
|
|
cmpr = None |
|
|
|
file_size = 0 |
|
|
|
while 1: |
|
|
|
buf = fp.read(1024 * 8) |
|
|
|
if not buf: |
|
|
|
@ -1146,11 +1154,16 @@ class ZipFile(object): |
|
|
|
zinfo.compress_size = file_size |
|
|
|
zinfo.CRC = CRC |
|
|
|
zinfo.file_size = file_size |
|
|
|
# Seek backwards and write CRC and file sizes |
|
|
|
if not zip64 and self._allowZip64: |
|
|
|
if file_size > ZIP64_LIMIT: |
|
|
|
raise RuntimeError('File size has increased during compressing') |
|
|
|
if compress_size > ZIP64_LIMIT: |
|
|
|
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 |
|
|
|
self.fp.seek(zinfo.header_offset + 14, 0) |
|
|
|
self.fp.write(struct.pack("<LLL", zinfo.CRC, zinfo.compress_size, |
|
|
|
zinfo.file_size)) |
|
|
|
self.fp.seek(zinfo.header_offset, 0) |
|
|
|
self.fp.write(zinfo.FileHeader(zip64)) |
|
|
|
self.fp.seek(position, 0) |
|
|
|
self.filelist.append(zinfo) |
|
|
|
self.NameToInfo[zinfo.filename] = zinfo |
|
|
|
@ -1187,14 +1200,18 @@ class ZipFile(object): |
|
|
|
zinfo.compress_size = len(bytes) # Compressed size |
|
|
|
else: |
|
|
|
zinfo.compress_size = zinfo.file_size |
|
|
|
zinfo.header_offset = self.fp.tell() # Start of header bytes |
|
|
|
self.fp.write(zinfo.FileHeader()) |
|
|
|
zip64 = zinfo.file_size > ZIP64_LIMIT or \ |
|
|
|
zinfo.compress_size > ZIP64_LIMIT |
|
|
|
if zip64 and not self._allowZip64: |
|
|
|
raise LargeZipFile("Filesize would require ZIP64 extensions") |
|
|
|
self.fp.write(zinfo.FileHeader(zip64)) |
|
|
|
self.fp.write(bytes) |
|
|
|
self.fp.flush() |
|
|
|
if zinfo.flag_bits & 0x08: |
|
|
|
# Write CRC and file sizes after the file data |
|
|
|
self.fp.write(struct.pack("<LLL", zinfo.CRC, zinfo.compress_size, |
|
|
|
fmt = '<LQQ' if zip64 else '<LLL' |
|
|
|
self.fp.write(struct.pack(fmt, zinfo.CRC, zinfo.compress_size, |
|
|
|
zinfo.file_size)) |
|
|
|
self.fp.flush() |
|
|
|
self.filelist.append(zinfo) |
|
|
|
self.NameToInfo[zinfo.filename] = zinfo |
|
|
|
|
|
|
|
|