refactor: Eliminate some magic numbers and unnecessary path prefixes (#225)
* refactor: eliminate a magic number for CDE block size * refactor: Minor refactors * refactor: Can use cde_start_pos to locate ZIP64 end locator * chore: Fix import that can no longer be feature-gated * chore: Fix import that can no longer be feature-gated
This commit is contained in:
parent
a29b860395
commit
3ecd65176c
2 changed files with 97 additions and 115 deletions
84
src/read.rs
84
src/read.rs
|
@ -8,7 +8,10 @@ use crate::crc32::Crc32Reader;
|
|||
use crate::extra_fields::{ExtendedTimestamp, ExtraField};
|
||||
use crate::read::zip_archive::{Shared, SharedBuilder};
|
||||
use crate::result::{ZipError, ZipResult};
|
||||
use crate::spec::{self, FixedSizeBlock, Pod, Zip32CentralDirectoryEnd, ZIP64_ENTRY_THR};
|
||||
use crate::spec::{
|
||||
self, FixedSizeBlock, Pod, Zip32CentralDirectoryEnd, Zip64CDELocatorBlock,
|
||||
Zip64CentralDirectoryEnd, ZIP64_ENTRY_THR,
|
||||
};
|
||||
use crate::types::{
|
||||
AesMode, AesVendorVersion, DateTime, System, ZipCentralEntryBlock, ZipFileData,
|
||||
ZipLocalEntryBlock,
|
||||
|
@ -47,7 +50,7 @@ pub(crate) mod zip_archive {
|
|||
/// Extract immutable data from `ZipArchive` to make it cheap to clone
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Shared {
|
||||
pub(crate) files: super::IndexMap<Box<str>, super::ZipFileData>,
|
||||
pub(crate) files: IndexMap<Box<str>, super::ZipFileData>,
|
||||
pub(super) offset: u64,
|
||||
pub(super) dir_start: u64,
|
||||
// This isn't yet used anywhere, but it is here for use cases in the future.
|
||||
|
@ -324,7 +327,7 @@ pub(crate) fn find_content<'a>(
|
|||
None => find_data_start(data, reader)?,
|
||||
};
|
||||
|
||||
reader.seek(io::SeekFrom::Start(data_start))?;
|
||||
reader.seek(SeekFrom::Start(data_start))?;
|
||||
Ok((reader as &mut dyn Read).take(data.compressed_size))
|
||||
}
|
||||
|
||||
|
@ -334,7 +337,7 @@ fn find_content_seek<'a, R: Read + Seek>(
|
|||
) -> ZipResult<SeekableTake<'a, R>> {
|
||||
// Parse local header
|
||||
let data_start = find_data_start(data, reader)?;
|
||||
reader.seek(io::SeekFrom::Start(data_start))?;
|
||||
reader.seek(SeekFrom::Start(data_start))?;
|
||||
|
||||
// Explicit Ok and ? are needed to convert io::Error to ZipError
|
||||
Ok(SeekableTake::new(reader, data.compressed_size)?)
|
||||
|
@ -345,7 +348,7 @@ fn find_data_start(
|
|||
reader: &mut (impl Read + Seek + Sized),
|
||||
) -> Result<u64, ZipError> {
|
||||
// Go to start of data.
|
||||
reader.seek(io::SeekFrom::Start(data.header_start))?;
|
||||
reader.seek(SeekFrom::Start(data.header_start))?;
|
||||
|
||||
// Parse static-sized fields and check the magic value.
|
||||
let block = ZipLocalEntryBlock::parse(reader)?;
|
||||
|
@ -449,7 +452,7 @@ impl<R> ZipArchive<R> {
|
|||
Some((_, file)) => file.header_start,
|
||||
None => central_start,
|
||||
};
|
||||
let shared = Arc::new(zip_archive::Shared {
|
||||
let shared = Arc::new(Shared {
|
||||
files,
|
||||
offset: initial_offset,
|
||||
dir_start: central_start,
|
||||
|
@ -479,7 +482,7 @@ impl<R> ZipArchive<R> {
|
|||
}
|
||||
|
||||
impl<R: Read + Seek> ZipArchive<R> {
|
||||
pub(crate) fn merge_contents<W: Write + io::Seek>(
|
||||
pub(crate) fn merge_contents<W: Write + Seek>(
|
||||
&mut self,
|
||||
mut w: W,
|
||||
) -> ZipResult<IndexMap<Box<str>, ZipFileData>> {
|
||||
|
@ -543,7 +546,7 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
fn get_directory_info_zip32(
|
||||
config: &Config,
|
||||
reader: &mut R,
|
||||
footer: &spec::Zip32CentralDirectoryEnd,
|
||||
footer: &Zip32CentralDirectoryEnd,
|
||||
cde_start_pos: u64,
|
||||
) -> ZipResult<CentralDirectoryInfo> {
|
||||
let archive_offset = match config.archive_offset {
|
||||
|
@ -556,15 +559,13 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
let mut offset = cde_start_pos
|
||||
.checked_sub(footer.central_directory_size as u64)
|
||||
.and_then(|x| x.checked_sub(footer.central_directory_offset as u64))
|
||||
.ok_or(ZipError::InvalidArchive(
|
||||
"Invalid central directory size or offset",
|
||||
))?;
|
||||
.ok_or(InvalidArchive("Invalid central directory size or offset"))?;
|
||||
|
||||
if config.archive_offset == ArchiveOffset::Detect {
|
||||
// Check whether the archive offset makes sense by peeking at the directory start. If it
|
||||
// doesn't, fall back to using no archive offset. This supports zips with the central
|
||||
// directory entries somewhere other than directly preceding the end of central directory.
|
||||
reader.seek(io::SeekFrom::Start(
|
||||
reader.seek(SeekFrom::Start(
|
||||
offset + footer.central_directory_offset as u64,
|
||||
))?;
|
||||
let mut buf = [0; 4];
|
||||
|
@ -593,11 +594,6 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
})
|
||||
}
|
||||
|
||||
const fn zip64_cde_len() -> usize {
|
||||
mem::size_of::<spec::Zip64CentralDirectoryEnd>()
|
||||
+ mem::size_of::<spec::Zip64CentralDirectoryEndLocator>()
|
||||
}
|
||||
|
||||
const fn order_lower_upper_bounds(a: u64, b: u64) -> (u64, u64) {
|
||||
if a > b {
|
||||
(b, a)
|
||||
|
@ -609,16 +605,18 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
fn get_directory_info_zip64(
|
||||
config: &Config,
|
||||
reader: &mut R,
|
||||
footer: &spec::Zip32CentralDirectoryEnd,
|
||||
cde_start_pos: u64,
|
||||
) -> ZipResult<Vec<ZipResult<CentralDirectoryInfo>>> {
|
||||
// See if there's a ZIP64 footer. The ZIP64 locator if present will
|
||||
// have its signature 20 bytes in front of the standard footer. The
|
||||
// standard footer, in turn, is 22+N bytes large, where N is the
|
||||
// comment length. Therefore:
|
||||
/* TODO: compute this from constant sizes and offsets! */
|
||||
reader.seek(io::SeekFrom::End(
|
||||
-(20 + 22 + footer.zip_file_comment.len() as i64),
|
||||
reader.seek(SeekFrom::Start(
|
||||
cde_start_pos
|
||||
.checked_sub(size_of::<Zip64CDELocatorBlock>() as u64)
|
||||
.ok_or(InvalidArchive(
|
||||
"No room for ZIP64 locator before central directory end",
|
||||
))?,
|
||||
))?;
|
||||
let locator64 = spec::Zip64CentralDirectoryEndLocator::parse(reader)?;
|
||||
|
||||
|
@ -632,8 +630,11 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
// ZIP comment data.
|
||||
|
||||
let search_upper_bound = cde_start_pos
|
||||
.checked_sub(Self::zip64_cde_len() as u64)
|
||||
.ok_or(ZipError::InvalidArchive(
|
||||
.checked_sub(
|
||||
(size_of::<Zip64CentralDirectoryEnd>()
|
||||
+ size_of::<spec::Zip64CentralDirectoryEndLocator>()) as u64,
|
||||
)
|
||||
.ok_or(InvalidArchive(
|
||||
"File cannot contain ZIP64 central directory end",
|
||||
))?;
|
||||
|
||||
|
@ -642,7 +643,7 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
search_upper_bound,
|
||||
);
|
||||
|
||||
let search_results = spec::Zip64CentralDirectoryEnd::find_and_parse(reader, lower, upper)?;
|
||||
let search_results = Zip64CentralDirectoryEnd::find_and_parse(reader, lower, upper)?;
|
||||
let results: Vec<ZipResult<CentralDirectoryInfo>> =
|
||||
search_results.into_iter().map(|(footer64, archive_offset)| {
|
||||
let archive_offset = match config.archive_offset {
|
||||
|
@ -654,7 +655,7 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
// Check whether the archive offset makes sense by peeking at the directory start.
|
||||
//
|
||||
// If any errors occur or no header signature is found, fall back to no offset to see if that works.
|
||||
reader.seek(io::SeekFrom::Start(start)).ok()?;
|
||||
reader.seek(SeekFrom::Start(start)).ok()?;
|
||||
let mut buf = [0; 4];
|
||||
reader.read_exact(&mut buf).ok()?;
|
||||
if spec::Magic::from_le_bytes(buf) != spec::Magic::CENTRAL_DIRECTORY_HEADER_SIGNATURE {
|
||||
|
@ -669,19 +670,19 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
let directory_start = footer64
|
||||
.central_directory_offset
|
||||
.checked_add(archive_offset)
|
||||
.ok_or(ZipError::InvalidArchive(
|
||||
.ok_or(InvalidArchive(
|
||||
"Invalid central directory size or offset",
|
||||
))?;
|
||||
if directory_start > search_upper_bound {
|
||||
Err(ZipError::InvalidArchive(
|
||||
Err(InvalidArchive(
|
||||
"Invalid central directory size or offset",
|
||||
))
|
||||
} else if footer64.number_of_files_on_this_disk > footer64.number_of_files {
|
||||
Err(ZipError::InvalidArchive(
|
||||
Err(InvalidArchive(
|
||||
"ZIP64 footer indicates more files on this disk than in the whole archive",
|
||||
))
|
||||
} else if footer64.version_needed_to_extract > footer64.version_made_by {
|
||||
Err(ZipError::InvalidArchive(
|
||||
Err(InvalidArchive(
|
||||
"ZIP64 footer indicates a new version is needed to extract this archive than the \
|
||||
version that wrote it",
|
||||
))
|
||||
|
@ -711,7 +712,7 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
let mut invalid_errors_64 = Vec::new();
|
||||
let mut unsupported_errors_64 = Vec::new();
|
||||
let mut ok_results = Vec::new();
|
||||
let cde_locations = spec::Zip32CentralDirectoryEnd::find_and_parse(reader)?;
|
||||
let cde_locations = Zip32CentralDirectoryEnd::find_and_parse(reader)?;
|
||||
cde_locations
|
||||
.into_vec()
|
||||
.into_iter()
|
||||
|
@ -728,7 +729,7 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
let mut inner_results = Vec::with_capacity(1);
|
||||
// Check if file has a zip64 footer
|
||||
let zip64_vec_result =
|
||||
Self::get_directory_info_zip64(&config, reader, &footer, cde_start_pos);
|
||||
Self::get_directory_info_zip64(&config, reader, cde_start_pos);
|
||||
Self::sort_result(
|
||||
zip64_vec_result,
|
||||
&mut invalid_errors_64,
|
||||
|
@ -798,7 +799,7 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
.next()
|
||||
.unwrap());
|
||||
};
|
||||
reader.seek(io::SeekFrom::Start(shared.dir_start))?;
|
||||
reader.seek(SeekFrom::Start(shared.dir_start))?;
|
||||
Ok((Rc::try_unwrap(footer).unwrap(), shared.build()))
|
||||
}
|
||||
|
||||
|
@ -818,7 +819,7 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
return unsupported_zip_error("Support for multi-disk files is not implemented");
|
||||
}
|
||||
let mut files = Vec::with_capacity(file_capacity);
|
||||
reader.seek(io::SeekFrom::Start(dir_info.directory_start))?;
|
||||
reader.seek(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)?;
|
||||
files.push(file);
|
||||
|
@ -925,7 +926,7 @@ impl<R: Read + Seek> ZipArchive<R> {
|
|||
let mut file = self.by_index(i)?;
|
||||
let filepath = file
|
||||
.enclosed_name()
|
||||
.ok_or(ZipError::InvalidArchive("Invalid file path"))?;
|
||||
.ok_or(InvalidArchive("Invalid file path"))?;
|
||||
|
||||
let outpath = directory.as_ref().join(filepath);
|
||||
|
||||
|
@ -1333,7 +1334,7 @@ fn central_header_to_zip_file_inner<R: Read>(
|
|||
|
||||
let aes_enabled = result.compression_method == CompressionMethod::AES;
|
||||
if aes_enabled && result.aes_mode.is_none() {
|
||||
return Err(ZipError::InvalidArchive(
|
||||
return Err(InvalidArchive(
|
||||
"AES encryption without AES extra data field",
|
||||
));
|
||||
}
|
||||
|
@ -1342,7 +1343,7 @@ fn central_header_to_zip_file_inner<R: Read>(
|
|||
result.header_start = result
|
||||
.header_start
|
||||
.checked_add(archive_offset)
|
||||
.ok_or(ZipError::InvalidArchive("Archive header is too large"))?;
|
||||
.ok_or(InvalidArchive("Archive header is too large"))?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -1392,14 +1393,13 @@ pub(crate) fn parse_single_extra_field<R: Read>(
|
|||
"Can't write a custom field using the ZIP64 ID",
|
||||
));
|
||||
}
|
||||
file.large_file = true;
|
||||
let mut consumed_len = 0;
|
||||
if len >= 24 || file.uncompressed_size == spec::ZIP64_BYTES_THR {
|
||||
file.large_file = true;
|
||||
file.uncompressed_size = reader.read_u64_le()?;
|
||||
consumed_len += size_of::<u64>();
|
||||
}
|
||||
if len >= 24 || file.compressed_size == spec::ZIP64_BYTES_THR {
|
||||
file.large_file = true;
|
||||
file.compressed_size = reader.read_u64_le()?;
|
||||
consumed_len += size_of::<u64>();
|
||||
}
|
||||
|
@ -1428,18 +1428,18 @@ pub(crate) fn parse_single_extra_field<R: Read>(
|
|||
let compression_method = CompressionMethod::parse_from_u16(reader.read_u16_le()?);
|
||||
|
||||
if vendor_id != 0x4541 {
|
||||
return Err(ZipError::InvalidArchive("Invalid AES vendor"));
|
||||
return Err(InvalidArchive("Invalid AES vendor"));
|
||||
}
|
||||
let vendor_version = match vendor_version {
|
||||
0x0001 => AesVendorVersion::Ae1,
|
||||
0x0002 => AesVendorVersion::Ae2,
|
||||
_ => return Err(ZipError::InvalidArchive("Invalid AES vendor version")),
|
||||
_ => return Err(InvalidArchive("Invalid AES vendor version")),
|
||||
};
|
||||
match aes_mode {
|
||||
0x01 => file.aes_mode = Some((AesMode::Aes128, vendor_version, compression_method)),
|
||||
0x02 => file.aes_mode = Some((AesMode::Aes192, vendor_version, compression_method)),
|
||||
0x03 => file.aes_mode = Some((AesMode::Aes256, vendor_version, compression_method)),
|
||||
_ => return Err(ZipError::InvalidArchive("Invalid AES encryption strength")),
|
||||
_ => return Err(InvalidArchive("Invalid AES encryption strength")),
|
||||
};
|
||||
file.compression_method = compression_method;
|
||||
file.aes_extra_data_start = bytes_already_read;
|
||||
|
@ -1488,7 +1488,7 @@ pub trait HasZipMetadata {
|
|||
/// Methods for retrieving information on zip files
|
||||
impl<'a> ZipFile<'a> {
|
||||
pub(crate) fn take_raw_reader(&mut self) -> io::Result<io::Take<&'a mut dyn Read>> {
|
||||
std::mem::replace(&mut self.reader, ZipFileReader::NoReader).into_inner()
|
||||
mem::replace(&mut self.reader, ZipFileReader::NoReader).into_inner()
|
||||
}
|
||||
|
||||
/// Get the version of the file
|
||||
|
|
128
src/write.rs
128
src/write.rs
|
@ -50,7 +50,7 @@ use zstd::stream::write::Encoder as ZstdEncoder;
|
|||
enum MaybeEncrypted<W> {
|
||||
Unencrypted(W),
|
||||
#[cfg(feature = "aes-crypto")]
|
||||
Aes(crate::aes::AesWriter<W>),
|
||||
Aes(AesWriter<W>),
|
||||
ZipCrypto(crate::zipcrypto::ZipCryptoWriter<W>),
|
||||
}
|
||||
|
||||
|
@ -173,9 +173,7 @@ pub(crate) mod zip_writer {
|
|||
}
|
||||
#[doc(inline)]
|
||||
pub use self::sealed::FileOptionExtension;
|
||||
use crate::result::ZipError::InvalidArchive;
|
||||
#[cfg(any(feature = "lzma", feature = "xz"))]
|
||||
use crate::result::ZipError::UnsupportedArchive;
|
||||
use crate::result::ZipError::{InvalidArchive, UnsupportedArchive};
|
||||
use crate::unstable::path_to_string;
|
||||
use crate::unstable::LittleEndianWriteExt;
|
||||
use crate::write::GenericZipWriter::{Closed, Storer};
|
||||
|
@ -649,7 +647,7 @@ impl<A: Read + Write + Seek> ZipWriter<A> {
|
|||
/// read previously-written files and not overwrite them.
|
||||
///
|
||||
/// Note: when using an `inner` that cannot overwrite flushed bytes, do not wrap it in a
|
||||
/// [std::io::BufWriter], because that has a [Seek::seek] method that implicitly calls
|
||||
/// [BufWriter], because that has a [Seek::seek] method that implicitly calls
|
||||
/// [BufWriter::flush], and ZipWriter needs to seek backward to update each file's header with
|
||||
/// the size and checksum after writing the body.
|
||||
///
|
||||
|
@ -859,7 +857,7 @@ impl<W: Write + Seek> ZipWriter<W> {
|
|||
"No file has been started",
|
||||
)));
|
||||
}
|
||||
self.stats.hasher = crc32fast::Hasher::new_with_initial_len(crc32, length);
|
||||
self.stats.hasher = Hasher::new_with_initial_len(crc32, length);
|
||||
self.stats.bytes_written = length;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1005,11 +1003,11 @@ impl<W: Write + Seek> ZipWriter<W> {
|
|||
#[cfg(feature = "aes-crypto")]
|
||||
Some(EncryptWith::Aes { mode, password }) => {
|
||||
let aeswriter = AesWriter::new(
|
||||
mem::replace(&mut self.inner, GenericZipWriter::Closed).unwrap(),
|
||||
mem::replace(&mut self.inner, Closed).unwrap(),
|
||||
mode,
|
||||
password.as_bytes(),
|
||||
)?;
|
||||
self.inner = GenericZipWriter::Storer(MaybeEncrypted::Aes(aeswriter));
|
||||
self.inner = Storer(MaybeEncrypted::Aes(aeswriter));
|
||||
}
|
||||
Some(EncryptWith::ZipCrypto(keys, ..)) => {
|
||||
let mut zipwriter = crate::zipcrypto::ZipCryptoWriter {
|
||||
|
@ -1220,7 +1218,7 @@ impl<W: Write + Seek> ZipWriter<W> {
|
|||
///```
|
||||
pub fn merge_archive<R>(&mut self, mut source: ZipArchive<R>) -> ZipResult<()>
|
||||
where
|
||||
R: Read + io::Seek,
|
||||
R: Read + Seek,
|
||||
{
|
||||
self.finish_file()?;
|
||||
|
||||
|
@ -1615,9 +1613,7 @@ impl<W: Write + Seek> GenericZipWriter<W> {
|
|||
match compression {
|
||||
Stored => {
|
||||
if compression_level.is_some() {
|
||||
Err(ZipError::UnsupportedArchive(
|
||||
"Unsupported compression level",
|
||||
))
|
||||
Err(UnsupportedArchive("Unsupported compression level"))
|
||||
} else {
|
||||
Ok(Box::new(|bare| Storer(bare)))
|
||||
}
|
||||
|
@ -1637,9 +1633,8 @@ impl<W: Write + Seek> GenericZipWriter<W> {
|
|||
compression_level.unwrap_or(default),
|
||||
deflate_compression_level_range(),
|
||||
)
|
||||
.ok_or(ZipError::UnsupportedArchive(
|
||||
"Unsupported compression level",
|
||||
))? as u32;
|
||||
.ok_or(UnsupportedArchive("Unsupported compression level"))?
|
||||
as u32;
|
||||
|
||||
#[cfg(feature = "deflate-zopfli")]
|
||||
{
|
||||
|
@ -1681,18 +1676,17 @@ impl<W: Write + Seek> GenericZipWriter<W> {
|
|||
}
|
||||
}
|
||||
#[cfg(feature = "deflate64")]
|
||||
CompressionMethod::Deflate64 => Err(ZipError::UnsupportedArchive(
|
||||
"Compressing Deflate64 is not supported",
|
||||
)),
|
||||
CompressionMethod::Deflate64 => {
|
||||
Err(UnsupportedArchive("Compressing Deflate64 is not supported"))
|
||||
}
|
||||
#[cfg(feature = "bzip2")]
|
||||
CompressionMethod::Bzip2 => {
|
||||
let level = clamp_opt(
|
||||
compression_level.unwrap_or(bzip2::Compression::default().level() as i64),
|
||||
bzip2_compression_level_range(),
|
||||
)
|
||||
.ok_or(ZipError::UnsupportedArchive(
|
||||
"Unsupported compression level",
|
||||
))? as u32;
|
||||
.ok_or(UnsupportedArchive("Unsupported compression level"))?
|
||||
as u32;
|
||||
Ok(Box::new(move |bare| {
|
||||
GenericZipWriter::Bzip2(BzEncoder::new(
|
||||
bare,
|
||||
|
@ -1700,7 +1694,7 @@ impl<W: Write + Seek> GenericZipWriter<W> {
|
|||
))
|
||||
}))
|
||||
}
|
||||
CompressionMethod::AES => Err(ZipError::UnsupportedArchive(
|
||||
CompressionMethod::AES => Err(UnsupportedArchive(
|
||||
"AES encryption is enabled through FileOptions::with_aes_encryption",
|
||||
)),
|
||||
#[cfg(feature = "zstd")]
|
||||
|
@ -1709,9 +1703,7 @@ impl<W: Write + Seek> GenericZipWriter<W> {
|
|||
compression_level.unwrap_or(zstd::DEFAULT_COMPRESSION_LEVEL as i64),
|
||||
zstd::compression_level_range(),
|
||||
)
|
||||
.ok_or(ZipError::UnsupportedArchive(
|
||||
"Unsupported compression level",
|
||||
))?;
|
||||
.ok_or(UnsupportedArchive("Unsupported compression level"))?;
|
||||
Ok(Box::new(move |bare| {
|
||||
GenericZipWriter::Zstd(ZstdEncoder::new(bare, level as i32).unwrap())
|
||||
}))
|
||||
|
@ -1725,7 +1717,7 @@ impl<W: Write + Seek> GenericZipWriter<W> {
|
|||
Err(UnsupportedArchive("XZ isn't supported for compression"))
|
||||
}
|
||||
CompressionMethod::Unsupported(..) => {
|
||||
Err(ZipError::UnsupportedArchive("Unsupported compression"))
|
||||
Err(UnsupportedArchive("Unsupported compression"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1777,7 +1769,7 @@ impl<W: Write + Seek> GenericZipWriter<W> {
|
|||
}
|
||||
|
||||
const fn is_closed(&self) -> bool {
|
||||
matches!(*self, GenericZipWriter::Closed)
|
||||
matches!(*self, Closed)
|
||||
}
|
||||
|
||||
fn get_plain(&mut self) -> &mut W {
|
||||
|
@ -1832,17 +1824,14 @@ fn clamp_opt<T: Ord + Copy, U: Ord + Copy + TryFrom<T>>(
|
|||
}
|
||||
}
|
||||
|
||||
fn update_aes_extra_data<W: Write + io::Seek>(
|
||||
writer: &mut W,
|
||||
file: &mut ZipFileData,
|
||||
) -> ZipResult<()> {
|
||||
fn update_aes_extra_data<W: Write + Seek>(writer: &mut W, file: &mut ZipFileData) -> ZipResult<()> {
|
||||
let Some((aes_mode, version, compression_method)) = file.aes_mode else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let extra_data_start = file.extra_data_start.unwrap();
|
||||
|
||||
writer.seek(io::SeekFrom::Start(
|
||||
writer.seek(SeekFrom::Start(
|
||||
extra_data_start + file.aes_extra_data_start,
|
||||
))?;
|
||||
|
||||
|
@ -1925,7 +1914,7 @@ fn write_local_zip64_extra_field<T: Write>(writer: &mut T, file: &ZipFileData) -
|
|||
// This entry in the Local header MUST include BOTH original
|
||||
// and compressed file size fields.
|
||||
let Some(block) = file.zip64_extra_field_block() else {
|
||||
return Err(ZipError::InvalidArchive(
|
||||
return Err(InvalidArchive(
|
||||
"Attempted to write a ZIP64 extra field for a file that's within zip32 limits",
|
||||
));
|
||||
};
|
||||
|
@ -1938,19 +1927,15 @@ fn update_local_zip64_extra_field<T: Write + Seek>(
|
|||
writer: &mut T,
|
||||
file: &ZipFileData,
|
||||
) -> ZipResult<()> {
|
||||
if !file.large_file {
|
||||
return Err(ZipError::InvalidArchive(
|
||||
"Attempted to update a nonexistent ZIP64 extra field",
|
||||
));
|
||||
}
|
||||
let block = file.zip64_extra_field_block().ok_or(InvalidArchive(
|
||||
"Attempted to update a nonexistent ZIP64 extra field",
|
||||
))?;
|
||||
|
||||
let zip64_extra_field = file.header_start
|
||||
+ mem::size_of::<ZipLocalEntryBlock>() as u64
|
||||
let zip64_extra_field_start = file.header_start
|
||||
+ size_of::<ZipLocalEntryBlock>() as u64
|
||||
+ file.file_name_raw.len() as u64;
|
||||
|
||||
writer.seek(SeekFrom::Start(zip64_extra_field))?;
|
||||
|
||||
let block = file.zip64_extra_field_block().unwrap();
|
||||
writer.seek(SeekFrom::Start(zip64_extra_field_start))?;
|
||||
let block = block.serialize();
|
||||
writer.write_all(&block)?;
|
||||
Ok(())
|
||||
|
@ -1994,14 +1979,13 @@ mod test {
|
|||
use crate::zipcrypto::ZipCryptoKeys;
|
||||
use crate::CompressionMethod::Stored;
|
||||
use crate::ZipArchive;
|
||||
use std::io;
|
||||
use std::io::{Cursor, Read, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
fn write_empty_zip() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer.set_comment("ZIP");
|
||||
let result = writer.finish().unwrap();
|
||||
assert_eq!(result.get_ref().len(), 25);
|
||||
|
@ -2020,7 +2004,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn write_zip_dir() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.add_directory(
|
||||
"test",
|
||||
|
@ -2048,7 +2032,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn write_symlink_simple() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.add_symlink(
|
||||
"name",
|
||||
|
@ -2083,7 +2067,7 @@ mod test {
|
|||
path.push("..");
|
||||
path.push(".");
|
||||
path.push("example.txt");
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.start_file_from_path(path, SimpleFileOptions::default())
|
||||
.unwrap();
|
||||
|
@ -2093,7 +2077,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn write_symlink_wonky_paths() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.add_symlink(
|
||||
"directory\\link",
|
||||
|
@ -2125,9 +2109,9 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn write_mimetype_zip() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let options = FileOptions {
|
||||
compression_method: CompressionMethod::Stored,
|
||||
compression_method: Stored,
|
||||
compression_level: None,
|
||||
last_modified_time: DateTime::default(),
|
||||
permissions: Some(33188),
|
||||
|
@ -2162,9 +2146,9 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn write_non_utf8() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let options = FileOptions {
|
||||
compression_method: CompressionMethod::Stored,
|
||||
compression_method: Stored,
|
||||
compression_level: None,
|
||||
last_modified_time: DateTime::default(),
|
||||
permissions: Some(33188),
|
||||
|
@ -2199,7 +2183,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn path_to_string() {
|
||||
let mut path = std::path::PathBuf::new();
|
||||
let mut path = PathBuf::new();
|
||||
#[cfg(windows)]
|
||||
path.push(r"C:\");
|
||||
#[cfg(unix)]
|
||||
|
@ -2214,7 +2198,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_shallow_copy() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let options = FileOptions {
|
||||
compression_method: CompressionMethod::default(),
|
||||
compression_level: None,
|
||||
|
@ -2264,7 +2248,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_deep_copy() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let options = FileOptions {
|
||||
compression_method: CompressionMethod::default(),
|
||||
compression_level: None,
|
||||
|
@ -2312,7 +2296,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn duplicate_filenames() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.start_file("foo/bar/test", SimpleFileOptions::default())
|
||||
.unwrap();
|
||||
|
@ -2326,7 +2310,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_filename_looks_like_zip64_locator() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.start_file(
|
||||
"PK\u{6}\u{7}\0\0\0\u{11}\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
|
@ -2339,7 +2323,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_filename_looks_like_zip64_locator_2() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.start_file(
|
||||
"PK\u{6}\u{6}\0\0\0\0\0\0\0\0\0\0PK\u{6}\u{7}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
|
@ -2352,7 +2336,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_filename_looks_like_zip64_locator_2a() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.start_file(
|
||||
"PK\u{6}\u{6}PK\u{6}\u{7}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
|
@ -2365,7 +2349,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_filename_looks_like_zip64_locator_3() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.start_file("\0PK\u{6}\u{6}", SimpleFileOptions::default())
|
||||
.unwrap();
|
||||
|
@ -2381,7 +2365,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_filename_looks_like_zip64_locator_4() {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.start_file("PK\u{6}\u{6}", SimpleFileOptions::default())
|
||||
.unwrap();
|
||||
|
@ -2407,7 +2391,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_filename_looks_like_zip64_locator_5() -> ZipResult<()> {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.add_directory("", SimpleFileOptions::default().with_alignment(21))
|
||||
.unwrap();
|
||||
|
@ -2433,7 +2417,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn remove_shallow_copy_keeps_original() -> ZipResult<()> {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer
|
||||
.start_file("original", SimpleFileOptions::default())
|
||||
.unwrap();
|
||||
|
@ -2452,7 +2436,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn remove_encrypted_file() -> ZipResult<()> {
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let first_file_options = SimpleFileOptions::default()
|
||||
.with_alignment(65535)
|
||||
.with_deprecated_encryption(b"Password");
|
||||
|
@ -2469,7 +2453,7 @@ mod test {
|
|||
let mut options = SimpleFileOptions::default();
|
||||
options = options.with_deprecated_encryption(b"Password");
|
||||
options.alignment = 65535;
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer.add_symlink("", "s\t\0\0ggggg\0\0", options).unwrap();
|
||||
writer.abort_file().unwrap();
|
||||
let zip = writer.finish().unwrap();
|
||||
|
@ -2485,7 +2469,7 @@ mod test {
|
|||
options = options
|
||||
.compression_method(CompressionMethod::default())
|
||||
.compression_level(Some(264));
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
writer.start_file("", options).unwrap();
|
||||
writer.write_all(&[]).unwrap();
|
||||
writer.write_all(&[]).unwrap();
|
||||
|
@ -2495,11 +2479,9 @@ mod test {
|
|||
#[test]
|
||||
fn crash_with_no_features() -> ZipResult<()> {
|
||||
const ORIGINAL_FILE_NAME: &str = "PK\u{6}\u{6}\0\0\0\0\0\0\0\0\0\u{2}g\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\u{1}\0\0\0\0\0\0\0\0\0\0PK\u{6}\u{7}\0\0\0\0\0\0\0\0\0\0\0\0\u{7}\0\t'";
|
||||
let mut writer = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut writer = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let mut options = SimpleFileOptions::default();
|
||||
options = options
|
||||
.with_alignment(3584)
|
||||
.compression_method(CompressionMethod::Stored);
|
||||
options = options.with_alignment(3584).compression_method(Stored);
|
||||
writer.start_file(ORIGINAL_FILE_NAME, options)?;
|
||||
let archive = writer.finish()?;
|
||||
let mut writer = ZipWriter::new_append(archive)?;
|
||||
|
@ -2512,9 +2494,9 @@ mod test {
|
|||
fn test_alignment() {
|
||||
let page_size = 4096;
|
||||
let options = SimpleFileOptions::default()
|
||||
.compression_method(CompressionMethod::Stored)
|
||||
.compression_method(Stored)
|
||||
.with_alignment(page_size);
|
||||
let mut zip = ZipWriter::new(io::Cursor::new(Vec::new()));
|
||||
let mut zip = ZipWriter::new(Cursor::new(Vec::new()));
|
||||
let contents = b"sleeping";
|
||||
let () = zip.start_file("sleep", options).unwrap();
|
||||
let _count = zip.write(&contents[..]).unwrap();
|
||||
|
|
Loading…
Add table
Reference in a new issue