Fix bad mergee: write_local_file_header is now part of start_entry
This commit is contained in:
parent
c23bcc55fb
commit
0482a1329a
1 changed files with 13 additions and 127 deletions
140
src/write.rs
140
src/write.rs
|
@ -815,15 +815,15 @@ impl<W: Write + Seek> ZipWriter<W> {
|
||||||
let index = self.insert_file_data(file)?;
|
let index = self.insert_file_data(file)?;
|
||||||
let file = &mut self.files[index];
|
let file = &mut self.files[index];
|
||||||
let writer = self.inner.get_plain();
|
let writer = self.inner.get_plain();
|
||||||
|
// local file header signature
|
||||||
writer.write_u32_le(spec::LOCAL_FILE_HEADER_SIGNATURE)?;
|
writer.write_u32_le(spec::LOCAL_FILE_HEADER_SIGNATURE)?;
|
||||||
// version needed to extract
|
// version needed to extract
|
||||||
writer.write_u16_le(file.version_needed())?;
|
writer.write_u16_le(file.version_needed())?;
|
||||||
// general purpose bit flag
|
// general purpose bit flag
|
||||||
let flag = if !file.file_name.is_ascii() {
|
let is_utf8 = std::str::from_utf8(&file.file_name_raw).is_ok();
|
||||||
1u16 << 11
|
let is_ascii = file.file_name_raw.is_ascii();
|
||||||
} else {
|
let flag = if is_utf8 && !is_ascii { 1u16 << 11 } else { 0 }
|
||||||
0
|
| if file.encrypted { 1u16 << 0 } else { 0 };
|
||||||
} | if file.encrypted { 1u16 << 0 } else { 0 };
|
|
||||||
writer.write_u16_le(flag)?;
|
writer.write_u16_le(flag)?;
|
||||||
// Compression method
|
// Compression method
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
|
@ -842,89 +842,22 @@ impl<W: Write + Seek> ZipWriter<W> {
|
||||||
writer.write_u32_le(file.uncompressed_size as u32)?;
|
writer.write_u32_le(file.uncompressed_size as u32)?;
|
||||||
}
|
}
|
||||||
// file name length
|
// file name length
|
||||||
writer.write_u16_le(file.file_name.as_bytes().len() as u16)?;
|
writer.write_u16_le(file.file_name_raw.len() as u16)?;
|
||||||
// extra field length
|
// extra field length
|
||||||
let mut extra_field_length = file.extra_field_len();
|
let mut extra_field_length = if file.large_file { 20 } else { 0 };
|
||||||
if file.large_file {
|
if let Some(field) = &file.extra_field {
|
||||||
extra_field_length += 20;
|
extra_field_length += field.len();
|
||||||
}
|
}
|
||||||
if extra_field_length + file.central_extra_field_len() > u16::MAX as usize {
|
match extra_field_length.try_into() {
|
||||||
let _ = self.abort_file();
|
Ok(length_u16) => writer.write_u16_le(length_u16)?,
|
||||||
return Err(InvalidArchive("Extra data field is too large"));
|
Err(_) => return Err(ZipError::InvalidArchive("Extra field is too long")),
|
||||||
}
|
}
|
||||||
let extra_field_length = extra_field_length as u16;
|
|
||||||
writer.write_u16_le(extra_field_length)?;
|
|
||||||
// file name
|
// file name
|
||||||
writer.write_all(file.file_name.as_bytes())?;
|
writer.write_all(&file.file_name_raw)?;
|
||||||
// zip64 extra field
|
// zip64 extra field
|
||||||
if file.large_file {
|
if file.large_file {
|
||||||
write_local_zip64_extra_field(writer, file)?;
|
write_local_zip64_extra_field(writer, file)?;
|
||||||
}
|
}
|
||||||
if let Some(extra_field) = &file.extra_field {
|
|
||||||
file.extra_data_start = Some(writer.stream_position()?);
|
|
||||||
writer.write_all(extra_field)?;
|
|
||||||
}
|
|
||||||
let mut header_end = writer.stream_position()?;
|
|
||||||
if options.alignment > 1 {
|
|
||||||
let align = options.alignment as u64;
|
|
||||||
let unaligned_header_bytes = header_end % align;
|
|
||||||
if unaligned_header_bytes != 0 {
|
|
||||||
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();
|
|
||||||
return Err(InvalidArchive(
|
|
||||||
"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_le(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)?;
|
|
||||||
}
|
|
||||||
header_end = writer.stream_position()?;
|
|
||||||
|
|
||||||
// Update extra field length in local file header.
|
|
||||||
writer.seek(SeekFrom::Start(file.header_start + 28))?;
|
|
||||||
writer.write_u16_le(new_extra_field_length)?;
|
|
||||||
writer.seek(SeekFrom::Start(header_end))?;
|
|
||||||
debug_assert_eq!(header_end % align, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match options.encrypt_with {
|
|
||||||
#[cfg(feature = "aes-crypto")]
|
|
||||||
Some(EncryptWith::Aes { mode, password }) => {
|
|
||||||
let aeswriter = AesWriter::new(
|
|
||||||
mem::replace(&mut self.inner, GenericZipWriter::Closed).unwrap(),
|
|
||||||
mode,
|
|
||||||
password.as_bytes(),
|
|
||||||
)?;
|
|
||||||
self.inner = GenericZipWriter::Storer(MaybeEncrypted::Aes(aeswriter));
|
|
||||||
}
|
|
||||||
Some(EncryptWith::ZipCrypto(keys, ..)) => {
|
|
||||||
let mut zipwriter = crate::zipcrypto::ZipCryptoWriter {
|
|
||||||
writer: mem::replace(&mut self.inner, Closed).unwrap(),
|
|
||||||
buffer: vec![],
|
|
||||||
keys,
|
|
||||||
};
|
|
||||||
let crypto_header = [0u8; 12];
|
|
||||||
|
|
||||||
zipwriter.write_all(&crypto_header)?;
|
|
||||||
header_end = zipwriter.writer.stream_position()?;
|
|
||||||
self.inner = Storer(MaybeEncrypted::ZipCrypto(zipwriter));
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
self.stats.start = header_end;
|
self.stats.start = header_end;
|
||||||
debug_assert!(file.data_start.get().is_none());
|
debug_assert!(file.data_start.get().is_none());
|
||||||
file.data_start.get_or_init(|| header_end);
|
file.data_start.get_or_init(|| header_end);
|
||||||
|
@ -1725,53 +1658,6 @@ fn clamp_opt<T: Ord + Copy, U: Ord + Copy + TryFrom<T>>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_local_file_header<T: Write>(writer: &mut T, file: &ZipFileData) -> ZipResult<()> {
|
|
||||||
// local file header signature
|
|
||||||
writer.write_u32_le(spec::LOCAL_FILE_HEADER_SIGNATURE)?;
|
|
||||||
// version needed to extract
|
|
||||||
writer.write_u16_le(file.version_needed())?;
|
|
||||||
// general purpose bit flag
|
|
||||||
let is_utf8 = std::str::from_utf8(&file.file_name_raw).is_ok();
|
|
||||||
let is_ascii = file.file_name_raw.is_ascii();
|
|
||||||
let flag = if is_utf8 && !is_ascii { 1u16 << 11 } else { 0 }
|
|
||||||
| if file.encrypted { 1u16 << 0 } else { 0 };
|
|
||||||
writer.write_u16_le(flag)?;
|
|
||||||
// Compression method
|
|
||||||
#[allow(deprecated)]
|
|
||||||
writer.write_u16_le(file.compression_method.to_u16())?;
|
|
||||||
// last mod file time and last mod file date
|
|
||||||
writer.write_u16_le(file.last_modified_time.timepart())?;
|
|
||||||
writer.write_u16_le(file.last_modified_time.datepart())?;
|
|
||||||
// crc-32
|
|
||||||
writer.write_u32_le(file.crc32)?;
|
|
||||||
// compressed size and uncompressed size
|
|
||||||
if file.large_file {
|
|
||||||
writer.write_u32_le(spec::ZIP64_BYTES_THR as u32)?;
|
|
||||||
writer.write_u32_le(spec::ZIP64_BYTES_THR as u32)?;
|
|
||||||
} else {
|
|
||||||
writer.write_u32_le(file.compressed_size as u32)?;
|
|
||||||
writer.write_u32_le(file.uncompressed_size as u32)?;
|
|
||||||
}
|
|
||||||
// file name length
|
|
||||||
writer.write_u16_le(file.file_name_raw.len() as u16)?;
|
|
||||||
// extra field length
|
|
||||||
let mut extra_field_length = if file.large_file { 20 } else { 0 };
|
|
||||||
if let Some(field) = &file.extra_field {
|
|
||||||
extra_field_length += field.len();
|
|
||||||
}
|
|
||||||
match extra_field_length.try_into() {
|
|
||||||
Ok(length_u16) => writer.write_u16_le(length_u16)?,
|
|
||||||
Err(_) => return Err(ZipError::InvalidArchive("Extra field is too long")),
|
|
||||||
}
|
|
||||||
// file name
|
|
||||||
writer.write_all(&file.file_name_raw)?;
|
|
||||||
// zip64 extra field
|
|
||||||
if file.large_file {
|
|
||||||
write_local_zip64_extra_field(writer, file)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_aes_extra_data<W: Write + io::Seek>(
|
fn update_aes_extra_data<W: Write + io::Seek>(
|
||||||
writer: &mut W,
|
writer: &mut W,
|
||||||
file: &mut ZipFileData,
|
file: &mut ZipFileData,
|
||||||
|
|
Loading…
Add table
Reference in a new issue