From 989101f9384b9e94e36e6e9e0f51908fdf98bde6 Mon Sep 17 00:00:00 2001 From: Andrew Gunnerson Date: Fri, 25 Aug 2023 01:47:46 -0400 Subject: [PATCH] Fix panic when a non-zip64 local header is written after 0xFFFFFFFF 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 --- src/types.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/types.rs b/src/types.rs index f65877f23..6de0036c0 100644 --- a/src/types.rs +++ b/src/types.rs @@ -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 } @@ -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