Skip to content

Commit ff21444

Browse files
authored
build: implement zip64 stripping (electron#22998)
When zip contains files larger than 4GB 4bytes length headers are not sufficient anymore. Zip64 defines an extra header 0x0001 which may contain 8byte lengthed (16 exabytes) lengths [uncompressed and compressed]. Read this value when performing extra data cleaning and override the bogus value if the header is available. Read https://blog.yaakov.online/zip64-go-big-or-go-home/ for more information on Zip64 extra header. This is the first known implementation of zip64 stripping.
1 parent f4cf23f commit ff21444

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

script/release/uploaders/upload.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def zero_zip_date_time(fname):
182182

183183

184184
def _zero_zip_date_time(zip_):
185-
def purify_extra_data(mm, offset, length):
185+
def purify_extra_data(mm, offset, length, compressed_size=0):
186186
extra_header_struct = Struct("<HH")
187187
# 0. id
188188
# 1. length
@@ -194,6 +194,16 @@ def purify_extra_data(mm, offset, length):
194194
UNIX_EXTRA_DATA = 0x7875
195195
# Unix extra data; UID / GID stuff, see
196196
# ftp://ftp.info-zip.org/pub/infozip/src/zip30.zip ./proginfo/extrafld.txt
197+
ZIP64_EXTRA_HEADER = 0x0001
198+
zip64_extra_struct = Struct("<HHQQ")
199+
# ZIP64.
200+
# When a ZIP64 extra field is present his 8byte length
201+
# will override the 4byte length defined in canonical zips.
202+
# This is in the form:
203+
# - 0x0001 (header_id)
204+
# - 0x0010 [16] (header_length)
205+
# - ... (8byte uncompressed_length)
206+
# - ... (8byte compressed_length)
197207
mlen = offset + length
198208

199209
while offset < mlen:
@@ -205,15 +215,17 @@ def purify_extra_data(mm, offset, length):
205215

206216
if header_id in (EXTENDED_TIME_DATA, UNIX_EXTRA_DATA):
207217
values[0] = STRIPZIP_OPTION_HEADER
208-
for i in xrange(2, len(values)):
218+
for i in range(2, len(values)):
209219
values[i] = 0xff
210220
extra_struct.pack_into(mm, offset, *values)
211-
elif header_id != STRIPZIP_OPTION_HEADER:
212-
return False
221+
if header_id == ZIP64_EXTRA_HEADER:
222+
assert header_length == 16
223+
values = list(zip64_extra_struct.unpack_from(mm, offset))
224+
header_id, header_length, uncompressed_size, compressed_size = values
213225

214226
offset += extra_header_struct.size + header_length
215227

216-
return True
228+
return compressed_size
217229

218230
FILE_HEADER_SIGNATURE = 0x04034b50
219231
CENDIR_HEADER_SIGNATURE = 0x02014b50
@@ -263,9 +275,10 @@ def purify_extra_data(mm, offset, length):
263275
# reset last_mod_date
264276
values[5] = 0x21
265277
local_file_header_struct.pack_into(mm, offset, *values)
266-
offset += local_file_header_struct.size + compressed_size + name_length + extra_field_length
278+
offset += local_file_header_struct.size + name_length
267279
if extra_field_length != 0:
268-
purify_extra_data(mm, offset - extra_field_length - compressed_size, extra_field_length)
280+
compressed_size = purify_extra_data(mm, offset, extra_field_length, compressed_size)
281+
offset += compressed_size + extra_field_length
269282

270283
while offset < archive_size:
271284
if signature_struct.unpack_from(mm, offset) != (CENDIR_HEADER_SIGNATURE,):

0 commit comments

Comments
 (0)