Fix failing tests other than deflate64 bug 25

This commit is contained in:
Chris Hennick 2024-03-07 15:16:04 -08:00
parent e23ba853d3
commit 5e03f43f9a
2 changed files with 51 additions and 47 deletions

View file

@ -5,6 +5,7 @@ use crate::aes::{AesReader, AesReaderValid};
use crate::compression::CompressionMethod; use crate::compression::CompressionMethod;
use crate::cp437::FromCp437; use crate::cp437::FromCp437;
use crate::crc32::Crc32Reader; use crate::crc32::Crc32Reader;
use crate::read::zip_archive::Shared;
use crate::result::{InvalidPassword, ZipError, ZipResult}; use crate::result::{InvalidPassword, ZipError, ZipResult};
use crate::spec; use crate::spec;
use crate::types::{AesMode, AesVendorVersion, AtomicU64, DateTime, System, ZipFileData}; use crate::types::{AesMode, AesVendorVersion, AtomicU64, DateTime, System, ZipFileData};
@ -74,11 +75,10 @@ pub(crate) mod zip_archive {
pub struct ZipArchive<R> { pub struct ZipArchive<R> {
pub(super) reader: R, pub(super) reader: R,
pub(super) shared: Arc<Shared>, pub(super) shared: Arc<Shared>,
pub(super) comment: Vec<u8>, pub(super) comment: Arc<Vec<u8>>,
} }
} }
use crate::read::zip_archive::Shared;
pub use zip_archive::ZipArchive; pub use zip_archive::ZipArchive;
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
@ -381,43 +381,45 @@ impl<R: Read + Seek> ZipArchive<R> {
.ok_or(ZipError::InvalidArchive( .ok_or(ZipError::InvalidArchive(
"File cannot contain ZIP64 central directory end", "File cannot contain ZIP64 central directory end",
))?; ))?;
while let Ok((footer64, archive_offset)) = spec::Zip64CentralDirectoryEnd::find_and_parse( let search_results = spec::Zip64CentralDirectoryEnd::find_and_parse(
reader, reader,
locator64.end_of_central_directory_offset, locator64.end_of_central_directory_offset,
search_upper_bound, search_upper_bound,
) { )?;
search_results.into_iter().for_each(|(footer64, archive_offset)| {
results.push({ results.push({
let directory_start = footer64 let directory_start_result = footer64
.central_directory_offset .central_directory_offset
.checked_add(archive_offset) .checked_add(archive_offset)
.ok_or(ZipError::InvalidArchive( .ok_or(ZipError::InvalidArchive(
"Invalid central directory size or offset", "Invalid central directory size or offset",
))?;
if directory_start > search_upper_bound {
return Err(ZipError::InvalidArchive(
"Invalid central directory size or offset",
)); ));
} directory_start_result.and_then(|directory_start| {
if footer64.number_of_files_on_this_disk > footer64.number_of_files { if directory_start > search_upper_bound {
return Err(ZipError::InvalidArchive( Err(ZipError::InvalidArchive(
"ZIP64 footer indicates more files on this disk than in the whole archive", "Invalid central directory size or offset",
)); ))
} } else if footer64.number_of_files_on_this_disk > footer64.number_of_files {
if footer64.version_needed_to_extract > footer64.version_made_by { Err(ZipError::InvalidArchive(
return Err(ZipError::InvalidArchive( "ZIP64 footer indicates more files on this disk than in the whole archive",
"ZIP64 footer indicates a new version is needed to extract this archive than the \ ))
} else if footer64.version_needed_to_extract > footer64.version_made_by {
Err(ZipError::InvalidArchive(
"ZIP64 footer indicates a new version is needed to extract this archive than the \
version that wrote it", version that wrote it",
)); ))
} } else {
Ok(CentralDirectoryInfo { Ok(CentralDirectoryInfo {
archive_offset, archive_offset,
directory_start, directory_start,
number_of_files: footer64.number_of_files as usize, number_of_files: footer64.number_of_files as usize,
disk_number: footer64.disk_number, disk_number: footer64.disk_number,
disk_with_central_directory: footer64.disk_with_central_directory, disk_with_central_directory: footer64.disk_with_central_directory,
})
}
}) })
}); });
} });
Ok(results) Ok(results)
} }
@ -480,25 +482,23 @@ impl<R: Read + Seek> ZipArchive<R> {
}; };
let mut files = Vec::with_capacity(file_capacity); let mut files = Vec::with_capacity(file_capacity);
let mut names_map = HashMap::with_capacity(file_capacity); let mut names_map = HashMap::with_capacity(file_capacity);
let dir_end = reader.seek(io::SeekFrom::Start(dir_info.directory_start))?;
for _ in 0..dir_info.number_of_files { for _ in 0..dir_info.number_of_files {
let file = central_header_to_zip_file(reader, dir_info.archive_offset)?; let file = central_header_to_zip_file(reader, dir_info.archive_offset)?;
names_map.insert(file.file_name.clone(), files.len()); names_map.insert(file.file_name.clone(), files.len());
files.push(file); files.push(file);
} }
let dir_end = reader.seek(io::SeekFrom::Start(dir_info.directory_start))?;
if dir_info.disk_number != dir_info.disk_with_central_directory { if dir_info.disk_number != dir_info.disk_with_central_directory {
return unsupported_zip_error( unsupported_zip_error("Support for multi-disk files is not implemented")
"Support for multi-disk files is not implemented", } else {
); Ok(Shared {
files,
names_map,
offset: dir_info.archive_offset,
dir_start: dir_info.directory_start,
dir_end,
})
} }
Ok(Shared {
files,
names_map,
offset: dir_info.archive_offset,
dir_start: dir_info.directory_start,
dir_end,
})
}) })
}) })
.for_each(|result| match result { .for_each(|result| match result {
@ -530,8 +530,8 @@ impl<R: Read + Seek> ZipArchive<R> {
let shared = Self::get_metadata(&mut reader, &footer, cde_start_pos)?; let shared = Self::get_metadata(&mut reader, &footer, cde_start_pos)?;
Ok(ZipArchive { Ok(ZipArchive {
reader, reader,
shared: Arc::new(shared), shared: shared.into(),
comment: footer.zip_file_comment, comment: footer.zip_file_comment.into(),
}) })
} }
/// Extract a Zip archive into a directory, overwriting files if they /// Extract a Zip archive into a directory, overwriting files if they

View file

@ -145,7 +145,8 @@ impl Zip64CentralDirectoryEnd {
reader: &mut T, reader: &mut T,
nominal_offset: u64, nominal_offset: u64,
search_upper_bound: u64, search_upper_bound: u64,
) -> ZipResult<(Zip64CentralDirectoryEnd, u64)> { ) -> ZipResult<Vec<(Zip64CentralDirectoryEnd, u64)>> {
let mut results = Vec::new();
let mut pos = search_upper_bound; let mut pos = search_upper_bound;
while pos >= nominal_offset { while pos >= nominal_offset {
@ -166,7 +167,7 @@ impl Zip64CentralDirectoryEnd {
let central_directory_size = reader.read_u64::<LittleEndian>()?; let central_directory_size = reader.read_u64::<LittleEndian>()?;
let central_directory_offset = reader.read_u64::<LittleEndian>()?; let central_directory_offset = reader.read_u64::<LittleEndian>()?;
return Ok(( results.push((
Zip64CentralDirectoryEnd { Zip64CentralDirectoryEnd {
version_made_by, version_made_by,
version_needed_to_extract, version_needed_to_extract,
@ -186,10 +187,13 @@ impl Zip64CentralDirectoryEnd {
break; break;
} }
} }
if results.is_empty() {
Err(ZipError::InvalidArchive( Err(ZipError::InvalidArchive(
"Could not find ZIP64 central directory end", "Could not find ZIP64 central directory end",
)) ))
} else {
Ok(results)
}
} }
pub fn write<T: Write>(&self, writer: &mut T) -> ZipResult<()> { pub fn write<T: Write>(&self, writer: &mut T) -> ZipResult<()> {