From 3fc54cf68c653b596f239fbfb0181f4a8df57475 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Mon, 30 Jan 2023 11:13:01 +0100 Subject: [PATCH] feat: Detect insufficient Dir record size - Per zip spec 4.4.1.4 (https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT) - If a CentralDirectoryEnd record field cannot hold the required data, a ZIP64 record must exist and the field will be set to -1(0xFFFF || 0xFFFFFFFF) - Previously these archives were incorrectly detected as multi-disk --- src/read.rs | 6 ++++-- src/spec.rs | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/read.rs b/src/read.rs index 9c40e656..dad20c26 100644 --- a/src/read.rs +++ b/src/read.rs @@ -348,7 +348,9 @@ impl ZipArchive { Some(locator64) => { // If we got here, this is indeed a ZIP64 file. - if footer.disk_number as u32 != locator64.disk_with_central_directory { + if !footer.record_too_small() + && footer.disk_number as u32 != locator64.disk_with_central_directory + { return unsupported_zip_error( "Support for multi-disk files is not implemented", ); @@ -401,7 +403,7 @@ impl ZipArchive { pub fn new(mut reader: R) -> ZipResult> { let (footer, cde_start_pos) = spec::CentralDirectoryEnd::find_and_parse(&mut reader)?; - if footer.disk_number != footer.disk_with_central_directory { + if !footer.record_too_small() && footer.disk_number != footer.disk_with_central_directory { return unsupported_zip_error("Support for multi-disk files is not implemented"); } diff --git a/src/spec.rs b/src/spec.rs index 2ed051b1..1d8cb0a6 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -23,6 +23,18 @@ pub struct CentralDirectoryEnd { } impl CentralDirectoryEnd { + // Per spec 4.4.1.4 - a CentralDirectoryEnd field might be insufficient to hold the + // required data. In this case the file SHOULD contain a ZIP64 format record + // and the field of this record will be set to -1 + pub(crate) fn record_too_small(&self) -> bool { + self.disk_number == 0xFFFF + || self.disk_with_central_directory == 0xFFFF + || self.number_of_files_on_this_disk == 0xFFFF + || self.number_of_files == 0xFFFF + || self.central_directory_size == 0xFFFFFFFF + || self.central_directory_offset == 0xFFFFFFFF + } + pub fn parse(reader: &mut T) -> ZipResult { let magic = reader.read_u32::()?; if magic != CENTRAL_DIRECTORY_END_SIGNATURE {