From 384afcda2a8e63ba1045ae6fd5be1962d62f2fea Mon Sep 17 00:00:00 2001 From: Chris Hennick Date: Mon, 8 Apr 2024 10:29:17 -0700 Subject: [PATCH] Switch from `String` to `Box` for metadata --- CHANGELOG.md | 6 ++++++ src/read.rs | 32 ++++++++++++++++---------------- src/read/stream.rs | 2 +- src/types.rs | 16 ++++++++-------- src/write.rs | 19 +++++++++---------- 5 files changed, 40 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index caea4178c..5707c248f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -245,3 +245,9 @@ ### Fixed - Fixed some rare bugs that could cause panics when trying to read an invalid ZIP file or using an incorrect password. + +## [1.0.0] + +### Changed + + - Now uses `Box` rather than `String` for metadata. \ No newline at end of file diff --git a/src/read.rs b/src/read.rs index 1b39b14fc..203f0ea82 100644 --- a/src/read.rs +++ b/src/read.rs @@ -11,10 +11,10 @@ use crate::spec; use crate::types::{AesMode, AesVendorVersion, AtomicU64, DateTime, System, ZipFileData}; use crate::zipcrypto::{ZipCryptoReader, ZipCryptoReaderValid, ZipCryptoValidator}; use byteorder::{LittleEndian, ReadBytesExt}; -use std::borrow::Cow; +use std::borrow::{Borrow, Cow}; use std::collections::HashMap; use std::io::{self, prelude::*}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::Arc; #[cfg(any( @@ -45,7 +45,7 @@ pub(crate) mod zip_archive { #[derive(Debug)] pub(crate) struct Shared { pub(crate) files: Vec, - pub(crate) names_map: super::HashMap, + pub(crate) names_map: super::HashMap, usize>, pub(super) offset: u64, pub(super) dir_start: u64, pub(super) dir_end: u64, @@ -486,7 +486,7 @@ impl ZipArchive { reader.seek(io::SeekFrom::Start(dir_info.directory_start))?; for _ in 0..dir_info.number_of_files { 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().into(), files.len()); files.push(file); } let dir_end = reader.seek(io::SeekFrom::Start(dir_info.directory_start))?; @@ -600,7 +600,7 @@ impl ZipArchive { /// Returns an iterator over all the file and directory names in this archive. pub fn file_names(&self) -> impl Iterator { - self.shared.names_map.keys().map(|s| s.as_str()) + self.shared.names_map.keys().map(Box::borrow) } /// Search for a file entry by name, decrypt with given password @@ -777,13 +777,13 @@ fn central_header_to_zip_file_inner( let mut file_comment_raw = vec![0; file_comment_length]; reader.read_exact(&mut file_comment_raw)?; - let file_name = match is_utf8 { - true => String::from_utf8_lossy(&file_name_raw).into_owned(), - false => file_name_raw.clone().from_cp437(), + let file_name: Box = match is_utf8 { + true => String::from_utf8_lossy(&file_name_raw).into(), + false => file_name_raw.clone().from_cp437().into_boxed_str(), }; let file_comment = match is_utf8 { - true => String::from_utf8_lossy(&file_comment_raw).into_owned(), - false => file_comment_raw.from_cp437(), + true => String::from_utf8_lossy(&file_comment_raw).into(), + false => file_comment_raw.from_cp437().into_boxed_str(), }; // Construct the result @@ -991,7 +991,7 @@ impl<'a> ZipFile<'a> { /// This will read well-formed ZIP files correctly, and is resistant /// to path-based exploits. It is recommended over /// [`ZipFile::mangled_name`]. - pub fn enclosed_name(&self) -> Option<&Path> { + pub fn enclosed_name(&self) -> Option { self.data.enclosed_name() } @@ -1145,9 +1145,9 @@ pub fn read_zipfile_from_stream<'a, R: Read>(reader: &'a mut R) -> ZipResult String::from_utf8_lossy(&file_name_raw).into_owned(), - false => file_name_raw.clone().from_cp437(), + let file_name: Box = match is_utf8 { + true => String::from_utf8_lossy(&file_name_raw).into(), + false => file_name_raw.clone().from_cp437().into_boxed_str(), }; let mut result = ZipFileData { @@ -1161,11 +1161,11 @@ pub fn read_zipfile_from_stream<'a, R: Read>(reader: &'a mut R) -> ZipResult Option<&Path> { + pub fn enclosed_name(&self) -> Option { self.0.enclosed_name() } diff --git a/src/types.rs b/src/types.rs index fe316ca39..dd2666af7 100644 --- a/src/types.rs +++ b/src/types.rs @@ -315,7 +315,7 @@ impl TryFrom for DateTime { fn try_from(dt: OffsetDateTime) -> Result { if dt.year() >= 1980 && dt.year() <= 2107 { Ok(DateTime { - year: (dt.year()).try_into()?, + year: dt.year().try_into()?, month: dt.month().into(), day: dt.day(), hour: dt.hour(), @@ -385,7 +385,7 @@ pub struct ZipFileData { /// Size of the file when extracted pub uncompressed_size: u64, /// Name of the file - pub file_name: String, + pub file_name: Box, /// Raw file name. To be used when file_name was incorrectly decoded. pub file_name_raw: Vec, /// Extra field usually used for storage expansion @@ -393,7 +393,7 @@ pub struct ZipFileData { /// Extra field only written to central directory pub central_extra_field: Arc>, /// File comment - pub file_comment: String, + pub file_comment: Box, /// Specifies where the local header of the file starts pub header_start: u64, /// Specifies where the central header of the file starts @@ -431,18 +431,18 @@ impl ZipFileData { Path::new(&filename) .components() - .filter(|component| matches!(*component, path::Component::Normal(..))) + .filter(|component| matches!(*component, Component::Normal(..))) .fold(PathBuf::new(), |mut path, ref cur| { path.push(cur.as_os_str()); path }) } - pub(crate) fn enclosed_name(&self) -> Option<&Path> { + pub(crate) fn enclosed_name(&self) -> Option { if self.file_name.contains('\0') { return None; } - let path = Path::new(&self.file_name); + let path = PathBuf::from(self.file_name.to_string()); let mut depth = 0usize; for component in path.components() { match component { @@ -556,11 +556,11 @@ mod test { crc32: 0, compressed_size: 0, uncompressed_size: 0, - file_name: file_name.clone(), + file_name: file_name.clone().into_boxed_str(), file_name_raw: file_name.into_bytes(), extra_field: Arc::new(vec![]), central_extra_field: Arc::new(vec![]), - file_comment: String::new(), + file_comment: Box::new("".into()), header_start: 0, data_start: AtomicU64::new(0), central_header_start: 0, diff --git a/src/write.rs b/src/write.rs index 1cdf1c3dc..19e5acb73 100644 --- a/src/write.rs +++ b/src/write.rs @@ -121,7 +121,7 @@ pub(crate) mod zip_writer { pub struct ZipWriter { pub(super) inner: GenericZipWriter, pub(super) files: Vec, - pub(super) files_by_name: HashMap, + pub(super) files_by_name: HashMap, usize>, pub(super) stats: ZipWriterStats, pub(super) writing_to_file: bool, pub(super) writing_raw: bool, @@ -583,7 +583,7 @@ impl ZipWriter { raw_values: Option, ) -> ZipResult<()> where - S: Into, + S: Into>, { self.finish_file()?; @@ -595,7 +595,6 @@ impl ZipWriter { { let header_start = self.inner.get_plain().stream_position()?; - let name = name.into(); let permissions = options.permissions.unwrap_or(0o100644); let file = ZipFileData { @@ -609,11 +608,11 @@ impl ZipWriter { crc32: raw_values.crc32, compressed_size: raw_values.compressed_size, uncompressed_size: raw_values.uncompressed_size, - file_name: name, + file_name: name.into(), file_name_raw: Vec::new(), // Never used for saving extra_field: options.extra_data, central_extra_field: options.central_extra_data, - file_comment: String::new(), + file_comment: String::with_capacity(0).into_boxed_str(), header_start, data_start: AtomicU64::new(0), central_header_start: 0, @@ -818,7 +817,7 @@ impl ZipWriter { /// The data should be written using the [`Write`] implementation on this [`ZipWriter`] pub fn start_file(&mut self, name: S, mut options: FileOptions) -> ZipResult<()> where - S: Into, + S: Into>, { Self::normalize_options(&mut options); let make_new_self = self.inner.prepare_next_writer( @@ -890,7 +889,7 @@ impl ZipWriter { /// ``` pub fn raw_copy_file_rename(&mut self, mut file: ZipFile, name: S) -> ZipResult<()> where - S: Into, + S: Into>, { let mut options = FileOptions::default() .large_file(file.compressed_size().max(file.size()) > spec::ZIP64_BYTES_THR) @@ -1015,8 +1014,8 @@ impl ZipWriter { mut options: FileOptions, ) -> ZipResult<()> where - N: Into, - T: Into, + N: Into>, + T: Into>, { if options.permissions.is_none() { options.permissions = Some(0o777); @@ -1303,7 +1302,7 @@ impl GenericZipWriter { .into()); } }; - *self = (make_new_self)(bare); + *self = make_new_self(bare); Ok(()) }