(archive)
| 344 | # Directories can be recognized by the trailing path_sep in the name, |
| 345 | # data_size and file_offset are 0. |
| 346 | def _read_directory(archive): |
| 347 | try: |
| 348 | fp = _io.open_code(archive) |
| 349 | except OSError: |
| 350 | raise ZipImportError(f"can't open Zip file: {archive!r}", path=archive) |
| 351 | |
| 352 | with fp: |
| 353 | # GH-87235: On macOS all file descriptors for /dev/fd/N share the same |
| 354 | # file offset, reset the file offset after scanning the zipfile directory |
| 355 | # to not cause problems when some runs 'python3 /dev/fd/9 9<some_script' |
| 356 | start_offset = fp.tell() |
| 357 | try: |
| 358 | # Check if there's a comment. |
| 359 | try: |
| 360 | fp.seek(0, 2) |
| 361 | file_size = fp.tell() |
| 362 | except OSError: |
| 363 | raise ZipImportError(f"can't read Zip file: {archive!r}", |
| 364 | path=archive) |
| 365 | max_comment_plus_dirs_size = ( |
| 366 | MAX_COMMENT_LEN + END_CENTRAL_DIR_SIZE + |
| 367 | END_CENTRAL_DIR_SIZE_64 + END_CENTRAL_DIR_LOCATOR_SIZE_64) |
| 368 | max_comment_start = max(file_size - max_comment_plus_dirs_size, 0) |
| 369 | try: |
| 370 | fp.seek(max_comment_start) |
| 371 | data = fp.read(max_comment_plus_dirs_size) |
| 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 | pos64 = data.rfind(STRING_END_ZIP_64) |
| 377 | |
| 378 | if (pos64 >= 0 and pos64+END_CENTRAL_DIR_SIZE_64+END_CENTRAL_DIR_LOCATOR_SIZE_64==pos): |
| 379 | # Zip64 at "correct" offset from standard EOCD |
| 380 | buffer = data[pos64:pos64 + END_CENTRAL_DIR_SIZE_64] |
| 381 | if len(buffer) != END_CENTRAL_DIR_SIZE_64: |
| 382 | raise ZipImportError( |
| 383 | f"corrupt Zip64 file: Expected {END_CENTRAL_DIR_SIZE_64} byte " |
| 384 | f"zip64 central directory, but read {len(buffer)} bytes.", |
| 385 | path=archive) |
| 386 | header_position = file_size - len(data) + pos64 |
| 387 | |
| 388 | central_directory_size = _unpack_uint64(buffer[40:48]) |
| 389 | central_directory_position = _unpack_uint64(buffer[48:56]) |
| 390 | num_entries = _unpack_uint64(buffer[24:32]) |
| 391 | elif pos >= 0: |
| 392 | buffer = data[pos:pos+END_CENTRAL_DIR_SIZE] |
| 393 | if len(buffer) != END_CENTRAL_DIR_SIZE: |
| 394 | raise ZipImportError(f"corrupt Zip file: {archive!r}", |
| 395 | path=archive) |
| 396 | |
| 397 | header_position = file_size - len(data) + pos |
| 398 | |
| 399 | # Buffer now contains a valid EOCD, and header_position gives the |
| 400 | # starting position of it. |
| 401 | central_directory_size = _unpack_uint32(buffer[12:16]) |
| 402 | central_directory_position = _unpack_uint32(buffer[16:20]) |
| 403 | num_entries = _unpack_uint16(buffer[8:10]) |
no test coverage detected