diff --git a/Cargo.lock b/Cargo.lock index 7c02383..c376a20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,12 +98,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lsd" -version = "0.3.1" +version = "0.3.2-pre" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", "term_grid 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "terminal_size 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 485505f..50f562a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ ansi_term = "0.11.0" clap = "2.32.0" failure = "0.1.3" lazy_static = "1.2.0" +libc = "0.2.44" term_grid = "0.1.7" terminal_size = "0.1.8" time = "0.1.40" diff --git a/src/formatter.rs b/src/formatter.rs index b139432..a1feca8 100644 --- a/src/formatter.rs +++ b/src/formatter.rs @@ -1,7 +1,6 @@ use color::{Colors, Elem, PrecomputedElems}; use icon; use meta::{Meta, Type}; -use std::os::unix::fs::PermissionsExt; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use time::Timespec; @@ -77,67 +76,13 @@ impl Formatter { pub fn format_permissions(&self, meta: &Meta) -> String { let mut res = String::with_capacity(11); - let mode = meta.metadata.permissions().mode(); - match meta.node_type { Type::File => res += PrecomputedElems[&Elem::File].as_str(), Type::Directory => res += PrecomputedElems[&Elem::Dir].as_str(), Type::SymLink(_) => res += PrecomputedElems[&Elem::SymLink].as_str(), } - // User Read Permisssions - match mode & 0o400 { - 0 => res += PrecomputedElems[&Elem::NoAccess].as_str(), - _ => res += PrecomputedElems[&Elem::Read].as_str(), - } - - // User Write Permisssions - match mode & 0o200 { - 0 => res += PrecomputedElems[&Elem::NoAccess].as_str(), - _ => res += PrecomputedElems[&Elem::Write].as_str(), - } - - // User Exec Permisssions - match mode & 0o100 { - 0 => res += PrecomputedElems[&Elem::NoAccess].as_str(), - _ => res += PrecomputedElems[&Elem::Exec].as_str(), - } - - // Group Read Permisssions - match mode & 0o040 { - 0 => res += PrecomputedElems[&Elem::NoAccess].as_str(), - _ => res += PrecomputedElems[&Elem::Read].as_str(), - } - - // Group Write Permisssions - match mode & 0o020 { - 0 => res += PrecomputedElems[&Elem::NoAccess].as_str(), - _ => res += PrecomputedElems[&Elem::Write].as_str(), - } - - // Group Exec Permisssions - match mode & 0o010 { - 0 => res += PrecomputedElems[&Elem::NoAccess].as_str(), - _ => res += PrecomputedElems[&Elem::Exec].as_str(), - } - - // Other Read Permisssions - match mode & 0o040 { - 0 => res += PrecomputedElems[&Elem::NoAccess].as_str(), - _ => res += PrecomputedElems[&Elem::Read].as_str(), - } - - // Other Write Permisssions - match mode & 0o020 { - 0 => res += PrecomputedElems[&Elem::NoAccess].as_str(), - _ => res += PrecomputedElems[&Elem::Write].as_str(), - } - - // Other Exec Permisssions - match mode & 0o010 { - 0 => res += PrecomputedElems[&Elem::NoAccess].as_str(), - _ => res += PrecomputedElems[&Elem::Exec].as_str(), - } + res += &meta.permissions.render(); res.to_string() } diff --git a/src/main.rs b/src/main.rs index ce8d98d..e330a54 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ extern crate clap; extern crate lazy_static; extern crate ansi_term; extern crate failure; +extern crate libc; extern crate term_grid; extern crate terminal_size; extern crate time; diff --git a/src/meta/mod.rs b/src/meta/mod.rs index 806f071..8549fc3 100644 --- a/src/meta/mod.rs +++ b/src/meta/mod.rs @@ -1,3 +1,4 @@ +use self::permissions::Permissions; use self::size::Size; use failure::*; use std::fs::{read_link, Metadata}; @@ -6,6 +7,7 @@ use std::os::unix::fs::MetadataExt; use std::path::{Path, PathBuf}; use users::{get_group_by_gid, get_user_by_uid}; +mod permissions; mod size; #[derive(Debug, Fail)] @@ -39,6 +41,7 @@ impl<'a> From<&'a Metadata> for Type { pub struct Meta { pub path: PathBuf, pub name: String, + pub permissions: Permissions, pub metadata: Metadata, pub group: String, pub user: String, @@ -118,6 +121,7 @@ impl Meta { Ok(Meta { size: Size::from(&meta), + permissions: Permissions::from(&meta), path: path.to_path_buf(), metadata: meta, name: String::from(name), diff --git a/src/meta/permissions.rs b/src/meta/permissions.rs new file mode 100644 index 0000000..51d612b --- /dev/null +++ b/src/meta/permissions.rs @@ -0,0 +1,112 @@ +use color::{Elem, PrecomputedElems}; +use std::fs::Metadata; +use std::os::unix::fs::PermissionsExt; + +#[derive(Debug)] +pub struct Permissions { + pub user_read: bool, + pub user_write: bool, + pub user_execute: bool, + + pub group_read: bool, + pub group_write: bool, + pub group_execute: bool, + + pub other_read: bool, + pub other_write: bool, + pub other_execute: bool, + + pub sticky: bool, + pub setgid: bool, + pub setuid: bool, +} + +impl<'a> From<&'a Metadata> for Permissions { + fn from(meta: &Metadata) -> Self { + let bits = meta.permissions().mode(); + let has_bit = |bit| bits & bit == bit; + + Permissions { + user_read: has_bit(modes::USER_READ), + user_write: has_bit(modes::USER_WRITE), + user_execute: has_bit(modes::USER_EXECUTE), + + group_read: has_bit(modes::GROUP_READ), + group_write: has_bit(modes::GROUP_WRITE), + group_execute: has_bit(modes::GROUP_EXECUTE), + + other_read: has_bit(modes::OTHER_READ), + other_write: has_bit(modes::OTHER_WRITE), + other_execute: has_bit(modes::OTHER_EXECUTE), + + sticky: has_bit(modes::STICKY), + setgid: has_bit(modes::SETGID), + setuid: has_bit(modes::SETUID), + } + } +} + +impl Permissions { + pub fn render(&self) -> String { + let mut res = String::with_capacity(11); + + res += &self.render_permission_set(self.user_read, self.user_write, self.user_execute); + res += &self.render_permission_set(self.group_read, self.group_write, self.group_execute); + res += &self.render_permission_set(self.other_read, self.other_write, self.other_execute); + + res + } + + fn render_permission_set(&self, read: bool, write: bool, exec: bool) -> String { + let mut res = String::with_capacity(3); + + // Read Permisssions + if read { + res += PrecomputedElems[&Elem::Read].as_str(); + } else { + res += PrecomputedElems[&Elem::NoAccess].as_str(); + } + + // Write Permisssions + if write { + res += PrecomputedElems[&Elem::Write].as_str(); + } else { + res += PrecomputedElems[&Elem::NoAccess].as_str(); + } + + // Exec Permisssions + if exec { + res += PrecomputedElems[&Elem::Exec].as_str(); + } else { + res += PrecomputedElems[&Elem::NoAccess].as_str(); + } + + res + } +} + +// More readable aliases for the permission bits exposed by libc. +#[allow(trivial_numeric_casts)] +mod modes { + use libc; + + pub type Mode = u32; + // The `libc::mode_t` type’s actual type varies, but the value returned + // from `metadata.permissions().mode()` is always `u32`. + + pub const USER_READ: Mode = libc::S_IRUSR as Mode; + pub const USER_WRITE: Mode = libc::S_IWUSR as Mode; + pub const USER_EXECUTE: Mode = libc::S_IXUSR as Mode; + + pub const GROUP_READ: Mode = libc::S_IRGRP as Mode; + pub const GROUP_WRITE: Mode = libc::S_IWGRP as Mode; + pub const GROUP_EXECUTE: Mode = libc::S_IXGRP as Mode; + + pub const OTHER_READ: Mode = libc::S_IROTH as Mode; + pub const OTHER_WRITE: Mode = libc::S_IWOTH as Mode; + pub const OTHER_EXECUTE: Mode = libc::S_IXOTH as Mode; + + pub const STICKY: Mode = libc::S_ISVTX as Mode; + pub const SETGID: Mode = libc::S_ISGID as Mode; + pub const SETUID: Mode = libc::S_ISUID as Mode; +}