diff --git a/fuzz/fuzz_targets/fuzz_read.rs b/fuzz/fuzz_targets/fuzz_read.rs index 65076e4f..a5c5a3ff 100644 --- a/fuzz/fuzz_targets/fuzz_read.rs +++ b/fuzz/fuzz_targets/fuzz_read.rs @@ -1,6 +1,7 @@ #![no_main] use libfuzzer_sys::fuzz_target; -use std::io::Read; +use std::io::{Read, Seek, SeekFrom}; +use zip::read::read_zipfile_from_stream; const MAX_BYTES_TO_READ: u64 = 1 << 24; @@ -12,7 +13,11 @@ fn decompress_all(data: &[u8]) -> Result<(), Box> { let mut file = zip.by_index(i)?.take(MAX_BYTES_TO_READ); std::io::copy(&mut file, &mut std::io::sink())?; } - + let mut reader = zip.into_inner(); + reader.seek(SeekFrom::Start(0))?; + while let Ok(Some(mut file)) = read_zipfile_from_stream(&mut reader) { + std::io::copy(&mut file, &mut std::io::sink())?; + } Ok(()) } diff --git a/fuzz/fuzz_targets/fuzz_write.rs b/fuzz/fuzz_targets/fuzz_write.rs index 7fad5a20..f1f74a5e 100644 --- a/fuzz/fuzz_targets/fuzz_write.rs +++ b/fuzz/fuzz_targets/fuzz_write.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; #[derive(Arbitrary, Clone, Debug)] pub enum BasicFileOperation<'k> { WriteNormalFile { - contents: Vec>, + contents: Box<[Box<[u8]>]>, options: zip::write::FullFileOptions<'k>, }, WriteDirectory(zip::write::FullFileOptions<'k>), @@ -19,13 +19,21 @@ pub enum BasicFileOperation<'k> { }, ShallowCopy(Box>), DeepCopy(Box>), + MergeWithOtherFile(Box<[FileOperation<'k>]>) +} + +#[derive(Arbitrary, Clone, Debug)] +pub enum ReopenOption { + DoNotReopen, + ViaFinish, + ViaFinishIntoReadable } #[derive(Arbitrary, Clone, Debug)] pub struct FileOperation<'k> { basic: BasicFileOperation<'k>, path: PathBuf, - reopen: bool, + reopen: ReopenOption, // 'abort' flag is separate, to prevent trying to copy an aborted file } @@ -53,14 +61,14 @@ where options, .. } => { - let uncompressed_size = contents.iter().map(Vec::len).sum::(); + let uncompressed_size = contents.iter().map(|chunk| chunk.len()).sum::(); let mut options = (*options).to_owned(); if uncompressed_size >= u32::MAX as usize { options = options.large_file(true); } writer.start_file_from_path(path, options)?; - for chunk in contents { - writer.write_all(chunk.as_slice())?; + for chunk in contents.iter() { + writer.write_all(&chunk)?; } } BasicFileOperation::WriteDirectory(options) => { @@ -77,19 +85,33 @@ where do_operation(writer, &base, false, flush_on_finish_file)?; writer.deep_copy_file_from_path(&base.path, &path)?; } + BasicFileOperation::MergeWithOtherFile(other_ops) => { + let mut other_writer = zip::ZipWriter::new(Cursor::new(Vec::new())); + other_ops.iter().for_each(|operation| { + let _ = do_operation( + &mut other_writer, + &operation, + abort, + false, + ); + }); + writer.merge_archive(other_writer.finish_into_readable()?)?; + } } if abort { writer.abort_file().unwrap(); } - if operation.reopen { - let old_comment = writer.get_raw_comment().to_owned(); - replace_with_or_abort(writer, |old_writer: zip::ZipWriter| { - let new_writer = - zip::ZipWriter::new_append(old_writer.finish().unwrap()).unwrap(); - assert_eq!(&old_comment, new_writer.get_raw_comment()); - new_writer - }); + let old_comment = writer.get_raw_comment().to_owned(); + match operation.reopen { + ReopenOption::DoNotReopen => {}, + ReopenOption::ViaFinish => replace_with_or_abort(writer, |old_writer: zip::ZipWriter| { + zip::ZipWriter::new_append(old_writer.finish().unwrap()).unwrap() + }), + ReopenOption::ViaFinishIntoReadable => replace_with_or_abort(writer, |old_writer: zip::ZipWriter| { + zip::ZipWriter::new_append(old_writer.finish_into_readable().unwrap().into_inner()).unwrap() + }), } + assert_eq!(&old_comment, writer.get_raw_comment()); Ok(()) }