Skip to content

Commit

Permalink
Switch from String to Box<str> for metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
Pr0methean committed Apr 8, 2024
1 parent c4492b9 commit 384afcd
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 35 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<str>` rather than `String` for metadata.
32 changes: 16 additions & 16 deletions src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -45,7 +45,7 @@ pub(crate) mod zip_archive {
#[derive(Debug)]
pub(crate) struct Shared {
pub(crate) files: Vec<super::ZipFileData>,
pub(crate) names_map: super::HashMap<String, usize>,
pub(crate) names_map: super::HashMap<Box<str>, usize>,
pub(super) offset: u64,
pub(super) dir_start: u64,
pub(super) dir_end: u64,
Expand Down Expand Up @@ -486,7 +486,7 @@ impl<R: Read + Seek> ZipArchive<R> {
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());

Check failure on line 489 in src/read.rs

View workflow job for this annotation

GitHub Actions / clippy

useless conversion to the same type: `std::boxed::Box<str>`
files.push(file);
}
let dir_end = reader.seek(io::SeekFrom::Start(dir_info.directory_start))?;
Expand Down Expand Up @@ -600,7 +600,7 @@ impl<R: Read + Seek> ZipArchive<R> {

/// Returns an iterator over all the file and directory names in this archive.
pub fn file_names(&self) -> impl Iterator<Item = &str> {
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
Expand Down Expand Up @@ -777,13 +777,13 @@ fn central_header_to_zip_file_inner<R: Read>(
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<str> = 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
Expand Down Expand Up @@ -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<PathBuf> {
self.data.enclosed_name()
}

Expand Down Expand Up @@ -1145,9 +1145,9 @@ pub fn read_zipfile_from_stream<'a, R: Read>(reader: &'a mut R) -> ZipResult<Opt
let mut extra_field = vec![0; extra_field_length];
reader.read_exact(&mut extra_field)?;

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<str> = 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 {
Expand All @@ -1161,11 +1161,11 @@ pub fn read_zipfile_from_stream<'a, R: Read>(reader: &'a mut R) -> ZipResult<Opt
crc32,
compressed_size: compressed_size as u64,
uncompressed_size: uncompressed_size as u64,
file_name,
file_name: file_name.into(),

Check failure on line 1164 in src/read.rs

View workflow job for this annotation

GitHub Actions / clippy

useless conversion to the same type: `std::boxed::Box<str>`
file_name_raw,
extra_field: Arc::new(extra_field),
central_extra_field: Arc::new(vec![]),
file_comment: String::new(), // file comment is only available in the central directory
file_comment: String::with_capacity(0).into_boxed_str(), // file comment is only available in the central directory
// header_start and data start are not available, but also don't matter, since seeking is
// not available.
header_start: 0,
Expand Down
2 changes: 1 addition & 1 deletion src/read/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ impl ZipStreamFileMetadata {
/// 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<PathBuf> {
self.0.enclosed_name()
}

Expand Down
16 changes: 8 additions & 8 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ impl TryFrom<OffsetDateTime> for DateTime {
fn try_from(dt: OffsetDateTime) -> Result<Self, Self::Error> {
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(),
Expand Down Expand Up @@ -385,15 +385,15 @@ 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<str>,
/// Raw file name. To be used when file_name was incorrectly decoded.
pub file_name_raw: Vec<u8>,
/// Extra field usually used for storage expansion
pub extra_field: Arc<Vec<u8>>,
/// Extra field only written to central directory
pub central_extra_field: Arc<Vec<u8>>,
/// File comment
pub file_comment: String,
pub file_comment: Box<str>,
/// Specifies where the local header of the file starts
pub header_start: u64,
/// Specifies where the central header of the file starts
Expand Down Expand Up @@ -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<PathBuf> {
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 {
Expand Down Expand Up @@ -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()),

Check failure on line 563 in src/types.rs

View workflow job for this annotation

GitHub Actions / clippy

the trait bound `&str: std::convert::Into<str>` is not satisfied

Check failure on line 563 in src/types.rs

View workflow job for this annotation

GitHub Actions / clippy

the size for values of type `str` cannot be known at compilation time

Check failure on line 563 in src/types.rs

View workflow job for this annotation

GitHub Actions / Build and test (ubuntu-latest, stable)

the trait bound `str: From<&str>` is not satisfied

Check failure on line 563 in src/types.rs

View workflow job for this annotation

GitHub Actions / Build and test (ubuntu-latest, stable)

the size for values of type `str` cannot be known at compilation time
header_start: 0,
data_start: AtomicU64::new(0),
central_header_start: 0,
Expand Down
19 changes: 9 additions & 10 deletions src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ pub(crate) mod zip_writer {
pub struct ZipWriter<W: Write + Seek> {
pub(super) inner: GenericZipWriter<W>,
pub(super) files: Vec<ZipFileData>,
pub(super) files_by_name: HashMap<String, usize>,
pub(super) files_by_name: HashMap<Box<str>, usize>,
pub(super) stats: ZipWriterStats,
pub(super) writing_to_file: bool,
pub(super) writing_raw: bool,
Expand Down Expand Up @@ -583,7 +583,7 @@ impl<W: Write + Seek> ZipWriter<W> {
raw_values: Option<ZipRawValues>,
) -> ZipResult<()>
where
S: Into<String>,
S: Into<Box<str>>,
{
self.finish_file()?;

Expand All @@ -595,7 +595,6 @@ impl<W: Write + Seek> ZipWriter<W> {

{
let header_start = self.inner.get_plain().stream_position()?;
let name = name.into();

let permissions = options.permissions.unwrap_or(0o100644);
let file = ZipFileData {
Expand All @@ -609,11 +608,11 @@ impl<W: Write + Seek> ZipWriter<W> {
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,
Expand Down Expand Up @@ -818,7 +817,7 @@ impl<W: Write + Seek> ZipWriter<W> {
/// The data should be written using the [`Write`] implementation on this [`ZipWriter`]
pub fn start_file<S>(&mut self, name: S, mut options: FileOptions) -> ZipResult<()>
where
S: Into<String>,
S: Into<Box<str>>,
{
Self::normalize_options(&mut options);
let make_new_self = self.inner.prepare_next_writer(
Expand Down Expand Up @@ -890,7 +889,7 @@ impl<W: Write + Seek> ZipWriter<W> {
/// ```
pub fn raw_copy_file_rename<S>(&mut self, mut file: ZipFile, name: S) -> ZipResult<()>
where
S: Into<String>,
S: Into<Box<str>>,
{
let mut options = FileOptions::default()
.large_file(file.compressed_size().max(file.size()) > spec::ZIP64_BYTES_THR)
Expand Down Expand Up @@ -1015,8 +1014,8 @@ impl<W: Write + Seek> ZipWriter<W> {
mut options: FileOptions,
) -> ZipResult<()>
where
N: Into<String>,
T: Into<String>,
N: Into<Box<str>>,
T: Into<Box<str>>,
{
if options.permissions.is_none() {
options.permissions = Some(0o777);
Expand Down Expand Up @@ -1303,7 +1302,7 @@ impl<W: Write + Seek> GenericZipWriter<W> {
.into());
}
};
*self = (make_new_self)(bare);
*self = make_new_self(bare);
Ok(())
}

Expand Down

0 comments on commit 384afcd

Please sign in to comment.