fix: Alignment was previously handled incorrectly (#33)

This commit is contained in:
Chris Hennick 2024-04-23 12:07:30 -07:00
parent c3d9123abf
commit 00378bc6f2
No known key found for this signature in database
GPG key ID: DA47AABA4961C509
2 changed files with 23 additions and 12 deletions

View file

@ -1447,7 +1447,7 @@ mod test {
v.extend_from_slice(include_bytes!("../tests/data/deflate64_issue_25.zip")); v.extend_from_slice(include_bytes!("../tests/data/deflate64_issue_25.zip"));
ZipArchive::new(Cursor::new(v)).expect_err("Invalid file"); ZipArchive::new(Cursor::new(v)).expect_err("Invalid file");
} }
#[test] #[test]
fn test_read_with_data_descriptor() { fn test_read_with_data_descriptor() {
let mut v = Vec::new(); let mut v = Vec::new();

View file

@ -761,25 +761,36 @@ impl<W: Write + Seek> ZipWriter<W> {
let mut header_end = writer.stream_position()?; let mut header_end = writer.stream_position()?;
if options.alignment > 1 { if options.alignment > 1 {
let align = options.alignment as u64; let align = options.alignment as u64;
if header_end % align != 0 { let unaligned_header_bytes = header_end % align;
let pad_length = (align - (header_end + 4) % align) % align; if unaligned_header_bytes != 0 {
if pad_length + extra_field_length as u64 > u16::MAX as u64 { let pad_length = (align - unaligned_header_bytes) as usize;
let Some(new_extra_field_length) =
(pad_length as u16).checked_add(extra_field_length)
else {
let _ = self.abort_file(); let _ = self.abort_file();
return Err(InvalidArchive( return Err(InvalidArchive(
"Extra data field would be larger than allowed after aligning", "Extra data field would be larger than allowed after aligning",
)); ));
};
if pad_length >= 4 {
// Add an extra field to the extra_data
let pad_body = vec![0; pad_length - 4];
writer.write_all(b"za").map_err(ZipError::from)?; // 0x617a
writer
.write_u16::<LittleEndian>(pad_body.len() as u16)
.map_err(ZipError::from)?;
writer.write_all(&pad_body).map_err(ZipError::from)?;
} else {
// extra_data padding is too small for an extra field header, so pad with
// zeroes
let pad = vec![0; pad_length];
writer.write_all(&pad).map_err(ZipError::from)?;
} }
let pad = vec![0; pad_length as usize];
writer.write_all(b"za").map_err(ZipError::from)?; // 0x617a
writer
.write_u16::<LittleEndian>(pad.len() as u16)
.map_err(ZipError::from)?;
writer.write_all(&pad).map_err(ZipError::from)?;
header_end = writer.stream_position()?; header_end = writer.stream_position()?;
// Update extra field length in local file header. // Update extra field length in local file header.
writer.seek(SeekFrom::Start(file.header_start + 28))?; writer.seek(SeekFrom::Start(file.header_start + 28))?;
writer.write_u16::<LittleEndian>(pad_length as u16 + extra_field_length)?; writer.write_u16::<LittleEndian>(new_extra_field_length)?;
writer.seek(SeekFrom::Start(header_end))?; writer.seek(SeekFrom::Start(header_end))?;
debug_assert_eq!(header_end % align, 0); debug_assert_eq!(header_end % align, 0);
} }
@ -2210,7 +2221,7 @@ mod test {
writer.finish()?; writer.finish()?;
Ok(()) Ok(())
} }
#[test] #[test]
fn test_alignment() { fn test_alignment() {
let page_size = 4096; let page_size = 4096;