Use ZIP64_BYTES_THR and ZIP64_ENTRY_THR.

This commit is contained in:
Rouven Spreckels 2022-03-25 15:57:00 +01:00
parent e9706ae4f5
commit 00c1199dbe
3 changed files with 23 additions and 43 deletions

View file

@ -727,17 +727,17 @@ fn parse_extra_field(file: &mut ZipFileData) -> ZipResult<()> {
match kind {
// Zip64 extended information extra field
0x0001 => {
if file.uncompressed_size == 0xFFFFFFFF {
if file.uncompressed_size == spec::ZIP64_BYTES_THR {
file.large_file = true;
file.uncompressed_size = reader.read_u64::<LittleEndian>()?;
len_left -= 8;
}
if file.compressed_size == 0xFFFFFFFF {
if file.compressed_size == spec::ZIP64_BYTES_THR {
file.large_file = true;
file.compressed_size = reader.read_u64::<LittleEndian>()?;
len_left -= 8;
}
if file.header_start == 0xFFFFFFFF {
if file.header_start == spec::ZIP64_BYTES_THR {
file.header_start = reader.read_u64::<LittleEndian>()?;
len_left -= 8;
}

View file

@ -9,6 +9,9 @@ const CENTRAL_DIRECTORY_END_SIGNATURE: u32 = 0x06054b50;
pub const ZIP64_CENTRAL_DIRECTORY_END_SIGNATURE: u32 = 0x06064b50;
const ZIP64_CENTRAL_DIRECTORY_END_LOCATOR_SIGNATURE: u32 = 0x07064b50;
pub const ZIP64_BYTES_THR: u64 = u32::MAX as u64;
pub const ZIP64_ENTRY_THR: usize = u16::MAX as usize;
pub struct CentralDirectoryEnd {
pub disk_number: u16,
pub disk_with_central_directory: u16,

View file

@ -216,7 +216,7 @@ impl<W: Write + io::Seek> Write for ZipWriter<W> {
let write_result = w.write(buf);
if let Ok(count) = write_result {
self.stats.update(&buf[0..count]);
if self.stats.bytes_written > 0xFFFFFFFF
if self.stats.bytes_written > spec::ZIP64_BYTES_THR
&& !self.files.last_mut().unwrap().large_file
{
let _inner = mem::replace(&mut self.inner, GenericZipWriter::Closed);
@ -647,7 +647,7 @@ impl<W: Write + io::Seek> ZipWriter<W> {
S: Into<String>,
{
let mut options = FileOptions::default()
.large_file(file.compressed_size().max(file.size()) > 0xFFFFFFFF)
.large_file(file.compressed_size().max(file.size()) > spec::ZIP64_BYTES_THR)
.last_modified_time(file.last_modified())
.compression_method(file.compression());
if let Some(perms) = file.unix_mode() {
@ -760,7 +760,8 @@ impl<W: Write + io::Seek> ZipWriter<W> {
}
let central_size = writer.seek(io::SeekFrom::Current(0))? - central_start;
if self.files.len() > 0xFFFF || central_size > 0xFFFFFFFF || central_start > 0xFFFFFFFF
if self.files.len() > spec::ZIP64_ENTRY_THR
|| central_size.max(central_start) > spec::ZIP64_BYTES_THR
{
let zip64_footer = spec::Zip64CentralDirectoryEnd {
version_made_by: DEFAULT_VERSION as u16,
@ -784,27 +785,15 @@ impl<W: Write + io::Seek> ZipWriter<W> {
zip64_footer.write(writer)?;
}
let number_of_files = if self.files.len() > 0xFFFF {
0xFFFF
} else {
self.files.len() as u16
};
let number_of_files = self.files.len().min(spec::ZIP64_ENTRY_THR) as u16;
let footer = spec::CentralDirectoryEnd {
disk_number: 0,
disk_with_central_directory: 0,
zip_file_comment: self.comment.clone(),
number_of_files_on_this_disk: number_of_files,
number_of_files,
central_directory_size: if central_size > 0xFFFFFFFF {
0xFFFFFFFF
} else {
central_size as u32
},
central_directory_offset: if central_start > 0xFFFFFFFF {
0xFFFFFFFF
} else {
central_start as u32
},
central_directory_size: central_size.min(spec::ZIP64_BYTES_THR) as u32,
central_directory_offset: central_start.min(spec::ZIP64_BYTES_THR) as u32,
};
footer.write(writer)?;
@ -1030,8 +1019,8 @@ fn write_local_file_header<T: Write>(writer: &mut T, file: &ZipFileData) -> ZipR
writer.write_u32::<LittleEndian>(file.crc32)?;
// compressed size and uncompressed size
if file.large_file {
writer.write_u32::<LittleEndian>(0xFFFFFFFF)?;
writer.write_u32::<LittleEndian>(0xFFFFFFFF)?;
writer.write_u32::<LittleEndian>(spec::ZIP64_BYTES_THR as u32)?;
writer.write_u32::<LittleEndian>(spec::ZIP64_BYTES_THR as u32)?;
} else {
writer.write_u32::<LittleEndian>(file.compressed_size as u32)?;
writer.write_u32::<LittleEndian>(file.uncompressed_size as u32)?;
@ -1062,7 +1051,7 @@ fn update_local_file_header<T: Write + io::Seek>(
update_local_zip64_extra_field(writer, file)?;
} else {
// check compressed size as well as it can also be slightly larger than uncompressed size
if file.compressed_size > 0xFFFFFFFF {
if file.compressed_size > spec::ZIP64_BYTES_THR {
return Err(ZipError::Io(io::Error::new(
io::ErrorKind::Other,
"Large file option has not been set",
@ -1104,17 +1093,9 @@ fn write_central_directory_header<T: Write>(writer: &mut T, file: &ZipFileData)
// crc-32
writer.write_u32::<LittleEndian>(file.crc32)?;
// compressed size
writer.write_u32::<LittleEndian>(if file.compressed_size > 0xFFFFFFFF {
0xFFFFFFFF
} else {
file.compressed_size as u32
})?;
writer.write_u32::<LittleEndian>(file.compressed_size.min(spec::ZIP64_BYTES_THR) as u32)?;
// uncompressed size
writer.write_u32::<LittleEndian>(if file.uncompressed_size > 0xFFFFFFFF {
0xFFFFFFFF
} else {
file.uncompressed_size as u32
})?;
writer.write_u32::<LittleEndian>(file.uncompressed_size.min(spec::ZIP64_BYTES_THR) as u32)?;
// file name length
writer.write_u16::<LittleEndian>(file.file_name.as_bytes().len() as u16)?;
// extra field length
@ -1128,11 +1109,7 @@ fn write_central_directory_header<T: Write>(writer: &mut T, file: &ZipFileData)
// external file attributes
writer.write_u32::<LittleEndian>(file.external_attributes)?;
// relative offset of local header
writer.write_u32::<LittleEndian>(if file.header_start > 0xFFFFFFFF {
0xFFFFFFFF
} else {
file.header_start as u32
})?;
writer.write_u32::<LittleEndian>(file.header_start.min(spec::ZIP64_BYTES_THR) as u32)?;
// file name
writer.write_all(file.file_name.as_bytes())?;
// zip64 extra field
@ -1148,7 +1125,7 @@ fn write_central_directory_header<T: Write>(writer: &mut T, file: &ZipFileData)
fn validate_extra_data(file: &ZipFileData) -> ZipResult<()> {
let mut data = file.extra_field.as_slice();
if data.len() > 0xFFFF {
if data.len() > spec::ZIP64_ENTRY_THR {
return Err(ZipError::Io(io::Error::new(
io::ErrorKind::InvalidData,
"Extra data exceeds extra field",
@ -1231,9 +1208,9 @@ fn write_central_zip64_extra_field<T: Write>(writer: &mut T, file: &ZipFileData)
// only appear if the corresponding Local or Central
// directory record field is set to 0xFFFF or 0xFFFFFFFF.
let mut size = 0;
let uncompressed_size = file.uncompressed_size > 0xFFFFFFFF;
let compressed_size = file.compressed_size > 0xFFFFFFFF;
let header_start = file.header_start > 0xFFFFFFFF;
let uncompressed_size = file.uncompressed_size > spec::ZIP64_BYTES_THR;
let compressed_size = file.compressed_size > spec::ZIP64_BYTES_THR;
let header_start = file.header_start > spec::ZIP64_BYTES_THR;
if uncompressed_size {
size += 8;
}