1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 19:17:43 +00:00

Merge pull request #2288 from syukronrm/du-time

du: fix `--time` behavior
This commit is contained in:
Sylvestre Ledru 2021-06-03 07:56:41 +02:00 committed by GitHub
commit 963a0da0b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 23 deletions

View file

@ -14,6 +14,8 @@ use clap::{App, Arg};
use std::collections::HashSet;
use std::env;
use std::fs;
#[cfg(not(windows))]
use std::fs::Metadata;
use std::io::{stderr, ErrorKind, Result, Write};
use std::iter;
#[cfg(not(windows))]
@ -92,7 +94,7 @@ struct Stat {
size: u64,
blocks: u64,
inode: Option<FileInfo>,
created: u64,
created: Option<u64>,
accessed: u64,
modified: u64,
}
@ -113,7 +115,7 @@ impl Stat {
size: metadata.len(),
blocks: metadata.blocks() as u64,
inode: Some(file_info),
created: metadata.mtime() as u64,
created: birth_u64(&metadata),
accessed: metadata.atime() as u64,
modified: metadata.mtime() as u64,
});
@ -129,7 +131,7 @@ impl Stat {
size: metadata.len(),
blocks: size_on_disk / 1024 * 2,
inode: file_info,
created: windows_time_to_unix_time(metadata.creation_time()),
created: windows_creation_time_to_unix_time(metadata.creation_time()),
accessed: windows_time_to_unix_time(metadata.last_access_time()),
modified: windows_time_to_unix_time(metadata.last_write_time()),
})
@ -137,10 +139,24 @@ impl Stat {
}
#[cfg(windows)]
// https://doc.rust-lang.org/std/os/windows/fs/trait.MetadataExt.html#tymethod.creation_time
// https://doc.rust-lang.org/std/os/windows/fs/trait.MetadataExt.html#tymethod.last_access_time
// "The returned 64-bit value [...] which represents the number of 100-nanosecond intervals since January 1, 1601 (UTC)."
// "If the underlying filesystem does not support last access time, the returned value is 0."
fn windows_time_to_unix_time(win_time: u64) -> u64 {
win_time / 10_000_000 - 11_644_473_600
(win_time / 10_000_000).saturating_sub(11_644_473_600)
}
#[cfg(windows)]
fn windows_creation_time_to_unix_time(win_time: u64) -> Option<u64> {
(win_time / 10_000_000).checked_sub(11_644_473_600)
}
#[cfg(not(windows))]
fn birth_u64(meta: &Metadata) -> Option<u64> {
meta.created()
.ok()
.and_then(|t| t.duration_since(UNIX_EPOCH).ok())
.map(|e| e.as_secs() as u64)
}
#[cfg(windows)]
@ -539,10 +555,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.value_name("WORD")
.require_equals(true)
.min_values(0)
.possible_values(&["atime", "access", "use", "ctime", "status", "birth", "creation"])
.help(
"show time of the last modification of any file in the \
directory, or any of its subdirectories. If WORD is given, show time as WORD instead \
of modification time: atime, access, use, ctime or status"
of modification time: atime, access, use, ctime, status, birth or creation"
)
)
.arg(
@ -667,19 +684,22 @@ Try '{} --help' for more information.",
let secs = {
match matches.value_of(options::TIME) {
Some(s) => match s {
"accessed" => stat.accessed,
"created" => stat.created,
"modified" => stat.modified,
_ => {
show_error!(
"invalid argument 'modified' for '--time'
Valid arguments are:
- 'accessed', 'created', 'modified'
Try '{} --help' for more information.",
NAME
);
return 1;
"ctime" | "status" => stat.modified,
"access" | "atime" | "use" => stat.accessed,
"birth" | "creation" => {
if let Some(time) = stat.created {
time
} else {
show_error!(
"Invalid argument {} for --time.
birth and creation arguments are not supported on this platform.",
s
);
return 1;
}
}
// below should never happen as clap already restricts the values.
_ => unreachable!("Invalid field for --time"),
},
None => stat.modified,
}

View file

@ -240,18 +240,37 @@ fn test_du_time() {
scene
.ccmd("touch")
.arg("-a")
.arg("-m")
.arg("-t")
.arg("201505150000")
.arg("date_test")
.succeeds();
scene
.ucmd()
.arg("--time")
.ccmd("touch")
.arg("-m")
.arg("-t")
.arg("201606160000")
.arg("date_test")
.succeeds()
.stdout_only("0\t2015-05-15 00:00\tdate_test\n");
.succeeds();
let result = scene.ucmd().arg("--time").arg("date_test").succeeds();
result.stdout_only("0\t2016-06-16 00:00\tdate_test\n");
let result = scene.ucmd().arg("--time=atime").arg("date_test").succeeds();
result.stdout_only("0\t2015-05-15 00:00\tdate_test\n");
let result = scene.ucmd().arg("--time=ctime").arg("date_test").succeeds();
result.stdout_only("0\t2016-06-16 00:00\tdate_test\n");
#[cfg(not(target_env = "musl"))]
{
use regex::Regex;
let re_birth =
Regex::new(r"0\t[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}\tdate_test").unwrap();
let result = scene.ucmd().arg("--time=birth").arg("date_test").succeeds();
result.stdout_matches(&re_birth);
}
}
#[cfg(not(target_os = "windows"))]