add access control indicators

fixes #347
fixes #515

Signed-off-by: Martin Matous <m@matous.dev>
This commit is contained in:
Martin Matous 2022-03-15 05:13:52 +01:00 committed by Abin Simon
parent f1254a6b0c
commit 3b6b343944
9 changed files with 143 additions and 5 deletions

View file

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add support for `--no-sort` `-U` from [MichaelAug](https://github.com/MichaelAug)
- Add `--group-directories-first` as an alias for `--group-dirs=first` to improve compatibility with `coreutils/ls`
- Add `--permission` flag to choose permission formatting (rwx, octal) from [meain](https://github.com/meain)
- Display MAC and ACL indicators
### Fixed
- Support non-bold bright colors [#248](https://github.com/Peltoche/lsd/issues/248) from [meain](https://github.com/meain)
- Don't automatically dereference symlinks in tree/recursive [#637](https://github.com/Peltoche/lsd/issues/637) from [meain](https://github.com/meain)

18
Cargo.lock generated
View file

@ -364,9 +364,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "lock_api"
version = "0.4.6"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
dependencies = [
"scopeguard",
]
@ -417,6 +417,7 @@ dependencies = [
"version_check",
"wild",
"winapi",
"xattr",
"xdg",
"yaml-rust",
]
@ -740,9 +741,9 @@ dependencies = [
[[package]]
name = "signal-hook"
version = "0.3.13"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
checksum = "470c5a6397076fae0094aaf06a08e6ba6f37acb77d3b1b91ea92b4d6c8650c39"
dependencies = [
"libc",
"signal-hook-registry",
@ -969,6 +970,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xattr"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c"
dependencies = [
"libc",
]
[[package]]
name = "xdg"
version = "2.1.0"

View file

@ -40,6 +40,7 @@ serde_yaml = "0.8"
[target.'cfg(unix)'.dependencies]
users = "0.11.*"
xattr = "0.2.*"
[target.'cfg(windows)'.dependencies]
winapi = {version = "0.3.*", features = ["aclapi", "accctrl", "winnt", "winerror", "securitybaseapi", "winbase"]}

View file

@ -252,6 +252,8 @@ permission:
exec-sticky: 5
no-access: 245
octal: 6
acl: dark_cyan
security-label: white
date:
hour-old: 40
day-old: 42
@ -348,7 +350,7 @@ Workaround for Konsole: Edit the config file (or [create it](#config-file-loc
icons:
separator: " "
```
This is a known issue in a few terminal emulator. Try using a different terminal emulator like. [Alacritty](https://github.com/alacritty/alacritty) and [Kitty](https://github.com/kovidgoyal/kitty) are really good alternatives. You might also want to check if your font is responsible for causing this.
To verify this, try running lsd with icons disabled and if it still does not have the first character, then this is an lsd bug:

View file

@ -36,6 +36,8 @@ pub enum Elem {
ExecSticky,
NoAccess,
Octal,
Acl,
SecurityLabel,
/// Last Time Modified
DayOld,
@ -104,6 +106,8 @@ impl Elem {
Elem::ExecSticky => theme.permission.exec_sticky,
Elem::NoAccess => theme.permission.no_access,
Elem::Octal => theme.permission.octal,
Elem::Acl => theme.permission.acl,
Elem::SecurityLabel => theme.permission.security_label,
Elem::DayOld => theme.date.day_old,
Elem::HourOld => theme.date.hour_old,
@ -343,6 +347,8 @@ mod elem {
exec_sticky: Color::Magenta,
no_access: Color::AnsiValue(245), // Grey
octal: Color::AnsiValue(6),
acl: Color::DarkCyan,
security_label: Color::White,
},
file_type: theme::FileType {
file: theme::File {

View file

@ -39,6 +39,8 @@ pub struct Permission {
pub exec_sticky: Color,
pub no_access: Color,
pub octal: Color,
pub acl: Color,
pub security_label: Color,
}
#[derive(Debug, Deserialize, PartialEq)]
@ -134,6 +136,8 @@ impl Default for Permission {
exec_sticky: Color::AnsiValue(5),
no_access: Color::AnsiValue(245), // Grey
octal: Color::AnsiValue(6),
acl: Color::DarkCyan,
security_label: Color::White,
}
}
}

View file

@ -271,6 +271,7 @@ fn get_output<'a>(
block_vec.extend(vec![
meta.file_type.render(colors),
meta.permissions.render(colors, flags),
meta.access_control.render_method(colors),
]);
}
Block::User => block_vec.push(meta.owner.render_user(colors)),

108
src/meta/access_control.rs Normal file
View file

@ -0,0 +1,108 @@
use crate::color::{ColoredString, Colors, Elem};
use std::path::Path;
#[derive(Clone, Debug)]
pub struct AccessControl {
has_acl: bool,
selinux_label: String,
smack_label: String,
}
impl AccessControl {
#[cfg(not(unix))]
pub fn for_path(_: &Path) -> Self {
Self::from_data(false, &[], &[])
}
#[cfg(unix)]
pub fn for_path(path: &Path) -> Self {
let has_acl = !xattr::get(path, Method::Acl.name())
.unwrap_or_default()
.unwrap_or_default()
.is_empty();
let selinux_label = xattr::get(path, Method::Selinux.name())
.unwrap_or_default()
.unwrap_or_default();
let smack_label = xattr::get(path, Method::Smack.name())
.unwrap_or_default()
.unwrap_or_default();
Self::from_data(has_acl, &selinux_label, &smack_label)
}
fn from_data(has_acl: bool, selinux_label: &[u8], smack_label: &[u8]) -> Self {
let selinux_label = String::from_utf8_lossy(selinux_label).to_string();
let smack_label = String::from_utf8_lossy(smack_label).to_string();
Self {
has_acl,
selinux_label,
smack_label,
}
}
pub fn render_method(&self, colors: &Colors) -> ColoredString {
if self.has_acl {
colors.colorize(String::from("+"), &Elem::Acl)
} else if !self.selinux_label.is_empty() || !self.smack_label.is_empty() {
colors.colorize(String::from("."), &Elem::SecurityLabel)
} else {
colors.colorize(String::from(""), &Elem::Acl)
}
}
}
#[cfg(unix)]
enum Method {
Acl,
Selinux,
Smack,
}
#[cfg(unix)]
impl Method {
fn name(&self) -> &'static str {
match self {
Method::Acl => "system.posix_acl_access",
Method::Selinux => "security.selinux",
Method::Smack => "security.SMACK64",
}
}
}
#[cfg(test)]
mod test {
use super::AccessControl;
use crate::color::{Colors, ThemeOption};
use crossterm::style::{Color, Stylize};
#[test]
fn test_acl_only_indicator() {
// actual file would collide with proper AC data, no permission to scrub those
let access_control = AccessControl::from_data(true, &[], &[]);
assert_eq!(
String::from("+").with(Color::DarkCyan),
access_control.render_method(&Colors::new(ThemeOption::Default))
);
}
#[test]
fn test_smack_only_indicator() {
let access_control = AccessControl::from_data(false, &[], &[b'a']);
assert_eq!(
String::from(".").with(Color::White),
access_control.render_method(&Colors::new(ThemeOption::Default))
);
}
#[test]
fn test_acl_and_selinux_indicator() {
let access_control = AccessControl::from_data(true, &[b'a'], &[]);
assert_eq!(
String::from("+").with(Color::DarkCyan),
access_control.render_method(&Colors::new(ThemeOption::Default))
);
}
}

View file

@ -1,3 +1,4 @@
mod access_control;
mod date;
mod filetype;
mod indicator;
@ -12,6 +13,7 @@ mod symlink;
#[cfg(windows)]
mod windows_utils;
pub use self::access_control::AccessControl;
pub use self::date::Date;
pub use self::filetype::FileType;
pub use self::indicator::Indicator;
@ -44,6 +46,7 @@ pub struct Meta {
pub inode: INode,
pub links: Links,
pub content: Option<Vec<Meta>>,
pub access_control: AccessControl,
}
impl Meta {
@ -231,6 +234,7 @@ impl Meta {
#[cfg(windows)]
let (owner, permissions) = windows_utils::get_file_data(path)?;
let access_control = AccessControl::for_path(path);
let file_type = FileType::new(&metadata, symlink_meta.as_ref(), &permissions);
let name = Name::new(path, file_type);
let inode = INode::from(&metadata);
@ -249,6 +253,7 @@ impl Meta {
name,
file_type,
content: None,
access_control: access_control,
})
}
}