@@ -262,7 +262,7 @@ def is_zipfile(filename):
262262 else :
263263 with open (filename , "rb" ) as fp :
264264 result = _check_zipfile (fp )
265- except OSError :
265+ except ( OSError , BadZipFile ) :
266266 pass
267267 return result
268268
@@ -272,9 +272,6 @@ def _handle_prepended_data(endrec, debug=0):
272272
273273 # "concat" is zero, unless zip was concatenated to another file
274274 concat = endrec [_ECD_LOCATION ] - size_cd - offset_cd
275- if endrec [_ECD_SIGNATURE ] == stringEndArchive64 :
276- # If Zip64 extension structures are present, account for them
277- concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator )
278275
279276 if debug > 2 :
280277 inferred = concat + offset_cd
@@ -286,33 +283,49 @@ def _EndRecData64(fpin, offset, endrec):
286283 """
287284 Read the ZIP64 end-of-archive records and use that to update endrec
288285 """
289- try :
290- fpin .seek (offset - sizeEndCentDir64Locator , 2 )
291- except OSError :
292- # If the seek fails, the file is not large enough to contain a ZIP64
286+ offset -= sizeEndCentDir64Locator
287+ if offset < 0 :
288+ # The file is not large enough to contain a ZIP64
293289 # end-of-archive record, so just return the end record we were given.
294290 return endrec
295-
291+ fpin . seek ( offset )
296292 data = fpin .read (sizeEndCentDir64Locator )
297293 if len (data ) != sizeEndCentDir64Locator :
298- return endrec
294+ raise OSError ( "Unknown I/O error" )
299295 sig , diskno , reloff , disks = struct .unpack (structEndArchive64Locator , data )
300296 if sig != stringEndArchive64Locator :
301297 return endrec
302298
303299 if diskno != 0 or disks > 1 :
304300 raise BadZipFile ("zipfiles that span multiple disks are not supported" )
305301
306- # Assume no 'zip64 extensible data'
307- fpin .seek (offset - sizeEndCentDir64Locator - sizeEndCentDir64 , 2 )
302+ offset -= sizeEndCentDir64
303+ if reloff > offset :
304+ raise BadZipFile ("Corrupt zip64 end of central directory locator" )
305+ # First, check the assumption that there is no prepended data.
306+ fpin .seek (reloff )
307+ extrasz = offset - reloff
308308 data = fpin .read (sizeEndCentDir64 )
309309 if len (data ) != sizeEndCentDir64 :
310- return endrec
310+ raise OSError ("Unknown I/O error" )
311+ if not data .startswith (stringEndArchive64 ) and reloff != offset :
312+ # Since we already have seen the Zip64 EOCD Locator, it's
313+ # possible we got here because there is prepended data.
314+ # Assume no 'zip64 extensible data'
315+ fpin .seek (offset )
316+ extrasz = 0
317+ data = fpin .read (sizeEndCentDir64 )
318+ if len (data ) != sizeEndCentDir64 :
319+ raise OSError ("Unknown I/O error" )
320+ if not data .startswith (stringEndArchive64 ):
321+ raise BadZipFile ("Zip64 end of central directory record not found" )
322+
311323 sig , sz , create_version , read_version , disk_num , disk_dir , \
312324 dircount , dircount2 , dirsize , diroffset = \
313325 struct .unpack (structEndArchive64 , data )
314- if sig != stringEndArchive64 :
315- return endrec
326+ if (diroffset + dirsize != reloff or
327+ sz + 12 != sizeEndCentDir64 + extrasz ):
328+ raise BadZipFile ("Corrupt zip64 end of central directory record" )
316329
317330 # Update the original endrec using data from the ZIP64 record
318331 endrec [_ECD_SIGNATURE ] = sig
@@ -322,6 +335,7 @@ def _EndRecData64(fpin, offset, endrec):
322335 endrec [_ECD_ENTRIES_TOTAL ] = dircount2
323336 endrec [_ECD_SIZE ] = dirsize
324337 endrec [_ECD_OFFSET ] = diroffset
338+ endrec [_ECD_LOCATION ] = offset - extrasz
325339 return endrec
326340
327341
@@ -355,7 +369,7 @@ def _EndRecData(fpin):
355369 endrec .append (filesize - sizeEndCentDir )
356370
357371 # Try to read the "Zip64 end of central directory" structure
358- return _EndRecData64 (fpin , - sizeEndCentDir , endrec )
372+ return _EndRecData64 (fpin , filesize - sizeEndCentDir , endrec )
359373
360374 # Either this is not a ZIP file, or it is a ZIP file with an archive
361375 # comment. Search the end of the file for the "end of central directory"
@@ -379,8 +393,7 @@ def _EndRecData(fpin):
379393 endrec .append (maxCommentStart + start )
380394
381395 # Try to read the "Zip64 end of central directory" structure
382- return _EndRecData64 (fpin , maxCommentStart + start - filesize ,
383- endrec )
396+ return _EndRecData64 (fpin , maxCommentStart + start , endrec )
384397
385398 # Unable to find a valid end of central directory structure
386399 return None
@@ -2142,7 +2155,7 @@ def _write_end_record(self):
21422155 " would require ZIP64 extensions" )
21432156 zip64endrec = struct .pack (
21442157 structEndArchive64 , stringEndArchive64 ,
2145- 44 , 45 , 45 , 0 , 0 , centDirCount , centDirCount ,
2158+ sizeEndCentDir64 - 12 , 45 , 45 , 0 , 0 , centDirCount , centDirCount ,
21462159 centDirSize , centDirOffset )
21472160 self .fp .write (zip64endrec )
21482161
0 commit comments