diff options
Diffstat (limited to 'vendor/zip/src')
-rw-r--r-- | vendor/zip/src/compression.rs | 6 | ||||
-rw-r--r-- | vendor/zip/src/read.rs | 20 | ||||
-rw-r--r-- | vendor/zip/src/result.rs | 21 | ||||
-rw-r--r-- | vendor/zip/src/spec.rs | 16 | ||||
-rw-r--r-- | vendor/zip/src/types.rs | 91 | ||||
-rw-r--r-- | vendor/zip/src/write.rs | 56 |
6 files changed, 135 insertions, 75 deletions
diff --git a/vendor/zip/src/compression.rs b/vendor/zip/src/compression.rs index abd8b5300..baec93994 100644 --- a/vendor/zip/src/compression.rs +++ b/vendor/zip/src/compression.rs @@ -141,7 +141,7 @@ impl CompressionMethod { impl fmt::Display for CompressionMethod { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Just duplicate what the Debug format looks like, i.e, the enum key: - write!(f, "{:?}", self) + write!(f, "{self:?}") } } @@ -195,8 +195,8 @@ mod test { #[test] fn to_display_fmt() { fn check_match(method: CompressionMethod) { - let debug_str = format!("{:?}", method); - let display_str = format!("{}", method); + let debug_str = format!("{method:?}"); + let display_str = format!("{method}"); assert_eq!(debug_str, display_str); } diff --git a/vendor/zip/src/read.rs b/vendor/zip/src/read.rs index 728ddf579..dad20c260 100644 --- a/vendor/zip/src/read.rs +++ b/vendor/zip/src/read.rs @@ -348,7 +348,9 @@ impl<R: Read + io::Seek> ZipArchive<R> { Some(locator64) => { // If we got here, this is indeed a ZIP64 file. - if footer.disk_number as u32 != locator64.disk_with_central_directory { + if !footer.record_too_small() + && footer.disk_number as u32 != locator64.disk_with_central_directory + { return unsupported_zip_error( "Support for multi-disk files is not implemented", ); @@ -401,7 +403,7 @@ impl<R: Read + io::Seek> ZipArchive<R> { pub fn new(mut reader: R) -> ZipResult<ZipArchive<R>> { let (footer, cde_start_pos) = spec::CentralDirectoryEnd::find_and_parse(&mut reader)?; - if footer.disk_number != footer.disk_with_central_directory { + if !footer.record_too_small() && footer.disk_number != footer.disk_with_central_directory { return unsupported_zip_error("Support for multi-disk files is not implemented"); } @@ -461,7 +463,7 @@ impl<R: Read + io::Seek> ZipArchive<R> { } else { if let Some(p) = outpath.parent() { if !p.exists() { - fs::create_dir_all(&p)?; + fs::create_dir_all(p)?; } } let mut outfile = fs::File::create(&outpath)?; @@ -681,11 +683,11 @@ pub(crate) fn central_header_to_zip_file<R: Read + io::Seek>( reader.read_exact(&mut file_comment_raw)?; let file_name = match is_utf8 { - true => String::from_utf8_lossy(&*file_name_raw).into_owned(), + true => String::from_utf8_lossy(&file_name_raw).into_owned(), false => file_name_raw.clone().from_cp437(), }; let file_comment = match is_utf8 { - true => String::from_utf8_lossy(&*file_comment_raw).into_owned(), + true => String::from_utf8_lossy(&file_comment_raw).into_owned(), false => file_comment_raw.from_cp437(), }; @@ -920,12 +922,12 @@ impl<'a> ZipFile<'a> { self.data.compression_method } - /// Get the size of the file in the archive + /// Get the size of the file, in bytes, in the archive pub fn compressed_size(&self) -> u64 { self.data.compressed_size } - /// Get the size of the file when uncompressed + /// Get the size of the file, in bytes, when uncompressed pub fn size(&self) -> u64 { self.data.uncompressed_size } @@ -1085,7 +1087,7 @@ pub fn read_zipfile_from_stream<'a, R: io::Read>( reader.read_exact(&mut extra_field)?; let file_name = match is_utf8 { - true => String::from_utf8_lossy(&*file_name_raw).into_owned(), + true => String::from_utf8_lossy(&file_name_raw).into_owned(), false => file_name_raw.clone().from_cp437(), }; @@ -1129,7 +1131,7 @@ pub fn read_zipfile_from_stream<'a, R: io::Read>( return unsupported_zip_error("The file length is not available in the local header"); } - let limit_reader = (reader as &'a mut dyn io::Read).take(result.compressed_size as u64); + let limit_reader = (reader as &'a mut dyn io::Read).take(result.compressed_size); let result_crc32 = result.crc32; let result_compression_method = result.compression_method; diff --git a/vendor/zip/src/result.rs b/vendor/zip/src/result.rs index 72a30e488..00d558cb4 100644 --- a/vendor/zip/src/result.rs +++ b/vendor/zip/src/result.rs @@ -44,9 +44,9 @@ impl From<io::Error> for ZipError { impl fmt::Display for ZipError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { - ZipError::Io(err) => write!(fmt, "{}", err), - ZipError::InvalidArchive(err) => write!(fmt, "invalid Zip archive: {}", err), - ZipError::UnsupportedArchive(err) => write!(fmt, "unsupported Zip archive: {}", err), + ZipError::Io(err) => write!(fmt, "{err}"), + ZipError::InvalidArchive(err) => write!(fmt, "invalid Zip archive: {err}"), + ZipError::UnsupportedArchive(err) => write!(fmt, "unsupported Zip archive: {err}"), ZipError::FileNotFound => write!(fmt, "specified file not found in archive"), } } @@ -81,3 +81,18 @@ impl From<ZipError> for io::Error { io::Error::new(io::ErrorKind::Other, err) } } + +/// Error type for time parsing +#[derive(Debug)] +pub struct DateTimeRangeError; + +impl fmt::Display for DateTimeRangeError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!( + fmt, + "a date could not be represented within the bounds the MS-DOS date range (1980-2107)" + ) + } +} + +impl Error for DateTimeRangeError {} diff --git a/vendor/zip/src/spec.rs b/vendor/zip/src/spec.rs index 3ffcf7323..1d8cb0a64 100644 --- a/vendor/zip/src/spec.rs +++ b/vendor/zip/src/spec.rs @@ -23,6 +23,18 @@ pub struct CentralDirectoryEnd { } impl CentralDirectoryEnd { + // Per spec 4.4.1.4 - a CentralDirectoryEnd field might be insufficient to hold the + // required data. In this case the file SHOULD contain a ZIP64 format record + // and the field of this record will be set to -1 + pub(crate) fn record_too_small(&self) -> bool { + self.disk_number == 0xFFFF + || self.disk_with_central_directory == 0xFFFF + || self.number_of_files_on_this_disk == 0xFFFF + || self.number_of_files == 0xFFFF + || self.central_directory_size == 0xFFFFFFFF + || self.central_directory_offset == 0xFFFFFFFF + } + pub fn parse<T: Read>(reader: &mut T) -> ZipResult<CentralDirectoryEnd> { let magic = reader.read_u32::<LittleEndian>()?; if magic != CENTRAL_DIRECTORY_END_SIGNATURE { @@ -64,12 +76,12 @@ impl CentralDirectoryEnd { let mut pos = file_length - HEADER_SIZE; while pos >= search_upper_bound { - reader.seek(io::SeekFrom::Start(pos as u64))?; + reader.seek(io::SeekFrom::Start(pos))?; if reader.read_u32::<LittleEndian>()? == CENTRAL_DIRECTORY_END_SIGNATURE { reader.seek(io::SeekFrom::Current( BYTES_BETWEEN_MAGIC_AND_COMMENT_SIZE as i64, ))?; - let cde_start_pos = reader.seek(io::SeekFrom::Start(pos as u64))?; + let cde_start_pos = reader.seek(io::SeekFrom::Start(pos))?; return CentralDirectoryEnd::parse(reader).map(|cde| (cde, cde_start_pos)); } pos = match pos.checked_sub(1) { diff --git a/vendor/zip/src/types.rs b/vendor/zip/src/types.rs index b65fad401..ad3a5700b 100644 --- a/vendor/zip/src/types.rs +++ b/vendor/zip/src/types.rs @@ -1,13 +1,16 @@ //! Types that specify what is contained in a ZIP. -#[cfg(doc)] -use {crate::read::ZipFile, crate::write::FileOptions}; - +#[cfg(feature = "time")] +use std::convert::{TryFrom, TryInto}; #[cfg(not(any( all(target_arch = "arm", target_pointer_width = "32"), target_arch = "mips", target_arch = "powerpc" )))] use std::sync::atomic; +#[cfg(not(feature = "time"))] +use std::time::SystemTime; +#[cfg(doc)] +use {crate::read::ZipFile, crate::write::FileOptions}; #[cfg(any( all(target_arch = "arm", target_pointer_width = "32"), @@ -42,9 +45,11 @@ mod atomic { } #[cfg(feature = "time")] +use crate::result::DateTimeRangeError; +#[cfg(feature = "time")] use time::{error::ComponentRange, Date, Month, OffsetDateTime, PrimitiveDateTime, Time}; -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum System { Dos = 0, Unix = 3, @@ -115,7 +120,7 @@ impl DateTime { let years = (datepart & 0b1111111000000000) >> 9; DateTime { - year: (years + 1980) as u16, + year: years + 1980, month: months as u8, day: days as u8, hour: hours as u8, @@ -143,10 +148,8 @@ impl DateTime { second: u8, ) -> Result<DateTime, ()> { if (1980..=2107).contains(&year) - && month >= 1 - && month <= 12 - && day >= 1 - && day <= 31 + && (1..=12).contains(&month) + && (1..=31).contains(&day) && hour <= 23 && minute <= 59 && second <= 60 @@ -169,19 +172,9 @@ impl DateTime { /// /// Returns `Err` when this object is out of bounds #[allow(clippy::result_unit_err)] + #[deprecated(note = "use `DateTime::try_from()`")] pub fn from_time(dt: OffsetDateTime) -> Result<DateTime, ()> { - if dt.year() >= 1980 && dt.year() <= 2107 { - Ok(DateTime { - year: (dt.year()) as u16, - month: (dt.month()) as u8, - day: dt.day() as u8, - hour: dt.hour() as u8, - minute: dt.minute() as u8, - second: dt.second() as u8, - }) - } else { - Err(()) - } + dt.try_into().map_err(|_err| ()) } /// Gets the time portion of this datetime in the msdos representation @@ -197,8 +190,6 @@ impl DateTime { #[cfg(feature = "time")] /// Converts the DateTime to a OffsetDateTime structure pub fn to_time(&self) -> Result<OffsetDateTime, ComponentRange> { - use std::convert::TryFrom; - let date = Date::from_calendar_date(self.year as i32, Month::try_from(self.month)?, self.day)?; let time = Time::from_hms(self.hour, self.minute, self.second)?; @@ -256,6 +247,26 @@ impl DateTime { } } +#[cfg(feature = "time")] +impl TryFrom<OffsetDateTime> for DateTime { + type Error = DateTimeRangeError; + + fn try_from(dt: OffsetDateTime) -> Result<Self, Self::Error> { + if dt.year() >= 1980 && dt.year() <= 2107 { + Ok(DateTime { + year: (dt.year()) as u16, + month: (dt.month()) as u8, + day: dt.day(), + hour: dt.hour(), + minute: dt.minute(), + second: dt.second(), + }) + } else { + Err(DateTimeRangeError) + } + } +} + pub const DEFAULT_VERSION: u8 = 46; /// A type like `AtomicU64` except it implements `Clone` and has predefined @@ -500,20 +511,43 @@ mod test { #[cfg(feature = "time")] #[test] fn datetime_from_time_bounds() { + use std::convert::TryFrom; + + use super::DateTime; + use time::macros::datetime; + + // 1979-12-31 23:59:59 + assert!(DateTime::try_from(datetime!(1979-12-31 23:59:59 UTC)).is_err()); + + // 1980-01-01 00:00:00 + assert!(DateTime::try_from(datetime!(1980-01-01 00:00:00 UTC)).is_ok()); + + // 2107-12-31 23:59:59 + assert!(DateTime::try_from(datetime!(2107-12-31 23:59:59 UTC)).is_ok()); + + // 2108-01-01 00:00:00 + assert!(DateTime::try_from(datetime!(2108-01-01 00:00:00 UTC)).is_err()); + } + + #[cfg(feature = "time")] + #[test] + fn datetime_try_from_bounds() { + use std::convert::TryFrom; + use super::DateTime; use time::macros::datetime; // 1979-12-31 23:59:59 - assert!(DateTime::from_time(datetime!(1979-12-31 23:59:59 UTC)).is_err()); + assert!(DateTime::try_from(datetime!(1979-12-31 23:59:59 UTC)).is_err()); // 1980-01-01 00:00:00 - assert!(DateTime::from_time(datetime!(1980-01-01 00:00:00 UTC)).is_ok()); + assert!(DateTime::try_from(datetime!(1980-01-01 00:00:00 UTC)).is_ok()); // 2107-12-31 23:59:59 - assert!(DateTime::from_time(datetime!(2107-12-31 23:59:59 UTC)).is_ok()); + assert!(DateTime::try_from(datetime!(2107-12-31 23:59:59 UTC)).is_ok()); // 2108-01-01 00:00:00 - assert!(DateTime::from_time(datetime!(2108-01-01 00:00:00 UTC)).is_err()); + assert!(DateTime::try_from(datetime!(2108-01-01 00:00:00 UTC)).is_err()); } #[test] @@ -564,10 +598,11 @@ mod test { #[test] fn time_at_january() { use super::DateTime; + use std::convert::TryFrom; // 2020-01-01 00:00:00 let clock = OffsetDateTime::from_unix_timestamp(1_577_836_800).unwrap(); - assert!(DateTime::from_time(clock).is_ok()); + assert!(DateTime::try_from(clock).is_ok()); } } diff --git a/vendor/zip/src/write.rs b/vendor/zip/src/write.rs index 61ce378c0..14252b4d5 100644 --- a/vendor/zip/src/write.rs +++ b/vendor/zip/src/write.rs @@ -7,6 +7,7 @@ use crate::spec; use crate::types::{AtomicU64, DateTime, System, ZipFileData, DEFAULT_VERSION}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use crc32fast::Hasher; +use std::convert::TryInto; use std::default::Default; use std::io; use std::io::prelude::*; @@ -110,31 +111,6 @@ pub struct FileOptions { } impl FileOptions { - /// Construct a new FileOptions object - pub fn default() -> FileOptions { - FileOptions { - #[cfg(any( - feature = "deflate", - feature = "deflate-miniz", - feature = "deflate-zlib" - ))] - compression_method: CompressionMethod::Deflated, - #[cfg(not(any( - feature = "deflate", - feature = "deflate-miniz", - feature = "deflate-zlib" - )))] - compression_method: CompressionMethod::Stored, - compression_level: None, - #[cfg(feature = "time")] - last_modified_time: DateTime::from_time(OffsetDateTime::now_utc()).unwrap_or_default(), - #[cfg(not(feature = "time"))] - last_modified_time: DateTime::default(), - permissions: None, - large_file: false, - } - } - /// Set the compression method for the new file /// /// The default is `CompressionMethod::Deflated`. If the deflate compression feature is @@ -198,8 +174,29 @@ impl FileOptions { } impl Default for FileOptions { + /// Construct a new FileOptions object fn default() -> Self { - Self::default() + Self { + #[cfg(any( + feature = "deflate", + feature = "deflate-miniz", + feature = "deflate-zlib" + ))] + compression_method: CompressionMethod::Deflated, + #[cfg(not(any( + feature = "deflate", + feature = "deflate-miniz", + feature = "deflate-zlib" + )))] + compression_method: CompressionMethod::Stored, + compression_level: None, + #[cfg(feature = "time")] + last_modified_time: OffsetDateTime::now_utc().try_into().unwrap_or_default(), + #[cfg(not(feature = "time"))] + last_modified_time: DateTime::default(), + permissions: None, + large_file: false, + } } } @@ -848,7 +845,7 @@ impl<W: Write + io::Seek> Drop for ZipWriter<W> { fn drop(&mut self) { if !self.inner.is_closed() { if let Err(e) = self.finalize() { - let _ = write!(io::stderr(), "ZipWriter drop failed: {:?}", e); + let _ = write!(io::stderr(), "ZipWriter drop failed: {e:?}"); } } } @@ -1211,8 +1208,7 @@ fn validate_extra_data(file: &ZipFileData) -> ZipResult<()> { return Err(ZipError::Io(io::Error::new( io::ErrorKind::Other, format!( - "Extra data header ID {:#06} requires crate feature \"unreserved\"", - kind, + "Extra data header ID {kind:#06} requires crate feature \"unreserved\"", ), ))); } @@ -1301,7 +1297,7 @@ fn path_to_string(path: &std::path::Path) -> String { if !path_str.is_empty() { path_str.push('/'); } - path_str.push_str(&*os_str.to_string_lossy()); + path_str.push_str(&os_str.to_string_lossy()); } } path_str |