From bb705371f8465f82b3c9b52bea0f28fe245c5545 Mon Sep 17 00:00:00 2001 From: ariasuni Date: Thu, 3 Oct 2019 02:12:14 +0200 Subject: [PATCH 1/4] Use statx to get creation time of files on Linux --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + src/fs/file.rs | 38 +++++++++++++++++++++++++++++++++++--- src/options/view.rs | 2 -- 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47297a5f..6fb92908 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,6 +95,7 @@ dependencies = [ "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "statx-sys 0.2.1 (git+https://github.com/ariasuni/statx-sys?branch=fix-typo)", "term_grid 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -336,6 +337,14 @@ name = "smallvec" version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "statx-sys" +version = "0.2.1" +source = "git+https://github.com/ariasuni/statx-sys?branch=fix-typo#accd2e991df0ca2c2b741141e564c6bad88ec501" +dependencies = [ + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "term_grid" version = "0.1.7" @@ -532,6 +541,7 @@ dependencies = [ "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" +"checksum statx-sys 0.2.1 (git+https://github.com/ariasuni/statx-sys?branch=fix-typo)" = "" "checksum term_grid 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "230d3e804faaed5a39b08319efb797783df2fd9671b39b7596490cb486d702cf" "checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" diff --git a/Cargo.toml b/Cargo.toml index e685aebc..1a6c827c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ natord = "1.0.9" num_cpus = "1.10.0" number_prefix = "0.3.0" scoped_threadpool = "0.1.9" +statx-sys = { git = "https://github.com/ariasuni/statx-sys", branch = "fix-typo" } term_grid = "0.1.7" term_size = "0.3.1" unicode-width = "0.1.5" diff --git a/src/fs/file.rs b/src/fs/file.rs index 3a63aaeb..9d709a20 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -3,6 +3,7 @@ use std::fs::{self, metadata}; use std::io::Error as IOError; use std::io::Result as IOResult; +use std::os::unix::ffi::OsStrExt; use std::os::unix::fs::{MetadataExt, PermissionsExt, FileTypeExt}; use std::path::{Path, PathBuf}; use std::time::{UNIX_EPOCH, Duration}; @@ -11,6 +12,9 @@ use fs::dir::Dir; use fs::fields as f; use options::Misfire; +extern crate statx_sys; +use self::statx_sys::{statx, STATX_BTIME}; + /// A **File** is a wrapper around one of Rust's Path objects, along with /// associated data about the file. @@ -343,7 +347,12 @@ impl<'dir> File<'dir> { /// This file’s created timestamp. pub fn created_time(&self) -> Duration { - self.metadata.created().unwrap().duration_since(UNIX_EPOCH).unwrap() + if cfg!(target_os = "linux") { + let statx_data = statx_creation_time(&self.path).unwrap(); + Duration::new(statx_data.stx_btime.tv_sec as u64, statx_data.stx_btime.tv_nsec) + } else { + self.metadata.created().unwrap().duration_since(UNIX_EPOCH).unwrap() + } } /// This file’s ‘type’. @@ -474,11 +483,19 @@ impl PlatformMetadata { // Call the functions that return a Result to see if it works PlatformMetadata::AccessedTime => metadata(temp_dir()).unwrap().accessed(), PlatformMetadata::ModifiedTime => metadata(temp_dir()).unwrap().modified(), - PlatformMetadata::CreatedTime => metadata(temp_dir()).unwrap().created(), + PlatformMetadata::CreatedTime if cfg!(target_os = "linux") => { + if statx_creation_time(&temp_dir()).is_some() { + return Ok(()); + } + return Err(Misfire::Unsupported( + "creation time is not available on this platform currently \ + (needs Linux >= 4.11)".to_string())); + }, + PlatformMetadata::CreatedTime => metadata(temp_dir()).unwrap().created(), // We use the Unix API so we know it’s not available elsewhere PlatformMetadata::ChangedTime => { if cfg!(target_family = "unix") { - return Ok(()) + return Ok(()); } else { return Err(Misfire::Unsupported( // for consistency, this error message similar to the one Rust @@ -494,6 +511,21 @@ impl PlatformMetadata { } } +fn statx_creation_time(path: &PathBuf) -> Option { + let mut statx_data: statx = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; + let path_name = std::ffi::CString::new(path + .canonicalize() + .unwrap() + .as_os_str() + .as_bytes()).unwrap(); + let result = unsafe { statx(0, path_name.as_ptr(), 0, STATX_BTIME, &mut statx_data) }; + if result == 0 { + Some(statx_data) + } else { + None + } +} + /// More readable aliases for the permission bits exposed by libc. #[allow(trivial_numeric_casts)] diff --git a/src/options/view.rs b/src/options/view.rs index 23e9a444..4e1d8849 100644 --- a/src/options/view.rs +++ b/src/options/view.rs @@ -544,8 +544,6 @@ mod test { // Created #[cfg(not(target_os = "linux"))] test!(cr: TimeTypes <- ["--created"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: false, created: true })); - #[cfg(target_os = "linux")] - test!(cr: TimeTypes <- ["--created"]; Both => err Misfire::Unsupported("creation time is not available on this platform currently".to_string())); #[cfg(not(target_os = "linux"))] test!(c: TimeTypes <- ["-U"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: false, created: true })); #[cfg(not(target_os = "linux"))] From 7de520362aad77375ff7442a83546c6852cbe7ab Mon Sep 17 00:00:00 2001 From: ariasuni Date: Thu, 3 Oct 2019 14:59:39 +0200 Subject: [PATCH 2/4] Bump libc version to use it instead of adding statx-sys --- Cargo.lock | 38 ++++++++++++++------------------------ Cargo.toml | 3 +-- src/fs/file.rs | 4 ++-- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6fb92908..c821c4f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,7 +21,7 @@ name = "atty" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -58,7 +58,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iso8601 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "locale 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "pad 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -88,14 +88,13 @@ dependencies = [ "git2 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "locale 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "natord 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "statx-sys 0.2.1 (git+https://github.com/ariasuni/statx-sys?branch=fix-typo)", "term_grid 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -109,7 +108,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "libgit2-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.47 (registry+https://github.com/rust-lang/crates.io-index)", @@ -163,7 +162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.51" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -172,7 +171,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -183,7 +182,7 @@ version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -193,7 +192,7 @@ name = "locale" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -242,7 +241,7 @@ name = "num_cpus" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -265,7 +264,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-src 111.3.0+1.1.1c (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -337,14 +336,6 @@ name = "smallvec" version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "statx-sys" -version = "0.2.1" -source = "git+https://github.com/ariasuni/statx-sys?branch=fix-typo#accd2e991df0ca2c2b741141e564c6bad88ec501" -dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "term_grid" version = "0.1.7" @@ -359,7 +350,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -376,7 +367,7 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -430,7 +421,7 @@ name = "users" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -516,7 +507,7 @@ dependencies = [ "checksum iso8601 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "11dc464f8c6f17595d191447c9c6559298b2d023d6f846a4a23ac7ea3c46c477" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum libgit2-sys 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "941a41e23f77323b8c9d2ee118aec9ee39dfc176078c18b4757d3bad049d9ff7" "checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" "checksum locale 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5fdbe492a9c0238da900a1165c42fc5067161ce292678a6fe80921f30fe307fd" @@ -541,7 +532,6 @@ dependencies = [ "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" -"checksum statx-sys 0.2.1 (git+https://github.com/ariasuni/statx-sys?branch=fix-typo)" = "" "checksum term_grid 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "230d3e804faaed5a39b08319efb797783df2fd9671b39b7596490cb486d702cf" "checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" diff --git a/Cargo.toml b/Cargo.toml index 1a6c827c..6663a18a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,14 +32,13 @@ datetime = "0.4.7" env_logger = "0.6.1" glob = "0.3.0" lazy_static = "1.3.0" -libc = "0.2.51" +libc = "^0.2.57" locale = "0.2.2" log = "0.4.6" natord = "1.0.9" num_cpus = "1.10.0" number_prefix = "0.3.0" scoped_threadpool = "0.1.9" -statx-sys = { git = "https://github.com/ariasuni/statx-sys", branch = "fix-typo" } term_grid = "0.1.7" term_size = "0.3.1" unicode-width = "0.1.5" diff --git a/src/fs/file.rs b/src/fs/file.rs index 9d709a20..a0cefcaa 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -12,8 +12,8 @@ use fs::dir::Dir; use fs::fields as f; use options::Misfire; -extern crate statx_sys; -use self::statx_sys::{statx, STATX_BTIME}; +extern crate libc; +use libc::{statx, STATX_BTIME}; /// A **File** is a wrapper around one of Rust's Path objects, along with From be1be2b29b4fb295782651c3fd9880d2880f8320 Mon Sep 17 00:00:00 2001 From: ariasuni Date: Thu, 3 Oct 2019 15:05:39 +0200 Subject: [PATCH 3/4] Use syscall so we can call statx without glibc or with glibc < 2.28 --- src/fs/file.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fs/file.rs b/src/fs/file.rs index a0cefcaa..13d8df92 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -13,7 +13,7 @@ use fs::fields as f; use options::Misfire; extern crate libc; -use libc::{statx, STATX_BTIME}; +use libc::{syscall, SYS_statx, statx, STATX_BTIME}; /// A **File** is a wrapper around one of Rust's Path objects, along with @@ -518,7 +518,7 @@ fn statx_creation_time(path: &PathBuf) -> Option { .unwrap() .as_os_str() .as_bytes()).unwrap(); - let result = unsafe { statx(0, path_name.as_ptr(), 0, STATX_BTIME, &mut statx_data) }; + let result = unsafe { syscall(SYS_statx, 0, path_name.as_ptr(), 0, STATX_BTIME, &mut statx_data) }; if result == 0 { Some(statx_data) } else { From 3fe808951a4aab58d8fa9edb498a14966537c7a9 Mon Sep 17 00:00:00 2001 From: ariasuni Date: Thu, 3 Oct 2019 16:52:34 +0200 Subject: [PATCH 4/4] Check if seconds < 0 before casting to u64, inspired by #557 --- src/fs/file.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/fs/file.rs b/src/fs/file.rs index 13d8df92..5d866739 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -349,7 +349,11 @@ impl<'dir> File<'dir> { pub fn created_time(&self) -> Duration { if cfg!(target_os = "linux") { let statx_data = statx_creation_time(&self.path).unwrap(); - Duration::new(statx_data.stx_btime.tv_sec as u64, statx_data.stx_btime.tv_nsec) + if statx_data.stx_btime.tv_sec < 0 { + Duration::from_secs(0) + } else { + Duration::new(statx_data.stx_btime.tv_sec as u64, statx_data.stx_btime.tv_nsec) + } } else { self.metadata.created().unwrap().duration_since(UNIX_EPOCH).unwrap() }