@@ -347,114 +347,121 @@ def _read_directory(archive):
347
347
raise ZipImportError (f"can't open Zip file: { archive !r} " , path = archive )
348
348
349
349
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 ()
350
354
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.
361
355
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 )
430
359
except OSError :
431
360
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 :
433
362
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
437
404
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 )
440
406
except OSError :
441
407
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
442
432
443
- if flags & 0x800 :
444
- # UTF-8 file names extension
445
- name = name .decode ()
446
- else :
447
- # Historical ZIP filename encoding
448
433
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 )
458
465
_bootstrap ._verbose_message ('zipimport: found {} names in {!r}' , count , archive )
459
466
return files
460
467
0 commit comments