Skip to content

Commit

Permalink
Fix panic when a non-zip64 local header is written after 0xFFFFFFFF
Browse files Browse the repository at this point in the history
The zip spec allows non-zip64 local headers to be written at offset
>=2^32 as long as the corresponding central directory entry has a zip64
extra field for the local header offset. However, when writing a
non-zip64 small file after the 2^32 boundary, `local_header_size()`
would return a zip64 size while writing a non-zip64 local header to
disk. This would cause `self.stats.start` to get out of sync, leading to
a panic in `finish_file()` when doing a checked subtraction for
`self.compressed_size`. This would only manifest when performing
streaming writes.

This commit fixes the problem by updating `local_header_size()` to use a
new `zip64_sizes()` method that only considers the compressed and
uncompressed size fields since only those two matter for determining the
size of a local header.

Signed-off-by: Andrew Gunnerson <[email protected]>
  • Loading branch information
chenxiaolong committed Aug 25, 2023
1 parent 1810537 commit 989101f
Showing 1 changed file with 8 additions and 2 deletions.
10 changes: 8 additions & 2 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,9 +422,13 @@ impl ZipFileData {
}
}

pub fn zip64_extension(&self) -> bool {
pub(crate) fn zip64_sizes(&self) -> bool {
self.uncompressed_size > 0xFFFFFFFF
|| self.compressed_size > 0xFFFFFFFF
}

pub fn zip64_extension(&self) -> bool {
self.zip64_sizes()
|| self.header_start > 0xFFFFFFFF
}

Expand All @@ -449,7 +453,9 @@ impl ZipFileData {
} else {
size += self.file_name_raw.len() as u64;
};
if self.zip64_extension() || self.large_file {
// The local header does not necessarily need to be zip64 when its
// offset exceeds the 2^32 boundary.
if self.zip64_sizes() || self.large_file {
size += 20;
}
size
Expand Down

0 comments on commit 989101f

Please sign in to comment.