From a636d08f8b5a478938ec282a240b7bf3dc46a7f3 Mon Sep 17 00:00:00 2001 From: ariasuni Date: Fri, 20 Dec 2019 05:15:43 +0100 Subject: [PATCH] Fix handling of potentially unsupported time metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Checking on a directory doesn’t tell us if supported elsewhere (some filesystems, like tmpfs, don’t support created time) - We want to be able to display a column even if some subfiles or subdirectories don’t support it So now if unsupported a time of zero is used, and displayed as `-` --- src/fs/file.rs | 50 +++++++++++-------------------------------- src/fs/mod.rs | 2 +- src/options/filter.rs | 20 ++--------------- src/options/view.rs | 18 ---------------- src/output/time.rs | 7 ++++++ 5 files changed, 22 insertions(+), 75 deletions(-) diff --git a/src/fs/file.rs b/src/fs/file.rs index 3a63aae..dc2e22a 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -328,7 +328,10 @@ impl<'dir> File<'dir> { /// This file’s last modified timestamp. pub fn modified_time(&self) -> Duration { - self.metadata.modified().unwrap().duration_since(UNIX_EPOCH).unwrap() + match self.metadata.modified() { + Ok(system_time) => system_time.duration_since(UNIX_EPOCH).unwrap(), + Err(_) => Duration::new(0, 0), + } } /// This file’s last changed timestamp. @@ -338,12 +341,18 @@ impl<'dir> File<'dir> { /// This file’s last accessed timestamp. pub fn accessed_time(&self) -> Duration { - self.metadata.accessed().unwrap().duration_since(UNIX_EPOCH).unwrap() + match self.metadata.accessed() { + Ok(system_time) => system_time.duration_since(UNIX_EPOCH).unwrap(), + Err(_) => Duration::new(0, 0), + } } /// This file’s created timestamp. pub fn created_time(&self) -> Duration { - self.metadata.created().unwrap().duration_since(UNIX_EPOCH).unwrap() + match self.metadata.created() { + Ok(system_time) => system_time.duration_since(UNIX_EPOCH).unwrap(), + Err(_) => Duration::new(0, 0), + } } /// This file’s ‘type’. @@ -460,41 +469,6 @@ impl<'dir> FileTarget<'dir> { } -pub enum PlatformMetadata { - ModifiedTime, - ChangedTime, - AccessedTime, - CreatedTime, -} - -impl PlatformMetadata { - pub fn check_supported(&self) -> Result<(), Misfire> { - use std::env::temp_dir; - let result = match self { - // 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(), - // We use the Unix API so we know it’s not available elsewhere - PlatformMetadata::ChangedTime => { - if cfg!(target_family = "unix") { - return Ok(()) - } else { - return Err(Misfire::Unsupported( - // for consistency, this error message similar to the one Rust - // use when created time is not available - "status modified time is not available on this platform currently".to_string())); - } - }, - }; - match result { - Ok(_) => Ok(()), - Err(err) => Err(Misfire::Unsupported(err.to_string())) - } - } -} - - /// More readable aliases for the permission bits exposed by libc. #[allow(trivial_numeric_casts)] mod modes { diff --git a/src/fs/mod.rs b/src/fs/mod.rs index f6ca48e..3275ccf 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -2,7 +2,7 @@ mod dir; pub use self::dir::{Dir, DotFilter}; mod file; -pub use self::file::{File, FileTarget, PlatformMetadata}; +pub use self::file::{File, FileTarget}; pub mod feature; pub mod fields; diff --git a/src/options/filter.rs b/src/options/filter.rs index ab9d9c2..d15bd92 100644 --- a/src/options/filter.rs +++ b/src/options/filter.rs @@ -1,6 +1,6 @@ //! Parsing the options for `FileFilter`. -use fs::{DotFilter, PlatformMetadata}; +use fs::DotFilter; use fs::filter::{FileFilter, SortField, SortCase, IgnorePatterns, GitIgnore}; use options::{flags, Misfire}; @@ -67,23 +67,7 @@ impl SortField { _ => return Err(Misfire::BadArgument(&flags::SORT, word.into())) }; - match SortField::to_platform_metadata(field) { - Some(m) => match m.check_supported() { - Ok(_) => Ok(field), - Err(misfire) => Err(misfire), - }, - None => Ok(field), - } - } - - fn to_platform_metadata(field: Self) -> Option { - match field { - SortField::ModifiedDate => Some(PlatformMetadata::ModifiedTime), - SortField::ChangedDate => Some(PlatformMetadata::ChangedTime), - SortField::AccessedDate => Some(PlatformMetadata::AccessedTime), - SortField::CreatedDate => Some(PlatformMetadata::CreatedTime), - _ => None - } + Ok(field) } } diff --git a/src/options/view.rs b/src/options/view.rs index 23e9a44..cff430d 100644 --- a/src/options/view.rs +++ b/src/options/view.rs @@ -6,7 +6,6 @@ use output::time::TimeFormat; use options::{flags, Misfire, Vars}; use options::parser::MatchedFlags; -use fs::PlatformMetadata; use fs::feature::xattr; @@ -344,17 +343,6 @@ impl TimeTypes { TimeTypes::default() }; - let mut fields = vec![]; - if time_types.modified { fields.push(PlatformMetadata::ModifiedTime); } - if time_types.changed { fields.push(PlatformMetadata::ChangedTime); } - if time_types.accessed { fields.push(PlatformMetadata::AccessedTime); } - if time_types.created { fields.push(PlatformMetadata::CreatedTime); } - - for field in fields { - if let Err(misfire) = field.check_supported() { - return Err(misfire); - } - } Ok(time_types) } } @@ -542,15 +530,9 @@ mod test { test!(time_a: TimeTypes <- ["-t", "acc"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: true, created: false })); // 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"))] test!(time_cr: TimeTypes <- ["--time=created"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: false, created: true })); - #[cfg(not(target_os = "linux"))] test!(t_cr: TimeTypes <- ["-tcr"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: false, created: true })); // Multiples diff --git a/src/output/time.rs b/src/output/time.rs index cec1f34..023bc77 100644 --- a/src/output/time.rs +++ b/src/output/time.rs @@ -129,6 +129,9 @@ impl DefaultFormat { #[allow(trivial_numeric_casts)] fn format_local(&self, time: Duration) -> String { + if time.as_nanos() == 0 { + return "-".to_string(); + } let date = LocalDateTime::at(time.as_secs() as i64); if self.is_recent(date) { @@ -141,6 +144,10 @@ impl DefaultFormat { #[allow(trivial_numeric_casts)] fn format_zoned(&self, time: Duration, zone: &TimeZone) -> String { + if time.as_nanos() == 0 { + return "-".to_string(); + } + let date = zone.to_zoned(LocalDateTime::at(time.as_secs() as i64)); if self.is_recent(date) {