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::collections::HashSet;
use std::env; use std::env;
use std::fs; use std::fs;
#[cfg(not(windows))]
use std::fs::Metadata;
use std::io::{stderr, ErrorKind, Result, Write}; use std::io::{stderr, ErrorKind, Result, Write};
use std::iter; use std::iter;
#[cfg(not(windows))] #[cfg(not(windows))]
@ -92,7 +94,7 @@ struct Stat {
size: u64, size: u64,
blocks: u64, blocks: u64,
inode: Option<FileInfo>, inode: Option<FileInfo>,
created: u64, created: Option<u64>,
accessed: u64, accessed: u64,
modified: u64, modified: u64,
} }
@ -113,7 +115,7 @@ impl Stat {
size: metadata.len(), size: metadata.len(),
blocks: metadata.blocks() as u64, blocks: metadata.blocks() as u64,
inode: Some(file_info), inode: Some(file_info),
created: metadata.mtime() as u64, created: birth_u64(&metadata),
accessed: metadata.atime() as u64, accessed: metadata.atime() as u64,
modified: metadata.mtime() as u64, modified: metadata.mtime() as u64,
}); });
@ -129,7 +131,7 @@ impl Stat {
size: metadata.len(), size: metadata.len(),
blocks: size_on_disk / 1024 * 2, blocks: size_on_disk / 1024 * 2,
inode: file_info, 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()), accessed: windows_time_to_unix_time(metadata.last_access_time()),
modified: windows_time_to_unix_time(metadata.last_write_time()), modified: windows_time_to_unix_time(metadata.last_write_time()),
}) })
@ -137,10 +139,24 @@ impl Stat {
} }
#[cfg(windows)] #[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)." // "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 { 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)] #[cfg(windows)]
@ -539,10 +555,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.value_name("WORD") .value_name("WORD")
.require_equals(true) .require_equals(true)
.min_values(0) .min_values(0)
.possible_values(&["atime", "access", "use", "ctime", "status", "birth", "creation"])
.help( .help(
"show time of the last modification of any file in the \ "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 \ 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( .arg(
@ -667,19 +684,22 @@ Try '{} --help' for more information.",
let secs = { let secs = {
match matches.value_of(options::TIME) { match matches.value_of(options::TIME) {
Some(s) => match s { Some(s) => match s {
"accessed" => stat.accessed, "ctime" | "status" => stat.modified,
"created" => stat.created, "access" | "atime" | "use" => stat.accessed,
"modified" => stat.modified, "birth" | "creation" => {
_ => { if let Some(time) = stat.created {
show_error!( time
"invalid argument 'modified' for '--time' } else {
Valid arguments are: show_error!(
- 'accessed', 'created', 'modified' "Invalid argument {} for --time.
Try '{} --help' for more information.", birth and creation arguments are not supported on this platform.",
NAME s
); );
return 1; return 1;
}
} }
// below should never happen as clap already restricts the values.
_ => unreachable!("Invalid field for --time"),
}, },
None => stat.modified, None => stat.modified,
} }

View file

@ -240,18 +240,37 @@ fn test_du_time() {
scene scene
.ccmd("touch") .ccmd("touch")
.arg("-a") .arg("-a")
.arg("-m")
.arg("-t") .arg("-t")
.arg("201505150000") .arg("201505150000")
.arg("date_test") .arg("date_test")
.succeeds(); .succeeds();
scene scene
.ucmd() .ccmd("touch")
.arg("--time") .arg("-m")
.arg("-t")
.arg("201606160000")
.arg("date_test") .arg("date_test")
.succeeds() .succeeds();
.stdout_only("0\t2015-05-15 00:00\tdate_test\n");
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"))] #[cfg(not(target_os = "windows"))]