mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-07 20:15:27 +00:00
Refactor the way we set last modified times
Last modified time is a piece of metadata that is available when decompressing an archive
This commit is contained in:
parent
e12c25e833
commit
71893aafeb
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -393,6 +393,12 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
version = "0.1.25"
|
version = "0.1.25"
|
||||||
@ -521,6 +527,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"clap_complete",
|
"clap_complete",
|
||||||
"clap_mangen",
|
"clap_mangen",
|
||||||
|
"filetime",
|
||||||
"flate2",
|
"flate2",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"ignore",
|
"ignore",
|
||||||
@ -913,10 +920,18 @@ version = "0.3.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c"
|
checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
"libc",
|
"libc",
|
||||||
"num_threads",
|
"num_threads",
|
||||||
|
"time-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-macros"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@ -1075,6 +1090,7 @@ dependencies = [
|
|||||||
"crc32fast",
|
"crc32fast",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"flate2",
|
"flate2",
|
||||||
|
"time",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -25,11 +25,12 @@ once_cell = "1.15.0"
|
|||||||
snap = "1.0.5"
|
snap = "1.0.5"
|
||||||
tar = "0.4.38"
|
tar = "0.4.38"
|
||||||
xz2 = "0.1.7"
|
xz2 = "0.1.7"
|
||||||
zip = { version = "0.6.2", default-features = false }
|
zip = { version = "0.6.2", default-features = false, features = ["time"] }
|
||||||
zstd = { version = "0.11.2", default-features = false }
|
zstd = { version = "0.11.2", default-features = false }
|
||||||
tempfile = "3.3.0"
|
tempfile = "3.3.0"
|
||||||
ignore = "0.4.18"
|
ignore = "0.4.18"
|
||||||
indicatif = "0.17.1"
|
indicatif = "0.17.1"
|
||||||
|
filetime = "0.2.17"
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
time = { version = "0.3.15", default-features = false }
|
time = { version = "0.3.15", default-features = false }
|
||||||
|
@ -10,6 +10,7 @@ use std::{
|
|||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use filetime::{set_file_mtime, FileTime};
|
||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
use zip::{self, read::ZipFile, ZipArchive};
|
use zip::{self, read::ZipFile, ZipArchive};
|
||||||
|
|
||||||
@ -72,13 +73,12 @@ where
|
|||||||
let mut output_file = fs::File::create(file_path)?;
|
let mut output_file = fs::File::create(file_path)?;
|
||||||
io::copy(&mut file, &mut output_file)?;
|
io::copy(&mut file, &mut output_file)?;
|
||||||
|
|
||||||
#[cfg(unix)]
|
set_last_modified_time(&file, file_path)?;
|
||||||
set_last_modified_time(&output_file, &file)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
__unix_set_permissions(&file_path, &file)?;
|
unix_set_permissions(&file_path, &file)?;
|
||||||
|
|
||||||
unpacked_files.push(file_path);
|
unpacked_files.push(file_path);
|
||||||
}
|
}
|
||||||
@ -228,55 +228,23 @@ fn display_zip_comment_if_exists(file: &ZipFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
fn set_last_modified_time(zip_file: &ZipFile, path: &Path) -> crate::Result<()> {
|
||||||
/// Attempts to convert a [`zip::DateTime`] to a [`libc::timespec`].
|
let modification_time_in_seconds = zip_file
|
||||||
fn convert_zip_date_time(date_time: zip::DateTime) -> Option<libc::timespec> {
|
.last_modified()
|
||||||
use time::{Date, Month, PrimitiveDateTime, Time};
|
.to_time()
|
||||||
|
.expect("Zip archive contains a file with broken 'last modified time'")
|
||||||
|
.unix_timestamp();
|
||||||
|
|
||||||
// Safety: time::Month is repr(u8) and goes from 1 to 12
|
// Zip does not support nanoseconds, so we can assume zero here
|
||||||
let month: Month = unsafe { std::mem::transmute(date_time.month()) };
|
let modification_time = FileTime::from_unix_time(modification_time_in_seconds, 0);
|
||||||
|
|
||||||
let date = Date::from_calendar_date(date_time.year() as _, month, date_time.day()).ok()?;
|
set_file_mtime(path, modification_time)?;
|
||||||
|
|
||||||
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn __unix_set_permissions(file_path: &Path, file: &ZipFile) -> crate::Result<()> {
|
fn unix_set_permissions(file_path: &Path, file: &ZipFile) -> crate::Result<()> {
|
||||||
use std::fs::Permissions;
|
use std::fs::Permissions;
|
||||||
|
|
||||||
if let Some(mode) = file.unix_mode() {
|
if let Some(mode) = file.unix_mode() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user