@@ -347,114 +347,121 @@ def _read_directory(archive):
347347 raise ZipImportError (f"can't open Zip file: { archive !r} " , path = archive )
348348
349349 with fp :
350+ # GH-87235: On macOS all file descriptors for /dev/fd/N share the same
351+ # file offset, reset the file offset after scanning the zipfile diretory
352+ # to not cause problems when some runs 'python3 /dev/fd/9 9<some_script'
353+ start_offset = fp .tell ()
350354 try :
351- fp .seek (- END_CENTRAL_DIR_SIZE , 2 )
352- header_position = fp .tell ()
353- buffer = fp .read (END_CENTRAL_DIR_SIZE )
354- except OSError :
355- raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
356- if len (buffer ) != END_CENTRAL_DIR_SIZE :
357- raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
358- if buffer [:4 ] != STRING_END_ARCHIVE :
359- # Bad: End of Central Dir signature
360- # Check if there's a comment.
361355 try :
362- fp .seek (0 , 2 )
363- file_size = fp .tell ()
364- except OSError :
365- raise ZipImportError (f"can't read Zip file: { archive !r} " ,
366- path = archive )
367- max_comment_start = max (file_size - MAX_COMMENT_LEN -
368- END_CENTRAL_DIR_SIZE , 0 )
369- try :
370- fp .seek (max_comment_start )
371- data = fp .read ()
372- except OSError :
373- raise ZipImportError (f"can't read Zip file: { archive !r} " ,
374- path = archive )
375- pos = data .rfind (STRING_END_ARCHIVE )
376- if pos < 0 :
377- raise ZipImportError (f'not a Zip file: { archive !r} ' ,
378- path = archive )
379- buffer = data [pos :pos + END_CENTRAL_DIR_SIZE ]
380- if len (buffer ) != END_CENTRAL_DIR_SIZE :
381- raise ZipImportError (f"corrupt Zip file: { archive !r} " ,
382- path = archive )
383- header_position = file_size - len (data ) + pos
384-
385- header_size = _unpack_uint32 (buffer [12 :16 ])
386- header_offset = _unpack_uint32 (buffer [16 :20 ])
387- if header_position < header_size :
388- raise ZipImportError (f'bad central directory size: { archive !r} ' , path = archive )
389- if header_position < header_offset :
390- raise ZipImportError (f'bad central directory offset: { archive !r} ' , path = archive )
391- header_position -= header_size
392- arc_offset = header_position - header_offset
393- if arc_offset < 0 :
394- raise ZipImportError (f'bad central directory size or offset: { archive !r} ' , path = archive )
395-
396- files = {}
397- # Start of Central Directory
398- count = 0
399- try :
400- fp .seek (header_position )
401- except OSError :
402- raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
403- while True :
404- buffer = fp .read (46 )
405- if len (buffer ) < 4 :
406- raise EOFError ('EOF read where not expected' )
407- # Start of file header
408- if buffer [:4 ] != b'PK\x01 \x02 ' :
409- break # Bad: Central Dir File Header
410- if len (buffer ) != 46 :
411- raise EOFError ('EOF read where not expected' )
412- flags = _unpack_uint16 (buffer [8 :10 ])
413- compress = _unpack_uint16 (buffer [10 :12 ])
414- time = _unpack_uint16 (buffer [12 :14 ])
415- date = _unpack_uint16 (buffer [14 :16 ])
416- crc = _unpack_uint32 (buffer [16 :20 ])
417- data_size = _unpack_uint32 (buffer [20 :24 ])
418- file_size = _unpack_uint32 (buffer [24 :28 ])
419- name_size = _unpack_uint16 (buffer [28 :30 ])
420- extra_size = _unpack_uint16 (buffer [30 :32 ])
421- comment_size = _unpack_uint16 (buffer [32 :34 ])
422- file_offset = _unpack_uint32 (buffer [42 :46 ])
423- header_size = name_size + extra_size + comment_size
424- if file_offset > header_offset :
425- raise ZipImportError (f'bad local header offset: { archive !r} ' , path = archive )
426- file_offset += arc_offset
427-
428- try :
429- name = fp .read (name_size )
356+ fp .seek (- END_CENTRAL_DIR_SIZE , 2 )
357+ header_position = fp .tell ()
358+ buffer = fp .read (END_CENTRAL_DIR_SIZE )
430359 except OSError :
431360 raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
432- if len (name ) != name_size :
361+ if len (buffer ) != END_CENTRAL_DIR_SIZE :
433362 raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
434- # On Windows, calling fseek to skip over the fields we don't use is
435- # slower than reading the data because fseek flushes stdio's
436- # internal buffers. See issue #8745.
363+ if buffer [:4 ] != STRING_END_ARCHIVE :
364+ # Bad: End of Central Dir signature
365+ # Check if there's a comment.
366+ try :
367+ fp .seek (0 , 2 )
368+ file_size = fp .tell ()
369+ except OSError :
370+ raise ZipImportError (f"can't read Zip file: { archive !r} " ,
371+ path = archive )
372+ max_comment_start = max (file_size - MAX_COMMENT_LEN -
373+ END_CENTRAL_DIR_SIZE , 0 )
374+ try :
375+ fp .seek (max_comment_start )
376+ data = fp .read ()
377+ except OSError :
378+ raise ZipImportError (f"can't read Zip file: { archive !r} " ,
379+ path = archive )
380+ pos = data .rfind (STRING_END_ARCHIVE )
381+ if pos < 0 :
382+ raise ZipImportError (f'not a Zip file: { archive !r} ' ,
383+ path = archive )
384+ buffer = data [pos :pos + END_CENTRAL_DIR_SIZE ]
385+ if len (buffer ) != END_CENTRAL_DIR_SIZE :
386+ raise ZipImportError (f"corrupt Zip file: { archive !r} " ,
387+ path = archive )
388+ header_position = file_size - len (data ) + pos
389+
390+ header_size = _unpack_uint32 (buffer [12 :16 ])
391+ header_offset = _unpack_uint32 (buffer [16 :20 ])
392+ if header_position < header_size :
393+ raise ZipImportError (f'bad central directory size: { archive !r} ' , path = archive )
394+ if header_position < header_offset :
395+ raise ZipImportError (f'bad central directory offset: { archive !r} ' , path = archive )
396+ header_position -= header_size
397+ arc_offset = header_position - header_offset
398+ if arc_offset < 0 :
399+ raise ZipImportError (f'bad central directory size or offset: { archive !r} ' , path = archive )
400+
401+ files = {}
402+ # Start of Central Directory
403+ count = 0
437404 try :
438- if len (fp .read (header_size - name_size )) != header_size - name_size :
439- raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
405+ fp .seek (header_position )
440406 except OSError :
441407 raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
408+ while True :
409+ buffer = fp .read (46 )
410+ if len (buffer ) < 4 :
411+ raise EOFError ('EOF read where not expected' )
412+ # Start of file header
413+ if buffer [:4 ] != b'PK\x01 \x02 ' :
414+ break # Bad: Central Dir File Header
415+ if len (buffer ) != 46 :
416+ raise EOFError ('EOF read where not expected' )
417+ flags = _unpack_uint16 (buffer [8 :10 ])
418+ compress = _unpack_uint16 (buffer [10 :12 ])
419+ time = _unpack_uint16 (buffer [12 :14 ])
420+ date = _unpack_uint16 (buffer [14 :16 ])
421+ crc = _unpack_uint32 (buffer [16 :20 ])
422+ data_size = _unpack_uint32 (buffer [20 :24 ])
423+ file_size = _unpack_uint32 (buffer [24 :28 ])
424+ name_size = _unpack_uint16 (buffer [28 :30 ])
425+ extra_size = _unpack_uint16 (buffer [30 :32 ])
426+ comment_size = _unpack_uint16 (buffer [32 :34 ])
427+ file_offset = _unpack_uint32 (buffer [42 :46 ])
428+ header_size = name_size + extra_size + comment_size
429+ if file_offset > header_offset :
430+ raise ZipImportError (f'bad local header offset: { archive !r} ' , path = archive )
431+ file_offset += arc_offset
442432
443- if flags & 0x800 :
444- # UTF-8 file names extension
445- name = name .decode ()
446- else :
447- # Historical ZIP filename encoding
448433 try :
449- name = name .decode ('ascii' )
450- except UnicodeDecodeError :
451- name = name .decode ('latin1' ).translate (cp437_table )
452-
453- name = name .replace ('/' , path_sep )
454- path = _bootstrap_external ._path_join (archive , name )
455- t = (path , compress , data_size , file_size , file_offset , time , date , crc )
456- files [name ] = t
457- count += 1
434+ name = fp .read (name_size )
435+ except OSError :
436+ raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
437+ if len (name ) != name_size :
438+ raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
439+ # On Windows, calling fseek to skip over the fields we don't use is
440+ # slower than reading the data because fseek flushes stdio's
441+ # internal buffers. See issue #8745.
442+ try :
443+ if len (fp .read (header_size - name_size )) != header_size - name_size :
444+ raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
445+ except OSError :
446+ raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
447+
448+ if flags & 0x800 :
449+ # UTF-8 file names extension
450+ name = name .decode ()
451+ else :
452+ # Historical ZIP filename encoding
453+ try :
454+ name = name .decode ('ascii' )
455+ except UnicodeDecodeError :
456+ name = name .decode ('latin1' ).translate (cp437_table )
457+
458+ name = name .replace ('/' , path_sep )
459+ path = _bootstrap_external ._path_join (archive , name )
460+ t = (path , compress , data_size , file_size , file_offset , time , date , crc )
461+ files [name ] = t
462+ count += 1
463+ finally :
464+ fp .seek (start_offset )
458465 _bootstrap ._verbose_message ('zipimport: found {} names in {!r}' , count , archive )
459466 return files
460467
0 commit comments