diff --git a/benches/read_metadata.rs b/benches/read_metadata.rs index 9fcf38115..165f47726 100644 --- a/benches/read_metadata.rs +++ b/benches/read_metadata.rs @@ -1,7 +1,7 @@ use bencher::{benchmark_group, benchmark_main}; use std::fs; -use std::io::{self, prelude::*, Cursor}; +use std::io::{self, Cursor, Write}; use bencher::Bencher; use tempfile::TempDir; diff --git a/examples/extract_lorem.rs b/examples/extract_lorem.rs index bc50abe16..c2098af57 100644 --- a/examples/extract_lorem.rs +++ b/examples/extract_lorem.rs @@ -1,4 +1,4 @@ -use std::io::prelude::*; +use std::io::Read; fn main() { std::process::exit(real_main()); diff --git a/examples/write_dir.rs b/examples/write_dir.rs index e03e6c968..bee931697 100644 --- a/examples/write_dir.rs +++ b/examples/write_dir.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] use anyhow::Context; use clap::{Parser, ValueEnum}; -use std::io::prelude::*; +use std::io::{Read, Seek, Write}; use zip::{result::ZipError, write::SimpleFileOptions}; use std::fs::File; diff --git a/examples/write_sample.rs b/examples/write_sample.rs index b864afcd1..52ea42931 100644 --- a/examples/write_sample.rs +++ b/examples/write_sample.rs @@ -1,4 +1,4 @@ -use std::io::prelude::*; +use std::io::Write; use zip::write::SimpleFileOptions; #[cfg(feature = "aes-crypto")] use zip::{AesMode, CompressionMethod}; diff --git a/fuzz_write/src/main.rs b/fuzz_write/src/main.rs index 69f915f41..4e56f4991 100644 --- a/fuzz_write/src/main.rs +++ b/fuzz_write/src/main.rs @@ -254,10 +254,11 @@ fn do_operation( "let mut writer = ZipWriter::new_append(writer.finish()?)?;" )?; replace_with_or_abort(writer, |old_writer: zip::ZipWriter>>| { - (|| -> ZipResult>>> { + let get_writer = || { + // return a ZipResult>>> zip::ZipWriter::new_append(old_writer.finish()?) - })() - .unwrap_or_else(|_| { + }; + get_writer().unwrap_or_else(|_| { if panic_on_error { panic!("Failed to create new ZipWriter") } @@ -275,10 +276,11 @@ fn do_operation( "let mut writer = ZipWriter::new_append(writer.finish()?)?;" )?; replace_with_or_abort(writer, |old_writer| { - (|| -> ZipResult>>> { + let get_writer = || { + // return a ZipResult>>> zip::ZipWriter::new_append(old_writer.finish()?) - })() - .unwrap_or_else(|_| { + }; + get_writer().unwrap_or_else(|_| { if panic_on_error { panic!("Failed to create new ZipWriter") } diff --git a/src/aes.rs b/src/aes.rs index 726d70aed..14075e402 100644 --- a/src/aes.rs +++ b/src/aes.rs @@ -13,7 +13,7 @@ use sha1::Sha1; use std::io::{self, Error, ErrorKind, Read, Write}; use zeroize::{Zeroize, Zeroizing}; -/// The length of the password verifcation value in bytes +/// The length of the password verification value in bytes pub const PWD_VERIFY_LENGTH: usize = 2; /// The length of the authentication code in bytes const AUTH_CODE_LENGTH: usize = 10; diff --git a/src/aes_ctr.rs b/src/aes_ctr.rs index 6513fb978..75ff86974 100644 --- a/src/aes_ctr.rs +++ b/src/aes_ctr.rs @@ -7,7 +7,7 @@ use crate::unstable::LittleEndianWriteExt; use aes::cipher::generic_array::GenericArray; use aes::cipher::{BlockEncrypt, KeyInit}; -use std::{any, fmt}; +use core::{any, fmt}; /// Internal block size of an AES cipher. const AES_BLOCK_SIZE: usize = 16; @@ -153,7 +153,7 @@ mod tests { use aes::cipher::{BlockEncrypt, KeyInit}; /// Checks whether `crypt_in_place` produces the correct plaintext after one use and yields the - /// cipertext again after applying it again. + /// ciphertext again after applying it again. fn roundtrip(key: &[u8], ciphertext: &[u8], expected_plaintext: &[u8]) where Aes: AesKind, diff --git a/src/compression.rs b/src/compression.rs index a2cae7536..77fad6e2b 100644 --- a/src/compression.rs +++ b/src/compression.rs @@ -1,6 +1,7 @@ //! Possible ZIP compression methods. -use std::{fmt, io}; +use core::fmt; +use std::io; #[allow(deprecated)] /// Identifies the storage format used to compress a file within a ZIP archive. diff --git a/src/crc32.rs b/src/crc32.rs index 4b2beb62e..4d1bd8e26 100644 --- a/src/crc32.rs +++ b/src/crc32.rs @@ -1,7 +1,6 @@ //! Helper module to compute a CRC32 checksum -use std::io; -use std::io::prelude::*; +use std::io::{self, Read}; use crc32fast::Hasher; @@ -85,7 +84,9 @@ impl Read for Crc32Reader { #[cfg(test)] mod test { - use super::*; + use std::io::Read; + + use super::Crc32Reader; #[test] fn test_empty_reader() { diff --git a/src/extra_fields/mod.rs b/src/extra_fields/mod.rs index 767a56952..de6a3b6c7 100644 --- a/src/extra_fields/mod.rs +++ b/src/extra_fields/mod.rs @@ -22,7 +22,7 @@ mod zipinfo_utf8; pub use extended_timestamp::*; pub use ntfs::Ntfs; -pub use zipinfo_utf8::*; +pub use zipinfo_utf8::UnicodeExtraField; /// contains one extra field #[derive(Debug, Clone)] diff --git a/src/lib.rs b/src/lib.rs index d7bd1e08d..de7b83de1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,20 +15,20 @@ //! //! This is a list of supported features: //! -//! | | Reading | Writing | -//! | ------- | ------ | ------- | -//! | Stored | ✅ | ✅ | -//! | Deflate | ✅ [->](`crate::ZipArchive::by_name`) | ✅ [->](`crate::write::FileOptions::compression_method`) | -//! | Deflate64 | ✅ | | -//! | Bzip2 | ✅ | ✅ | -//! | ZStandard | ✅ | ✅ | -//! | LZMA | ✅ | | -//! | XZ | ✅ | ✅ | -//! | PPMd | ✅ | ✅ | -//! | AES encryption | ✅ | ✅ | -//! | ZipCrypto deprecated encryption | ✅ | ✅ | -//! +//! | | Reading | Writing | +//! | ------------------------------- | ------------------------------------- | -------------------------------------------------------- | +//! | Stored | ✅ | ✅ | +//! | Deflate | ✅ [->](`crate::ZipArchive::by_name`) | ✅ [->](`crate::write::FileOptions::compression_method`) | +//! | Deflate64 | ✅ | | +//! | Bzip2 | ✅ | ✅ | +//! | ZStandard | ✅ | ✅ | +//! | LZMA | ✅ | | +//! | XZ | ✅ | ✅ | +//! | PPMd | ✅ | ✅ | +//! | AES encryption | ✅ | ✅ | +//! | ZipCrypto deprecated encryption | ✅ | ✅ | //! + #![cfg_attr(docsrs, feature(doc_cfg))] #![warn(missing_docs)] #![allow(unexpected_cfgs)] // Needed for cfg(fuzzing) on nightly as of 2024-05-06 diff --git a/src/read.rs b/src/read.rs index f45fb1908..e348e187e 100644 --- a/src/read.rs +++ b/src/read.rs @@ -6,31 +6,27 @@ use crate::compression::{CompressionMethod, Decompressor}; use crate::cp437::FromCp437; use crate::crc32::Crc32Reader; use crate::extra_fields::{ExtendedTimestamp, ExtraField, Ntfs}; -use crate::read::zip_archive::{Shared, SharedBuilder}; -use crate::result::invalid; -use crate::result::{ZipError, ZipResult}; -use crate::spec::{self, CentralDirectoryEndInfo, DataAndPosition, FixedSizeBlock, Pod}; +use crate::result::{invalid, ZipError, ZipResult}; +use crate::spec::{ + self, CentralDirectoryEndInfo, DataAndPosition, FixedSizeBlock, Pod, ZIP64_BYTES_THR, +}; use crate::types::{ - AesMode, AesVendorVersion, DateTime, System, ZipCentralEntryBlock, ZipFileData, - ZipLocalEntryBlock, + AesMode, AesVendorVersion, DateTime, SimpleFileOptions, System, ZipCentralEntryBlock, + ZipFileData, ZipLocalEntryBlock, }; -use crate::write::SimpleFileOptions; use crate::zipcrypto::{ZipCryptoReader, ZipCryptoReaderValid, ZipCryptoValidator}; -use crate::ZIP64_BYTES_THR; +use core::mem::{replace, size_of}; +use core::ops::{Deref, Range}; use indexmap::IndexMap; use std::borrow::Cow; use std::ffi::OsStr; -use std::fs::create_dir_all; -use std::io::{self, copy, prelude::*, sink, SeekFrom}; -use std::mem; -use std::mem::size_of; -use std::ops::{Deref, Range}; +use std::io::{self, copy, sink, Read, Seek, SeekFrom, Write}; use std::path::{Component, Path, PathBuf}; use std::sync::{Arc, OnceLock}; mod config; -pub use config::*; +pub use config::{ArchiveOffset, Config}; /// Provides high level API for reading from a stream. pub(crate) mod stream; @@ -89,7 +85,7 @@ pub(crate) mod zip_archive { /// change in the future. /// /// ```no_run - /// use std::io::prelude::*; + /// use std::io::{Read, Seek}; /// fn list_zip_contents(reader: impl Read + Seek) -> zip::result::ZipResult<()> { /// use zip::HasZipMetadata; /// let mut zip = zip::ZipArchive::new(reader)?; @@ -313,7 +309,8 @@ impl Read for SeekableTake<'_, R> { } pub(crate) fn make_writable_dir_all>(outpath: T) -> Result<(), ZipError> { - create_dir_all(outpath.as_ref())?; + use std::fs; + fs::create_dir_all(outpath.as_ref())?; #[cfg(unix)] { // Dirs must be writable until all normal files are extracted @@ -545,7 +542,7 @@ impl ZipArchive { Some((_, file)) => file.header_start, None => central_start, }; - let shared = Arc::new(Shared { + let shared = Arc::new(zip_archive::Shared { files, offset: initial_offset, dir_start: central_start, @@ -642,7 +639,7 @@ impl ZipArchive { /// Get the directory start offset and number of files. This is done in a /// separate function to ease the control flow design. - pub(crate) fn get_metadata(config: Config, reader: &mut R) -> ZipResult { + pub(crate) fn get_metadata(config: Config, reader: &mut R) -> ZipResult { // End of the probed region, initially set to the end of the file let file_len = reader.seek(io::SeekFrom::End(0))?; let mut end_exclusive = file_len; @@ -687,7 +684,7 @@ impl ZipArchive { dir_info: CentralDirectoryInfo, config: Config, reader: &mut R, - ) -> Result { + ) -> Result { // If the parsed number of files is greater than the offset then // something fishy is going on and we shouldn't trust number_of_files. let file_capacity = if dir_info.number_of_files > dir_info.directory_start as usize { @@ -711,7 +708,7 @@ impl ZipArchive { files.push(file); } - Ok(SharedBuilder { + Ok(zip_archive::SharedBuilder { files, offset: dir_info.archive_offset, dir_start: dir_info.directory_start, @@ -865,7 +862,7 @@ impl ZipArchive { ) -> ZipResult<()> { use std::fs; - create_dir_all(&directory)?; + fs::create_dir_all(&directory)?; let directory = directory.as_ref().canonicalize()?; let root_dir = root_dir_filter @@ -1614,7 +1611,7 @@ impl<'a> ZipReadOptions<'a> { /// Methods for retrieving information on zip files impl<'a, R: Read> ZipFile<'a, R> { pub(crate) fn take_raw_reader(&mut self) -> io::Result> { - mem::replace(&mut self.reader, ZipFileReader::NoReader).into_inner() + replace(&mut self.reader, ZipFileReader::NoReader).into_inner() } /// Get the version of the file @@ -2123,7 +2120,7 @@ fn generate_chrono_datetime(datetime: &DateTime) -> Option ZipStreamReader { /// Extraction is not atomic; If an error is encountered, some of the files /// may be left on disk. pub fn extract>(self, directory: P) -> ZipResult<()> { - create_dir_all(&directory)?; + use std::fs; + fs::create_dir_all(&directory)?; let directory = directory.as_ref().canonicalize()?; struct Extractor(PathBuf, IndexMap, ()>); impl ZipStreamVisitor for Extractor { @@ -121,7 +120,7 @@ pub trait ZipStreamVisitor { /// - `external_attributes`: `unix_mode()`: will return None fn visit_file(&mut self, file: &mut ZipFile<'_, R>) -> ZipResult<()>; - /// This function is guranteed to be called after all `visit_file`s. + /// This function is guaranteed to be called after all `visit_file`s. /// /// * `metadata` - Provides missing metadata in `visit_file`. fn visit_additional_metadata(&mut self, metadata: &ZipStreamFileMetadata) -> ZipResult<()>; @@ -211,11 +210,13 @@ impl ZipStreamFileMetadata { mod test { use tempfile::TempDir; - use super::*; + use crate::read::stream::{ZipStreamFileMetadata, ZipStreamReader, ZipStreamVisitor}; + use crate::read::ZipFile; + use crate::result::ZipResult; use crate::write::SimpleFileOptions; use crate::ZipWriter; use std::collections::BTreeSet; - use std::io::Cursor; + use std::io::{Cursor, Read}; struct DummyVisitor; impl ZipStreamVisitor for DummyVisitor { @@ -251,7 +252,7 @@ mod test { #[test] fn invalid_offset() { - ZipStreamReader::new(io::Cursor::new(include_bytes!( + ZipStreamReader::new(Cursor::new(include_bytes!( "../../tests/data/invalid_offset.zip" ))) .visit(&mut DummyVisitor) @@ -260,7 +261,7 @@ mod test { #[test] fn invalid_offset2() { - ZipStreamReader::new(io::Cursor::new(include_bytes!( + ZipStreamReader::new(Cursor::new(include_bytes!( "../../tests/data/invalid_offset2.zip" ))) .visit(&mut DummyVisitor) @@ -269,9 +270,8 @@ mod test { #[test] fn zip_read_streaming() { - let reader = ZipStreamReader::new(io::Cursor::new(include_bytes!( - "../../tests/data/mimetype.zip" - ))); + let reader = + ZipStreamReader::new(Cursor::new(include_bytes!("../../tests/data/mimetype.zip"))); #[derive(Default)] struct V { @@ -306,7 +306,7 @@ mod test { #[test] fn file_and_dir_predicates() { - let reader = ZipStreamReader::new(io::Cursor::new(include_bytes!( + let reader = ZipStreamReader::new(Cursor::new(include_bytes!( "../../tests/data/files_and_dirs.zip" ))); @@ -353,7 +353,7 @@ mod test { /// files declared is more than the alleged offset in the CDE #[test] fn invalid_cde_number_of_files_allocation_smaller_offset() { - ZipStreamReader::new(io::Cursor::new(include_bytes!( + ZipStreamReader::new(Cursor::new(include_bytes!( "../../tests/data/invalid_cde_number_of_files_allocation_smaller_offset.zip" ))) .visit(&mut DummyVisitor) @@ -365,7 +365,7 @@ mod test { /// files declared is less than the alleged offset in the CDE #[test] fn invalid_cde_number_of_files_allocation_greater_offset() { - ZipStreamReader::new(io::Cursor::new(include_bytes!( + ZipStreamReader::new(Cursor::new(include_bytes!( "../../tests/data/invalid_cde_number_of_files_allocation_greater_offset.zip" ))) .visit(&mut DummyVisitor) diff --git a/src/result.rs b/src/result.rs index 550f2bdae..7c0353f3d 100644 --- a/src/result.rs +++ b/src/result.rs @@ -2,12 +2,11 @@ #![allow(non_local_definitions)] //! Error types that can be emitted from this library +use core::error::Error; +use core::fmt::{self, Display, Formatter}; +use core::num::TryFromIntError; use std::borrow::Cow; -use std::error::Error; -use std::fmt::{self, Display, Formatter}; use std::io; -use std::num::TryFromIntError; -use std::string::FromUtf8Error; /// Generic result type with ZipError as its error variant pub type ZipResult = Result; @@ -97,8 +96,8 @@ impl From for ZipError { } } -impl From for ZipError { - fn from(_: FromUtf8Error) -> Self { +impl From for ZipError { + fn from(_: std::string::FromUtf8Error) -> Self { invalid!("Invalid UTF-8") } } diff --git a/src/spec.rs b/src/spec.rs index bd2364b71..f6eaeb0ee 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -4,9 +4,8 @@ use crate::read::magic_finder::{Backwards, Forward, MagicFinder, OptimisticMagic use crate::read::ArchiveOffset; use crate::result::{invalid, ZipError, ZipResult}; use core::mem; -use std::io; -use std::io::prelude::*; -use std::slice; +use core::slice; +use std::io::{self, Read, Seek, Write}; /// "Magic" header values used in the zip spec to locate metadata records. /// @@ -102,7 +101,7 @@ impl ExtraFieldMagic { /// # fn main() -> Result<(), zip::result::ZipError> { /// # #[cfg(target_pointer_width = "64")] /// # { -/// use std::io::{self, Cursor, prelude::*}; +/// use std::io::{self, Cursor, Write}; /// use std::error::Error; /// use zip::{ZipWriter, write::SimpleFileOptions}; /// @@ -816,9 +815,13 @@ pub(crate) fn is_dir(filename: &str) -> bool { #[cfg(test)] mod test { - use super::*; use std::io::Cursor; + use crate::{ + result::{invalid, ZipError}, + spec::{FixedSizeBlock, Magic, Pod}, + }; + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[repr(packed, C)] pub struct TestBlock { diff --git a/src/types.rs b/src/types.rs index 1115fea82..feae253b9 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,13 +1,12 @@ //! Types that specify what is contained in a ZIP. use crate::cp437::FromCp437; -use crate::write::{FileOptionExtension, FileOptions}; -use path::{Component, Path, PathBuf}; -use std::cmp::Ordering; +use crate::write::FileOptionExtension; +use crate::zipcrypto::EncryptWith; +use core::cmp::Ordering; +use core::fmt::{self, Debug, Formatter}; +use core::mem; use std::ffi::OsStr; -use std::fmt; -use std::fmt::{Debug, Formatter}; -use std::mem; -use std::path; +use std::path::{Component, Path, PathBuf, MAIN_SEPARATOR}; use std::sync::{Arc, OnceLock}; #[cfg(feature = "chrono")] @@ -69,6 +68,25 @@ impl From for u8 { } } +/// Metadata for a file to be written +#[derive(Clone, Debug, Copy, Eq, PartialEq)] +pub struct FileOptions<'k, T: FileOptionExtension> { + pub(crate) compression_method: CompressionMethod, + pub(crate) compression_level: Option, + pub(crate) last_modified_time: DateTime, + pub(crate) permissions: Option, + pub(crate) large_file: bool, + pub(crate) encrypt_with: Option>, + pub(crate) extended_options: T, + pub(crate) alignment: u16, + #[cfg(feature = "deflate-zopfli")] + pub(super) zopfli_buffer_size: Option, + #[cfg(feature = "aes-crypto")] + pub(crate) aes_mode: Option<(AesMode, AesVendorVersion, CompressionMethod)>, +} +/// Simple File Options. Can be copied and good for simple writing zip files +pub type SimpleFileOptions = FileOptions<'static, ()>; + /// Representation of a moment in time. /// /// Zip files use an old format from DOS to store timestamps, @@ -572,7 +590,7 @@ impl ZipFileData { // zip files can contain both / and \ as separators regardless of the OS // and as we want to return a sanitized PathBuf that only supports the // OS separator let's convert incompatible separators to compatible ones - let separator = path::MAIN_SEPARATOR; + let separator = MAIN_SEPARATOR; let opposite_separator = match separator { '/' => '\\', _ => '/', @@ -1300,7 +1318,6 @@ mod test { #[test] fn sanitize() { - use super::*; let file_name = "/path/../../../../etc/./passwd\0/etc/shadow".to_string(); let data = ZipFileData { system: System::Dos, @@ -1464,9 +1481,13 @@ mod test { assert!(DateTime::from_date_and_time(2100, 2, 29, 0, 0, 0).is_err()); } + use std::{path::PathBuf, sync::OnceLock}; + #[cfg(feature = "time")] use time::{format_description::well_known::Rfc3339, OffsetDateTime, PrimitiveDateTime}; + use crate::types::{System, ZipFileData}; + #[cfg(feature = "time")] #[test] fn datetime_try_from_offset_datetime() { diff --git a/src/write.rs b/src/write.rs index 12cfb5b4d..3439ea04e 100644 --- a/src/write.rs +++ b/src/write.rs @@ -6,27 +6,26 @@ use crate::compression::CompressionMethod; use crate::read::{parse_single_extra_field, Config, ZipArchive, ZipFile}; use crate::result::{invalid, ZipError, ZipResult}; use crate::spec::{self, FixedSizeBlock, Zip32CDEBlock}; +use crate::types::ffi::S_IFLNK; #[cfg(feature = "aes-crypto")] use crate::types::AesMode; use crate::types::{ ffi, AesVendorVersion, DateTime, Zip64ExtraFieldBlock, ZipFileData, ZipLocalEntryBlock, ZipRawValues, MIN_VERSION, }; -use crate::write::ffi::S_IFLNK; +use core::default::Default; +use core::fmt::{Debug, Formatter}; +use core::marker::PhantomData; +use core::mem::{self, size_of}; #[cfg(feature = "deflate-zopfli")] use core::num::NonZeroU64; +use core::str::{from_utf8, Utf8Error}; use crc32fast::Hasher; use indexmap::IndexMap; use std::borrow::ToOwned; -use std::default::Default; -use std::fmt::{Debug, Formatter}; -use std::io; -use std::io::prelude::*; +use std::io::{self, Read, Seek, Write}; use std::io::{BufReader, SeekFrom}; use std::io::{Cursor, ErrorKind}; -use std::marker::PhantomData; -use std::mem; -use std::str::{from_utf8, Utf8Error}; use std::sync::Arc; #[cfg(feature = "deflate-flate2")] @@ -40,12 +39,14 @@ use zopfli::Options; #[cfg(feature = "deflate-zopfli")] use std::io::BufWriter; -use std::mem::size_of; use std::path::Path; #[cfg(feature = "zstd")] use zstd::stream::write::Encoder as ZstdEncoder; +// re-export from types +pub use crate::types::{FileOptions, SimpleFileOptions}; + enum MaybeEncrypted { Unencrypted(W), #[cfg(feature = "aes-crypto")] @@ -130,7 +131,16 @@ impl Debug for GenericZipWriter { // Put the struct declaration in a private module to convince rustdoc to display ZipWriter nicely pub(crate) mod zip_writer { - use super::*; + use core::fmt::{Debug, Formatter}; + use std::io::{Seek, Write}; + + use indexmap::IndexMap; + + use crate::{ + types::ZipFileData, + write::{GenericZipWriter, ZipWriterStats}, + }; + /// ZIP archive generator /// /// Handles the bookkeeping involved in building an archive, and provides an @@ -190,7 +200,7 @@ use crate::result::ZipError::UnsupportedArchive; use crate::unstable::path_to_string; use crate::unstable::LittleEndianWriteExt; use crate::write::GenericZipWriter::{Closed, Storer}; -use crate::zipcrypto::ZipCryptoKeys; +use crate::zipcrypto::{EncryptWith, ZipCryptoKeys}; use crate::CompressionMethod::Stored; pub use zip_writer::ZipWriter; @@ -236,52 +246,6 @@ mod sealed { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub(crate) enum EncryptWith<'k> { - #[cfg(feature = "aes-crypto")] - Aes { - mode: AesMode, - password: &'k str, - }, - ZipCrypto(ZipCryptoKeys, PhantomData<&'k ()>), -} - -#[cfg(fuzzing)] -impl<'a> arbitrary::Arbitrary<'a> for EncryptWith<'a> { - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - #[cfg(feature = "aes-crypto")] - if bool::arbitrary(u)? { - return Ok(EncryptWith::Aes { - mode: AesMode::arbitrary(u)?, - password: u.arbitrary::<&str>()?, - }); - } - - Ok(EncryptWith::ZipCrypto( - ZipCryptoKeys::arbitrary(u)?, - PhantomData, - )) - } -} - -/// Metadata for a file to be written -#[derive(Clone, Debug, Copy, Eq, PartialEq)] -pub struct FileOptions<'k, T: FileOptionExtension> { - pub(crate) compression_method: CompressionMethod, - pub(crate) compression_level: Option, - pub(crate) last_modified_time: DateTime, - pub(crate) permissions: Option, - pub(crate) large_file: bool, - pub(crate) encrypt_with: Option>, - pub(crate) extended_options: T, - pub(crate) alignment: u16, - #[cfg(feature = "deflate-zopfli")] - pub(super) zopfli_buffer_size: Option, - #[cfg(feature = "aes-crypto")] - pub(crate) aes_mode: Option<(AesMode, AesVendorVersion, CompressionMethod)>, -} -/// Simple File Options. Can be copied and good for simple writing zip files -pub type SimpleFileOptions = FileOptions<'static, ()>; /// Adds Extra Data and Central Extra Data. It does not implement copy. pub type FullFileOptions<'k> = FileOptions<'k, ExtendedFileOptions>; /// The Extension for Extra Data and Central Extra Data @@ -784,7 +748,7 @@ impl ZipWriter { /// # fn main() -> Result<(), zip::result::ZipError> { /// # #[cfg(any(feature = "deflate-flate2", not(feature = "_deflate-any")))] /// # { - /// use std::io::{Cursor, prelude::*}; + /// use std::io::{Cursor, Read, Write}; /// use zip::{ZipArchive, ZipWriter, write::SimpleFileOptions}; /// /// let buf = Cursor::new(Vec::new()); @@ -1241,7 +1205,7 @@ impl ZipWriter { /// # fn main() -> Result<(), zip::result::ZipError> { /// # #[cfg(any(feature = "deflate-flate2", not(feature = "_deflate-any")))] /// # { - /// use std::io::{Cursor, prelude::*}; + /// use std::io::{Cursor, Write, Read}; /// use zip::{ZipArchive, ZipWriter, write::SimpleFileOptions}; /// /// let buf = Cursor::new(Vec::new()); diff --git a/src/zipcrypto.rs b/src/zipcrypto.rs index 7ad017c8c..b4d2f3b29 100644 --- a/src/zipcrypto.rs +++ b/src/zipcrypto.rs @@ -3,11 +3,42 @@ //! The following paper was used to implement the ZipCrypto algorithm: //! [https://courses.cs.ut.ee/MTAT.07.022/2015_fall/uploads/Main/dmitri-report-f15-16.pdf](https://courses.cs.ut.ee/MTAT.07.022/2015_fall/uploads/Main/dmitri-report-f15-16.pdf) -use std::fmt::{Debug, Formatter}; -use std::hash::Hash; -use std::num::Wrapping; +use core::fmt::{Debug, Formatter}; +use core::hash::Hash; +use core::marker::PhantomData; +use core::num::Wrapping; use crate::result::ZipError; +#[cfg(feature = "aes-crypto")] +use crate::AesMode; + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub(crate) enum EncryptWith<'k> { + #[cfg(feature = "aes-crypto")] + Aes { + mode: AesMode, + password: &'k str, + }, + ZipCrypto(ZipCryptoKeys, PhantomData<&'k ()>), +} + +#[cfg(fuzzing)] +impl<'a> arbitrary::Arbitrary<'a> for EncryptWith<'a> { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + #[cfg(feature = "aes-crypto")] + if bool::arbitrary(u)? { + return Ok(EncryptWith::Aes { + mode: AesMode::arbitrary(u)?, + password: u.arbitrary::<&str>()?, + }); + } + + Ok(EncryptWith::ZipCrypto( + ZipCryptoKeys::arbitrary(u)?, + PhantomData, + )) + } +} /// A container to hold the current key state #[cfg_attr(fuzzing, derive(arbitrary::Arbitrary))] diff --git a/tests/end_to_end.rs b/tests/end_to_end.rs index de97986d2..2c01104a9 100644 --- a/tests/end_to_end.rs +++ b/tests/end_to_end.rs @@ -1,6 +1,5 @@ use std::collections::HashSet; -use std::io::prelude::*; -use std::io::Cursor; +use std::io::{Cursor, Read, Seek, Write}; use zip::result::ZipResult; use zip::unstable::LittleEndianWriteExt; use zip::write::ExtendedFileOptions; diff --git a/tests/zip_crypto.rs b/tests/zip_crypto.rs index 80e3b4ef8..f4d5b4d4e 100644 --- a/tests/zip_crypto.rs +++ b/tests/zip_crypto.rs @@ -123,7 +123,7 @@ fn encrypted_file() { fn buffered_read() { use std::io::{BufReader, Read}; - // delibirately pick a buffer capacity in a way that when `ZipCryptoReaderValid` read happens, it's not going to take entire buffer, + // deliberately pick a buffer capacity in a way that when `ZipCryptoReaderValid` read happens, it's not going to take entire buffer, // for this file it needs to be between 13..=46 bytes (with exception of 44 bytes) let zip_file_bytes = &mut Cursor::new(ZIP_CRYPTO_FILE); let buffered = BufReader::with_capacity(13, zip_file_bytes);