Skip to content

Commit

Permalink
Add shallow_copy_file_from_path,deep_copy_file_from_path and raw_copy…
Browse files Browse the repository at this point in the history
…_file_to_path, and use PathBuf in fuzz_write
  • Loading branch information
Pr0methean committed Apr 20, 2024
1 parent 0087dab commit cdc2e7a
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 28 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@

- `index_for_name`, `index_for_path`, `name_for_index`: get the index of a file given its path or vice-versa, without
initializing metadata from the local-file header or needing to mutably borrow the `ZipArchive`.
- `add_symlink_from_path`: create a symlink using `AsRef<Path>` arguments
- `add_symlink_from_path`, `shallow_copy_file_from_path`, `deep_copy_file_from_path`, `raw_copy_file_to_path`: copy a
file or create a symlink using `AsRef<Path>` arguments

### Changed

Expand Down
42 changes: 15 additions & 27 deletions fuzz/fuzz_targets/fuzz_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub enum BasicFileOperation {
},
WriteDirectory(zip::write::FullFileOptions),
WriteSymlinkWithTarget {
target: Box<PathBuf>,
target: PathBuf,
options: zip::write::FullFileOptions,
},
ShallowCopy(Box<FileOperation>),
Expand All @@ -24,7 +24,7 @@ pub enum BasicFileOperation {
#[derive(Arbitrary, Clone, Debug)]
pub struct FileOperation {
basic: BasicFileOperation,
name: String,
path: PathBuf,
reopen: bool,
// 'abort' flag is separate, to prevent trying to copy an aborted file
}
Expand All @@ -36,20 +36,9 @@ pub struct FuzzTestCase {
flush_on_finish_file: bool,
}

impl FileOperation {
fn referenceable_name(&self) -> String {
if let BasicFileOperation::WriteDirectory(_) = self.basic {
if !self.name.ends_with('\\') && !self.name.ends_with('/') {
return self.name.to_owned() + "/";
}
}
self.name.to_owned()
}
}

fn do_operation<T>(
writer: &mut RefCell<zip::ZipWriter<T>>,
operation: FileOperation,
operation: &FileOperation,
abort: bool,
flush_on_finish_file: bool,
) -> Result<(), Box<dyn std::error::Error>>
Expand All @@ -59,39 +48,38 @@ where
writer
.borrow_mut()
.set_flush_on_finish_file(flush_on_finish_file);
let name = operation.name;
match operation.basic {
let path = &operation.path;
match &operation.basic {
BasicFileOperation::WriteNormalFile {
contents,
mut options,
options,
..
} => {
let uncompressed_size = contents.iter().map(Vec::len).sum::<usize>();
let mut options = (*options).to_owned();
if uncompressed_size >= u32::MAX as usize {
options = options.large_file(true);
}
writer.borrow_mut().start_file(name, options)?;
writer.borrow_mut().start_file_from_path(path, options)?;
for chunk in contents {
writer.borrow_mut().write_all(chunk.as_slice())?;
}
}
BasicFileOperation::WriteDirectory(options) => {
writer.borrow_mut().add_directory(name, options)?;
writer.borrow_mut().add_directory_from_path(path, options.to_owned())?;
}
BasicFileOperation::WriteSymlinkWithTarget { target, options } => {
writer
.borrow_mut()
.add_symlink(name, target.to_string_lossy(), options)?;
.add_symlink_from_path(&path, target, options.to_owned())?;
}
BasicFileOperation::ShallowCopy(base) => {
let base_name = base.referenceable_name();
do_operation(writer, *base, false, flush_on_finish_file)?;
writer.borrow_mut().shallow_copy_file(&base_name, &name)?;
do_operation(writer, &base, false, flush_on_finish_file)?;
writer.borrow_mut().shallow_copy_file_from_path(&base.path, &path)?;
}
BasicFileOperation::DeepCopy(base) => {
let base_name = base.referenceable_name();
do_operation(writer, *base, false, flush_on_finish_file)?;
writer.borrow_mut().deep_copy_file(&base_name, &name)?;
do_operation(writer, &base, false, flush_on_finish_file)?;
writer.borrow_mut().deep_copy_file_from_path(&base.path, &path)?;
}
}
if abort {
Expand All @@ -113,7 +101,7 @@ fuzz_target!(|test_case: FuzzTestCase| {
for (operation, abort) in test_case.operations {
let _ = do_operation(
&mut writer,
operation,
&operation,
abort,
test_case.flush_on_finish_file,
);
Expand Down
29 changes: 29 additions & 0 deletions src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,16 @@ impl<A: Read + Write + Seek> ZipWriter<A> {
}
self.finish_file()
}

/// Like `deep_copy_file`, but uses Path arguments.
///
/// This function ensures that the '/' path separator is used and normalizes `.` and `..`. It
/// ignores any `..` or Windows drive letter that would produce a path outside the ZIP file's
/// root.
pub fn deep_copy_file_from_path<T: AsRef<Path>, U: AsRef<Path>>(&mut self, src_path: T, dest_path: U) -> ZipResult<()>
{
self.deep_copy_file(&*path_to_string(src_path), &*path_to_string(dest_path))

Check failure on line 605 in src/write.rs

View workflow job for this annotation

GitHub Actions / clippy

deref which would be done by auto-deref

Check failure on line 605 in src/write.rs

View workflow job for this annotation

GitHub Actions / clippy

deref which would be done by auto-deref
}
}

impl<W: Write + Seek> ZipWriter<W> {
Expand Down Expand Up @@ -997,6 +1007,15 @@ impl<W: Write + Seek> ZipWriter<W> {
Ok(())
}

/// Like `raw_copy_file_to_path`, but uses Path arguments.
///
/// This function ensures that the '/' path separator is used and normalizes `.` and `..`. It
/// ignores any `..` or Windows drive letter that would produce a path outside the ZIP file's
/// root.
pub fn raw_copy_file_to_path<P: AsRef<Path>>(&mut self, file: ZipFile, path: P) -> ZipResult<()> {
self.raw_copy_file_rename(file, path_to_string(path))
}

/// Add a new file using the already compressed data from a ZIP file being read, this allows faster
/// copies of the `ZipFile` since there is no need to decompress and compress it again. Any `ZipFile`
/// metadata is copied and not checked, for example the file CRC.
Expand Down Expand Up @@ -1219,6 +1238,16 @@ impl<W: Write + Seek> ZipWriter<W> {
self.insert_file_data(dest_data)?;
Ok(())
}

/// Like `shallow_copy_file`, but uses Path arguments.
///
/// This function ensures that the '/' path separator is used and normalizes `.` and `..`. It
/// ignores any `..` or Windows drive letter that would produce a path outside the ZIP file's
/// root.
pub fn shallow_copy_file_from_path<T: AsRef<Path>, U: AsRef<Path>>(&mut self, src_path: T, dest_path: U) -> ZipResult<()>
{
self.shallow_copy_file(&*path_to_string(src_path), &*path_to_string(dest_path))

Check failure on line 1249 in src/write.rs

View workflow job for this annotation

GitHub Actions / clippy

deref which would be done by auto-deref

Check failure on line 1249 in src/write.rs

View workflow job for this annotation

GitHub Actions / clippy

deref which would be done by auto-deref
}
}

impl<W: Write + Seek> Drop for ZipWriter<W> {
Expand Down

0 comments on commit cdc2e7a

Please sign in to comment.