Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add function to raw copy files and update metadata #260

Merged
merged 2 commits into from
Nov 19, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 50 additions & 5 deletions src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -651,8 +651,8 @@
/// read previously-written files and not overwrite them.
///
/// Note: when using an `inner` that cannot overwrite flushed bytes, do not wrap it in a
/// [BufWriter], because that has a [Seek::seek] method that implicitly calls

Check warning on line 654 in src/write.rs

View workflow job for this annotation

GitHub Actions / style_and_docs (--no-default-features)

unresolved link to `BufWriter`
/// [BufWriter::flush], and ZipWriter needs to seek backward to update each file's header with

Check warning on line 655 in src/write.rs

View workflow job for this annotation

GitHub Actions / style_and_docs (--no-default-features)

unresolved link to `BufWriter::flush`
/// the size and checksum after writing the body.
///
/// This setting is false by default.
Expand Down Expand Up @@ -1258,11 +1258,7 @@
/// Ok(())
/// }
/// ```
pub fn raw_copy_file_rename<S: ToString>(
&mut self,
mut file: ZipFile,
name: S,
) -> ZipResult<()> {
pub fn raw_copy_file_rename<S: ToString>(&mut self, file: ZipFile, name: S) -> ZipResult<()> {
let mut options = SimpleFileOptions::default()
.large_file(file.compressed_size().max(file.size()) > spec::ZIP64_BYTES_THR)
.last_modified_time(
Expand All @@ -1274,7 +1270,15 @@
options = options.unix_permissions(perms);
}
Self::normalize_options(&mut options);
self.raw_copy_file_rename_internal(file, name, options)
}

fn raw_copy_file_rename_internal<S: ToString>(
&mut self,
mut file: ZipFile,
name: S,
options: SimpleFileOptions,
) -> ZipResult<()> {
let raw_values = ZipRawValues {
crc32: file.crc32(),
compressed_size: file.compressed_size(),
Expand Down Expand Up @@ -1330,6 +1334,47 @@
self.raw_copy_file_rename(file, name)
}

/// Add a new file using the already compressed data from a ZIP file being read and set the last
/// modified date and unix mode. This allows faster copies of the `ZipFile` since there is no need
/// to decompress and compress it again. Any `ZipFile` metadata other than the last modified date
/// and the unix mode is copied and not checked, for example the file CRC.
///
/// ```no_run
/// use std::io::{Read, Seek, Write};
/// use zip::{DateTime, ZipArchive, ZipWriter};
///
/// fn copy<R, W>(src: &mut ZipArchive<R>, dst: &mut ZipWriter<W>) -> zip::result::ZipResult<()>
/// where
/// R: Read + Seek,
/// W: Write + Seek,
/// {
/// // Retrieve file entry by name
/// let file = src.by_name("src_file.txt")?;
///
/// // Copy the previously obtained file entry to the destination zip archive
/// dst.raw_copy_file_touch(file, DateTime::default(), Some(0o644))?;
///
/// Ok(())
/// }
/// ```
pub fn raw_copy_file_touch(
&mut self,
file: ZipFile,
last_modified_time: DateTime,
unix_mode: Option<u32>,
) -> ZipResult<()> {
let name = file.name().to_owned();
let mut options = SimpleFileOptions::default()
.large_file(file.compressed_size().max(file.size()) > spec::ZIP64_BYTES_THR)
.last_modified_time(last_modified_time)
.compression_method(file.compression());
if let Some(perms) = unix_mode {
options = options.unix_permissions(perms);
}
Self::normalize_options(&mut options);
self.raw_copy_file_rename_internal(file, name, options)
}

/// Add a directory entry.
///
/// As directories have no content, you must not call [`ZipWriter::write`] before adding a new file.
Expand Down
Loading