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