mirror of
https://github.com/lsd-rs/lsd
synced 2024-11-10 06:14:19 +00:00
add access control indicators
fixes #347 fixes #515 Signed-off-by: Martin Matous <m@matous.dev>
This commit is contained in:
parent
f1254a6b0c
commit
3b6b343944
9 changed files with 143 additions and 5 deletions
|
@ -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
18
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"]}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
108
src/meta/access_control.rs
Normal 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))
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue