From 957c6c58fb7356bf6834a9628f873ce3eba35cc0 Mon Sep 17 00:00:00 2001 From: ardurin Date: Mon, 11 Nov 2024 18:14:06 +0100 Subject: [PATCH] Add function to raw copy files and update metadata --- src/write.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/src/write.rs b/src/write.rs index a7c300430..cf05fe724 100644 --- a/src/write.rs +++ b/src/write.rs @@ -1258,11 +1258,7 @@ impl ZipWriter { /// Ok(()) /// } /// ``` - pub fn raw_copy_file_rename( - &mut self, - mut file: ZipFile, - name: S, - ) -> ZipResult<()> { + pub fn raw_copy_file_rename(&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( @@ -1274,7 +1270,15 @@ impl ZipWriter { 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( + &mut self, + mut file: ZipFile, + name: S, + options: SimpleFileOptions, + ) -> ZipResult<()> { let raw_values = ZipRawValues { crc32: file.crc32(), compressed_size: file.compressed_size(), @@ -1330,6 +1334,47 @@ impl ZipWriter { 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(src: &mut ZipArchive, dst: &mut ZipWriter) -> 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, + ) -> 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.