Skip to content

Alter ZipFile.data_offset calculation #136170

Closed as duplicate
Closed as duplicate

Description

@danifus

Bug report

Bug description:

Zip implementations interpret the zip appnote with regards to offset fields in the central directory differently centDirOffset (offset of start of central directory with respect to the starting disk number) and relative offset of local header. Some implementations will store the number of bytes from the first local header (eg. 7zip - I tested by adding self extracting content with 7zz) while others will store the number of bytes from the start of the file (eg. infozip, python's zipfile which I didn't expect!). The two approaches only produce different results when data is prepended to an archive.

When prepended data is present, ZipFile.data_offset will contain different values for the different implementations.

Taking the example provided by @danny0838 in this comment: #134627 (comment)

with open('archive.zip', 'wb') as fh:
    fh.write(b'dummy')
    with zipfile.ZipFile(fh, 'a') as zh:
        zh.writestr('file', 'file content')

with zipfile.ZipFile('archive.zip') as zh:
    print(zh.data_offset)  # 0
    print(zh.infolist()[0].header_offset)  # 5
    print(zh.start_dir)  # 51

zh.data_offset should be 5

Related: #84481

CPython versions tested on:

3.14

Operating systems tested on:

macOS

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Jul 1, 2025
  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Jul 1, 2025
  3. added 2 commits that reference this issue on Jul 1, 2025
  4. danny0838 commented on Jul 1, 2025

    @danny0838
    Contributor

    Thank you. I was considering raising an issue for this.

    I think we have to first determine what the main purpose (or expected use case) of data_offset is. Seeing the original issue #84481 the data_offset can be used to detect whether a prefixed (potentially malware) payload exists, in which case the zip file can have bytes before data_offset stripped safely when it's non-zero.

    1. central directory offsets calculated from the first local header (can strip bytes 0..5)

      with open('archive.zip', 'wb') as fh:
          fh.write(b'dummy')
          with zipfile.ZipFile(fh, 'a') as zh:
              zh.writestr('file', 'file content')
      
      with zipfile.ZipFile('archive.zip') as zh:
          print(zh.data_offset)  # 5
          print(zh.filelist[0].header_offset)  # 5
          print(zh.start_dir)  # 51
    2. central directory offsets calculated from the start of the file (cannot strip bytes 0..5)

      with open('archive.zip', 'wb') as fh:
          with zipfile.ZipFile(fh, 'a') as zh:
              fh.write(b'dummy')
              zh.start_dir = fh.tell()
              zh.writestr('file', 'file content')
      
      with zipfile.ZipFile('archive.zip') as zh:
          print(zh.data_offset)  # 0
          print(zh.filelist[0].header_offset)  # 5
          print(zh.start_dir)  # 51

    The proposed PR 136171 will break the feature since case 2 cannot be stripped in the same way as case 1.

    When stripping case 2, the resulting zip file can be read by zipfile, with a negative concat value. However, the support of other zip apps varies. For example, 7z supports it while Windows file explorer does not.

    OTOH, I don't see there are too many potential useful case for the proposed data_offset, and would tend to simply remove it since the developer can simply calculate the value on the fly when it's really needed (like what zipfile.repack has done).

  5. danny0838 commented on Jul 6, 2025

    @danny0838
    Contributor

    Maybe we should ask @emmatyping, the original PR provider, about the intention of the implementation of this API.

  6. emmatyping commented on Jul 21, 2025

    @emmatyping
    Member

    Since 3.14rc1 is tomorrow and the interpretation of the attribute is unclear, I decided to simply revert the addition: #136950

  7. added a commit that references this issue on Jul 21, 2025
  8. added a commit that references this issue on Jul 21, 2025
  9. danny0838 commented on Jul 21, 2025

    @danny0838
    Contributor

    Should the original issue #84481 be reopened? [done]

  10. added a commit that references this issue on Jul 22, 2025
  11. emmatyping commented on Jul 22, 2025

    @emmatyping
    Member

    I suggest we close this as the feature was reverted and leave any follow up to #84481.

  12. added a commit that references this issue on Aug 4, 2025
  13. added a commit that references this issue on Aug 19, 2025
  14. added a commit that references this issue on Sep 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions