mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-11-26 13:56:27 +00:00
Fix handling of potentially unsupported time metadata
- 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 `-`
This commit is contained in:
parent
89c861f24d
commit
a636d08f8b
@ -328,7 +328,10 @@ impl<'dir> File<'dir> {
|
|||||||
|
|
||||||
/// This file’s last modified timestamp.
|
/// This file’s last modified timestamp.
|
||||||
pub fn modified_time(&self) -> Duration {
|
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.
|
/// This file’s last changed timestamp.
|
||||||
@ -338,12 +341,18 @@ impl<'dir> File<'dir> {
|
|||||||
|
|
||||||
/// This file’s last accessed timestamp.
|
/// This file’s last accessed timestamp.
|
||||||
pub fn accessed_time(&self) -> Duration {
|
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.
|
/// This file’s created timestamp.
|
||||||
pub fn created_time(&self) -> Duration {
|
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’.
|
/// 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.
|
/// More readable aliases for the permission bits exposed by libc.
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
mod modes {
|
mod modes {
|
||||||
|
@ -2,7 +2,7 @@ mod dir;
|
|||||||
pub use self::dir::{Dir, DotFilter};
|
pub use self::dir::{Dir, DotFilter};
|
||||||
|
|
||||||
mod file;
|
mod file;
|
||||||
pub use self::file::{File, FileTarget, PlatformMetadata};
|
pub use self::file::{File, FileTarget};
|
||||||
|
|
||||||
pub mod feature;
|
pub mod feature;
|
||||||
pub mod fields;
|
pub mod fields;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Parsing the options for `FileFilter`.
|
//! Parsing the options for `FileFilter`.
|
||||||
|
|
||||||
use fs::{DotFilter, PlatformMetadata};
|
use fs::DotFilter;
|
||||||
use fs::filter::{FileFilter, SortField, SortCase, IgnorePatterns, GitIgnore};
|
use fs::filter::{FileFilter, SortField, SortCase, IgnorePatterns, GitIgnore};
|
||||||
|
|
||||||
use options::{flags, Misfire};
|
use options::{flags, Misfire};
|
||||||
@ -67,23 +67,7 @@ impl SortField {
|
|||||||
_ => return Err(Misfire::BadArgument(&flags::SORT, word.into()))
|
_ => return Err(Misfire::BadArgument(&flags::SORT, word.into()))
|
||||||
};
|
};
|
||||||
|
|
||||||
match SortField::to_platform_metadata(field) {
|
Ok(field)
|
||||||
Some(m) => match m.check_supported() {
|
|
||||||
Ok(_) => Ok(field),
|
|
||||||
Err(misfire) => Err(misfire),
|
|
||||||
},
|
|
||||||
None => Ok(field),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_platform_metadata(field: Self) -> Option<PlatformMetadata> {
|
|
||||||
match field {
|
|
||||||
SortField::ModifiedDate => Some(PlatformMetadata::ModifiedTime),
|
|
||||||
SortField::ChangedDate => Some(PlatformMetadata::ChangedTime),
|
|
||||||
SortField::AccessedDate => Some(PlatformMetadata::AccessedTime),
|
|
||||||
SortField::CreatedDate => Some(PlatformMetadata::CreatedTime),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ use output::time::TimeFormat;
|
|||||||
use options::{flags, Misfire, Vars};
|
use options::{flags, Misfire, Vars};
|
||||||
use options::parser::MatchedFlags;
|
use options::parser::MatchedFlags;
|
||||||
|
|
||||||
use fs::PlatformMetadata;
|
|
||||||
use fs::feature::xattr;
|
use fs::feature::xattr;
|
||||||
|
|
||||||
|
|
||||||
@ -344,17 +343,6 @@ impl TimeTypes {
|
|||||||
TimeTypes::default()
|
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)
|
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 }));
|
test!(time_a: TimeTypes <- ["-t", "acc"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: true, created: false }));
|
||||||
|
|
||||||
// Created
|
// Created
|
||||||
#[cfg(not(target_os = "linux"))]
|
|
||||||
test!(cr: TimeTypes <- ["--created"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: false, created: true }));
|
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 }));
|
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 }));
|
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 }));
|
test!(t_cr: TimeTypes <- ["-tcr"]; Both => Ok(TimeTypes { modified: false, changed: false, accessed: false, created: true }));
|
||||||
|
|
||||||
// Multiples
|
// Multiples
|
||||||
|
@ -129,6 +129,9 @@ impl DefaultFormat {
|
|||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
fn format_local(&self, time: Duration) -> String {
|
fn format_local(&self, time: Duration) -> String {
|
||||||
|
if time.as_nanos() == 0 {
|
||||||
|
return "-".to_string();
|
||||||
|
}
|
||||||
let date = LocalDateTime::at(time.as_secs() as i64);
|
let date = LocalDateTime::at(time.as_secs() as i64);
|
||||||
|
|
||||||
if self.is_recent(date) {
|
if self.is_recent(date) {
|
||||||
@ -141,6 +144,10 @@ impl DefaultFormat {
|
|||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
fn format_zoned(&self, time: Duration, zone: &TimeZone) -> String {
|
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));
|
let date = zone.to_zoned(LocalDateTime::at(time.as_secs() as i64));
|
||||||
|
|
||||||
if self.is_recent(date) {
|
if self.is_recent(date) {
|
||||||
|
Loading…
Reference in New Issue
Block a user