@@ -406,114 +406,121 @@ def _read_directory(archive):
406
406
raise ZipImportError (f"can't open Zip file: { archive !r} " , path = archive )
407
407
408
408
with fp :
409
+ # GH-87235: On macOS all file descriptors for /dev/fd/N share the same
410
+ # file offset, reset the file offset after scanning the zipfile diretory
411
+ # to not cause problems when some runs 'python3 /dev/fd/9 9<some_script'
412
+ start_offset = fp .tell ()
409
413
try :
410
- fp .seek (- END_CENTRAL_DIR_SIZE , 2 )
411
- header_position = fp .tell ()
412
- buffer = fp .read (END_CENTRAL_DIR_SIZE )
413
- except OSError :
414
- raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
415
- if len (buffer ) != END_CENTRAL_DIR_SIZE :
416
- raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
417
- if buffer [:4 ] != STRING_END_ARCHIVE :
418
- # Bad: End of Central Dir signature
419
- # Check if there's a comment.
420
414
try :
421
- fp .seek (0 , 2 )
422
- file_size = fp .tell ()
423
- except OSError :
424
- raise ZipImportError (f"can't read Zip file: { archive !r} " ,
425
- path = archive )
426
- max_comment_start = max (file_size - MAX_COMMENT_LEN -
427
- END_CENTRAL_DIR_SIZE , 0 )
428
- try :
429
- fp .seek (max_comment_start )
430
- data = fp .read ()
431
- except OSError :
432
- raise ZipImportError (f"can't read Zip file: { archive !r} " ,
433
- path = archive )
434
- pos = data .rfind (STRING_END_ARCHIVE )
435
- if pos < 0 :
436
- raise ZipImportError (f'not a Zip file: { archive !r} ' ,
437
- path = archive )
438
- buffer = data [pos :pos + END_CENTRAL_DIR_SIZE ]
439
- if len (buffer ) != END_CENTRAL_DIR_SIZE :
440
- raise ZipImportError (f"corrupt Zip file: { archive !r} " ,
441
- path = archive )
442
- header_position = file_size - len (data ) + pos
443
-
444
- header_size = _unpack_uint32 (buffer [12 :16 ])
445
- header_offset = _unpack_uint32 (buffer [16 :20 ])
446
- if header_position < header_size :
447
- raise ZipImportError (f'bad central directory size: { archive !r} ' , path = archive )
448
- if header_position < header_offset :
449
- raise ZipImportError (f'bad central directory offset: { archive !r} ' , path = archive )
450
- header_position -= header_size
451
- arc_offset = header_position - header_offset
452
- if arc_offset < 0 :
453
- raise ZipImportError (f'bad central directory size or offset: { archive !r} ' , path = archive )
454
-
455
- files = {}
456
- # Start of Central Directory
457
- count = 0
458
- try :
459
- fp .seek (header_position )
460
- except OSError :
461
- raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
462
- while True :
463
- buffer = fp .read (46 )
464
- if len (buffer ) < 4 :
465
- raise EOFError ('EOF read where not expected' )
466
- # Start of file header
467
- if buffer [:4 ] != b'PK\x01 \x02 ' :
468
- break # Bad: Central Dir File Header
469
- if len (buffer ) != 46 :
470
- raise EOFError ('EOF read where not expected' )
471
- flags = _unpack_uint16 (buffer [8 :10 ])
472
- compress = _unpack_uint16 (buffer [10 :12 ])
473
- time = _unpack_uint16 (buffer [12 :14 ])
474
- date = _unpack_uint16 (buffer [14 :16 ])
475
- crc = _unpack_uint32 (buffer [16 :20 ])
476
- data_size = _unpack_uint32 (buffer [20 :24 ])
477
- file_size = _unpack_uint32 (buffer [24 :28 ])
478
- name_size = _unpack_uint16 (buffer [28 :30 ])
479
- extra_size = _unpack_uint16 (buffer [30 :32 ])
480
- comment_size = _unpack_uint16 (buffer [32 :34 ])
481
- file_offset = _unpack_uint32 (buffer [42 :46 ])
482
- header_size = name_size + extra_size + comment_size
483
- if file_offset > header_offset :
484
- raise ZipImportError (f'bad local header offset: { archive !r} ' , path = archive )
485
- file_offset += arc_offset
486
-
487
- try :
488
- name = fp .read (name_size )
415
+ fp .seek (- END_CENTRAL_DIR_SIZE , 2 )
416
+ header_position = fp .tell ()
417
+ buffer = fp .read (END_CENTRAL_DIR_SIZE )
489
418
except OSError :
490
419
raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
491
- if len (name ) != name_size :
420
+ if len (buffer ) != END_CENTRAL_DIR_SIZE :
492
421
raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
493
- # On Windows, calling fseek to skip over the fields we don't use is
494
- # slower than reading the data because fseek flushes stdio's
495
- # internal buffers. See issue #8745.
422
+ if buffer [:4 ] != STRING_END_ARCHIVE :
423
+ # Bad: End of Central Dir signature
424
+ # Check if there's a comment.
425
+ try :
426
+ fp .seek (0 , 2 )
427
+ file_size = fp .tell ()
428
+ except OSError :
429
+ raise ZipImportError (f"can't read Zip file: { archive !r} " ,
430
+ path = archive )
431
+ max_comment_start = max (file_size - MAX_COMMENT_LEN -
432
+ END_CENTRAL_DIR_SIZE , 0 )
433
+ try :
434
+ fp .seek (max_comment_start )
435
+ data = fp .read ()
436
+ except OSError :
437
+ raise ZipImportError (f"can't read Zip file: { archive !r} " ,
438
+ path = archive )
439
+ pos = data .rfind (STRING_END_ARCHIVE )
440
+ if pos < 0 :
441
+ raise ZipImportError (f'not a Zip file: { archive !r} ' ,
442
+ path = archive )
443
+ buffer = data [pos :pos + END_CENTRAL_DIR_SIZE ]
444
+ if len (buffer ) != END_CENTRAL_DIR_SIZE :
445
+ raise ZipImportError (f"corrupt Zip file: { archive !r} " ,
446
+ path = archive )
447
+ header_position = file_size - len (data ) + pos
448
+
449
+ header_size = _unpack_uint32 (buffer [12 :16 ])
450
+ header_offset = _unpack_uint32 (buffer [16 :20 ])
451
+ if header_position < header_size :
452
+ raise ZipImportError (f'bad central directory size: { archive !r} ' , path = archive )
453
+ if header_position < header_offset :
454
+ raise ZipImportError (f'bad central directory offset: { archive !r} ' , path = archive )
455
+ header_position -= header_size
456
+ arc_offset = header_position - header_offset
457
+ if arc_offset < 0 :
458
+ raise ZipImportError (f'bad central directory size or offset: { archive !r} ' , path = archive )
459
+
460
+ files = {}
461
+ # Start of Central Directory
462
+ count = 0
496
463
try :
497
- if len (fp .read (header_size - name_size )) != header_size - name_size :
498
- raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
464
+ fp .seek (header_position )
499
465
except OSError :
500
466
raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
467
+ while True :
468
+ buffer = fp .read (46 )
469
+ if len (buffer ) < 4 :
470
+ raise EOFError ('EOF read where not expected' )
471
+ # Start of file header
472
+ if buffer [:4 ] != b'PK\x01 \x02 ' :
473
+ break # Bad: Central Dir File Header
474
+ if len (buffer ) != 46 :
475
+ raise EOFError ('EOF read where not expected' )
476
+ flags = _unpack_uint16 (buffer [8 :10 ])
477
+ compress = _unpack_uint16 (buffer [10 :12 ])
478
+ time = _unpack_uint16 (buffer [12 :14 ])
479
+ date = _unpack_uint16 (buffer [14 :16 ])
480
+ crc = _unpack_uint32 (buffer [16 :20 ])
481
+ data_size = _unpack_uint32 (buffer [20 :24 ])
482
+ file_size = _unpack_uint32 (buffer [24 :28 ])
483
+ name_size = _unpack_uint16 (buffer [28 :30 ])
484
+ extra_size = _unpack_uint16 (buffer [30 :32 ])
485
+ comment_size = _unpack_uint16 (buffer [32 :34 ])
486
+ file_offset = _unpack_uint32 (buffer [42 :46 ])
487
+ header_size = name_size + extra_size + comment_size
488
+ if file_offset > header_offset :
489
+ raise ZipImportError (f'bad local header offset: { archive !r} ' , path = archive )
490
+ file_offset += arc_offset
501
491
502
- if flags & 0x800 :
503
- # UTF-8 file names extension
504
- name = name .decode ()
505
- else :
506
- # Historical ZIP filename encoding
507
492
try :
508
- name = name .decode ('ascii' )
509
- except UnicodeDecodeError :
510
- name = name .decode ('latin1' ).translate (cp437_table )
511
-
512
- name = name .replace ('/' , path_sep )
513
- path = _bootstrap_external ._path_join (archive , name )
514
- t = (path , compress , data_size , file_size , file_offset , time , date , crc )
515
- files [name ] = t
516
- count += 1
493
+ name = fp .read (name_size )
494
+ except OSError :
495
+ raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
496
+ if len (name ) != name_size :
497
+ raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
498
+ # On Windows, calling fseek to skip over the fields we don't use is
499
+ # slower than reading the data because fseek flushes stdio's
500
+ # internal buffers. See issue #8745.
501
+ try :
502
+ if len (fp .read (header_size - name_size )) != header_size - name_size :
503
+ raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
504
+ except OSError :
505
+ raise ZipImportError (f"can't read Zip file: { archive !r} " , path = archive )
506
+
507
+ if flags & 0x800 :
508
+ # UTF-8 file names extension
509
+ name = name .decode ()
510
+ else :
511
+ # Historical ZIP filename encoding
512
+ try :
513
+ name = name .decode ('ascii' )
514
+ except UnicodeDecodeError :
515
+ name = name .decode ('latin1' ).translate (cp437_table )
516
+
517
+ name = name .replace ('/' , path_sep )
518
+ path = _bootstrap_external ._path_join (archive , name )
519
+ t = (path , compress , data_size , file_size , file_offset , time , date , crc )
520
+ files [name ] = t
521
+ count += 1
522
+ finally :
523
+ fp .seek (start_offset )
517
524
_bootstrap ._verbose_message ('zipimport: found {} names in {!r}' , count , archive )
518
525
return files
519
526
0 commit comments