From eabfa2de54e1a589e8dc68af24a8b447b274a2f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20R=C3=B6jder=20Delnavaz?= Date: Sat, 29 Feb 2020 02:33:52 +0100 Subject: [PATCH] Let `ls` ignore permission errors (#1435) * Create a function to create an empty directory entry * Print an empty directory entry if permission is denied * Fix rustfmt whitespace issues. * Made metadata optional for `dir_entry_dict`. Removed `empty_dir_entry_dict` as its not needed anymore. --- src/data/files.rs | 127 +++++++++++++++++++++------------- src/shell/filesystem_shell.rs | 14 +++- 2 files changed, 92 insertions(+), 49 deletions(-) diff --git a/src/data/files.rs b/src/data/files.rs index 14581e3e4..3b69c4f09 100644 --- a/src/data/files.rs +++ b/src/data/files.rs @@ -4,7 +4,7 @@ use nu_protocol::{TaggedDictBuilder, UntaggedValue, Value}; pub(crate) fn dir_entry_dict( filename: &std::path::Path, - metadata: &std::fs::Metadata, + metadata: Option<&std::fs::Metadata>, tag: impl Into, full: bool, name_only: bool, @@ -28,77 +28,110 @@ pub(crate) fn dir_entry_dict( dict.insert_untagged("name", UntaggedValue::string(name)); - if metadata.is_dir() { - dict.insert_untagged("type", UntaggedValue::string("Dir")); - } else if metadata.is_file() { - dict.insert_untagged("type", UntaggedValue::string("File")); + if let Some(md) = metadata { + if md.is_dir() { + dict.insert_untagged("type", UntaggedValue::string("Dir")); + } else if md.is_file() { + dict.insert_untagged("type", UntaggedValue::string("File")); + } else { + dict.insert_untagged("type", UntaggedValue::string("Symlink")); + } } else { - dict.insert_untagged("type", UntaggedValue::string("Symlink")); - }; + dict.insert_untagged("type", UntaggedValue::nothing()); + } if full || with_symlink_targets { - if metadata.is_dir() || metadata.is_file() { - dict.insert_untagged("target", UntaggedValue::nothing()); - } else if let Ok(path_to_link) = filename.read_link() { - dict.insert_untagged( - "target", - UntaggedValue::string(path_to_link.to_string_lossy()), - ); + if let Some(md) = metadata { + if md.is_dir() || md.is_file() { + dict.insert_untagged("target", UntaggedValue::nothing()); + } else if let Ok(path_to_link) = filename.read_link() { + dict.insert_untagged( + "target", + UntaggedValue::string(path_to_link.to_string_lossy()), + ); + } else { + dict.insert_untagged( + "target", + UntaggedValue::string("Could not obtain target file's path"), + ); + } } else { - dict.insert_untagged( - "target", - UntaggedValue::string("Could not obtain target file's path"), - ); + dict.insert_untagged("target", UntaggedValue::nothing()); } } if full { - dict.insert_untagged( - "readonly", - UntaggedValue::boolean(metadata.permissions().readonly()), - ); - - #[cfg(unix)] - { - use std::os::unix::fs::MetadataExt; - use std::os::unix::fs::PermissionsExt; - let mode = metadata.permissions().mode(); + if let Some(md) = metadata { dict.insert_untagged( - "mode", - UntaggedValue::string(umask::Mode::from(mode).to_string()), + "readonly", + UntaggedValue::boolean(md.permissions().readonly()), ); - if let Some(user) = users::get_user_by_uid(metadata.uid()) { - dict.insert_untagged("uid", UntaggedValue::string(user.name().to_string_lossy())); - } - - if let Some(group) = users::get_group_by_gid(metadata.gid()) { + #[cfg(unix)] + { + use std::os::unix::fs::MetadataExt; + use std::os::unix::fs::PermissionsExt; + let mode = md.permissions().mode(); dict.insert_untagged( - "group", - UntaggedValue::string(group.name().to_string_lossy()), + "mode", + UntaggedValue::string(umask::Mode::from(mode).to_string()), ); + + if let Some(user) = users::get_user_by_uid(md.uid()) { + dict.insert_untagged( + "uid", + UntaggedValue::string(user.name().to_string_lossy()), + ); + } + + if let Some(group) = users::get_group_by_gid(md.gid()) { + dict.insert_untagged( + "group", + UntaggedValue::string(group.name().to_string_lossy()), + ); + } + } + } else { + dict.insert_untagged("readonly", UntaggedValue::nothing()); + + #[cfg(unix)] + { + dict.insert_untagged("mode", UntaggedValue::nothing()); } } } - if metadata.is_file() { - dict.insert_untagged("size", UntaggedValue::bytes(metadata.len() as u64)); + if let Some(md) = metadata { + if md.is_file() { + dict.insert_untagged("size", UntaggedValue::bytes(md.len() as u64)); + } else { + dict.insert_untagged("size", UntaggedValue::nothing()); + } } else { dict.insert_untagged("size", UntaggedValue::nothing()); } - if full { - if let Ok(c) = metadata.created() { - dict.insert_untagged("created", UntaggedValue::system_date(c)); + if let Some(md) = metadata { + if full { + if let Ok(c) = md.created() { + dict.insert_untagged("created", UntaggedValue::system_date(c)); + } + + if let Ok(a) = md.accessed() { + dict.insert_untagged("accessed", UntaggedValue::system_date(a)); + } } - if let Ok(a) = metadata.accessed() { - dict.insert_untagged("accessed", UntaggedValue::system_date(a)); + if let Ok(m) = md.modified() { + dict.insert_untagged("modified", UntaggedValue::system_date(m)); + } + } else { + if full { + dict.insert_untagged("created", UntaggedValue::nothing()); + dict.insert_untagged("accessed", UntaggedValue::nothing()); } - } - if let Ok(m) = metadata.modified() { - dict.insert_untagged("modified", UntaggedValue::system_date(m)); + dict.insert_untagged("modified", UntaggedValue::nothing()); } Ok(dict.into_value()) diff --git a/src/shell/filesystem_shell.rs b/src/shell/filesystem_shell.rs index de2480750..5fb4d64d5 100644 --- a/src/shell/filesystem_shell.rs +++ b/src/shell/filesystem_shell.rs @@ -142,12 +142,22 @@ impl Shell for FilesystemShell { match path { Ok(p) => match std::fs::symlink_metadata(&p) { Ok(m) => { - match dir_entry_dict(&p, &m, name_tag.clone(), full, short_names, with_symlink_targets) { + match dir_entry_dict(&p, Some(&m), name_tag.clone(), full, short_names, with_symlink_targets) { Ok(d) => yield ReturnSuccess::value(d), Err(e) => yield Err(e) } } - Err(e) => yield Err(ShellError::from(e)) + Err(e) => { + match e.kind() { + PermissionDenied => { + match dir_entry_dict(&p, None, name_tag.clone(), full, short_names, with_symlink_targets) { + Ok(d) => yield ReturnSuccess::value(d), + Err(e) => yield Err(e) + } + }, + _ => yield Err(ShellError::from(e)) + } + } } Err(e) => yield Err(e.into_error().into()), }