From 7dd016aa541733522154be5081f602d9c8454d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20R=2E=20Miguel?= Date: Sat, 5 Feb 2022 23:08:21 -0300 Subject: [PATCH 1/2] feat: recover last modified time when unpacking zip archives --- Cargo.lock | 20 +++++++++++++++++++ Cargo.toml | 1 + src/archive/zip.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41829a7a7..03950f88b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -477,6 +477,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_threads" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15" +dependencies = [ + "libc", +] + [[package]] name = "number_prefix" version = "0.4.0" @@ -523,6 +532,7 @@ dependencies = [ "tar", "tempfile", "test-strategy", + "time", "xz2", "zip", "zstd", @@ -911,6 +921,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" +dependencies = [ + "libc", + "num_threads", +] + [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 2e088e6eb..7ab045793 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ xz2 = "0.1.6" zip = { version = "0.5.13", default-features = false } zstd = { version = "0.9.0", default-features = false } tempfile = "3.2.0" +time = { version = "0.3.7", default-features = false } ignore = "0.4.18" indicatif = "0.16.2" diff --git a/src/archive/zip.rs b/src/archive/zip.rs index 147bc51f1..d9d3ee459 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -33,7 +33,9 @@ where D: Write, { assert!(output_folder.read_dir().expect("dir exists").count() == 0); - let mut unpacked_files = vec![]; + + let mut unpacked_files = Vec::with_capacity(archive.len()); + for idx in 0..archive.len() { let mut file = archive.by_index(idx)?; let file_path = match file.enclosed_name() { @@ -67,13 +69,15 @@ where let mut output_file = fs::File::create(&file_path)?; io::copy(&mut file, &mut output_file)?; + + #[cfg(unix)] + set_last_modified_time(&output_file, &file)?; } } #[cfg(unix)] __unix_set_permissions(&file_path, &file)?; - let file_path = fs::canonicalize(&file_path)?; unpacked_files.push(file_path); } @@ -204,6 +208,47 @@ fn check_for_comments(file: &ZipFile) { } } +#[cfg(unix)] +/// Attempts to convert a [`zip::DateTime`] to a [`libc::timespec`]. +fn convert_zip_date_time(date_time: zip::DateTime) -> Option { + use time::{Date, Month, PrimitiveDateTime, Time}; + + // Safety: time::Month is repr(u8) and goes from 1 to 12 + let month: Month = unsafe { std::mem::transmute(date_time.month()) }; + + let date = Date::from_calendar_date(date_time.year() as _, month, date_time.day()).ok()?; + + let time = Time::from_hms(date_time.hour(), date_time.minute(), date_time.second()).ok()?; + + let date_time = PrimitiveDateTime::new(date, time); + let timestamp = date_time.assume_utc().unix_timestamp(); + + Some(libc::timespec { tv_sec: timestamp, tv_nsec: 0 }) +} + +#[cfg(unix)] +fn set_last_modified_time(file: &fs::File, zip_file: &ZipFile) -> crate::Result<()> { + use std::os::unix::prelude::AsRawFd; + + use libc::UTIME_NOW; + + let now = libc::timespec { tv_sec: 0, tv_nsec: UTIME_NOW }; + + let last_modified = zip_file.last_modified(); + let last_modified = convert_zip_date_time(last_modified).unwrap_or(now); + + // The first value is the last accessed time, which we'll set as being right now. + // The second value is the last modified time, which we'll copy over from the zip archive + let times = [now, last_modified]; + + let output_fd = file.as_raw_fd(); + + // TODO: check for -1 + unsafe { libc::futimens(output_fd, × as *const _) }; + + Ok(()) +} + #[cfg(unix)] fn __unix_set_permissions(file_path: &Path, file: &ZipFile) -> crate::Result<()> { use std::{fs::Permissions, os::unix::fs::PermissionsExt}; From dc931de7965a7ba2a9b2079b4a5f9c53379d19d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Marcos=20Bezerra?= Date: Mon, 7 Feb 2022 15:26:58 -0300 Subject: [PATCH 2/2] chore: specify `time` dependency only for unix --- Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7ab045793..6ea923d7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,10 +28,12 @@ xz2 = "0.1.6" zip = { version = "0.5.13", default-features = false } zstd = { version = "0.9.0", default-features = false } tempfile = "3.2.0" -time = { version = "0.3.7", default-features = false } ignore = "0.4.18" indicatif = "0.16.2" +[target.'cfg(unix)'.dependencies] +time = { version = "0.3.7", default-features = false } + [build-dependencies] clap = { version = "3.0.4", features = ["derive", "env"] } clap_complete = "3.0.2"