Skip to content

Commit c1b9a0d

Browse files
show @ if extended attributes are present
1 parent 8937c47 commit c1b9a0d

1 file changed

Lines changed: 44 additions & 9 deletions

File tree

src/meta/access_control.rs

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ use std::path::Path;
44
#[derive(Clone, Debug)]
55
pub struct AccessControl {
66
has_acl: bool,
7+
has_xattr: bool,
78
selinux_context: String,
89
smack_context: String,
910
}
1011

1112
impl AccessControl {
1213
#[cfg(not(unix))]
1314
pub fn for_path(_: &Path) -> Self {
14-
Self::from_data(false, &[], &[])
15+
Self::from_data(false, false, &[], &[])
1516
}
1617

1718
#[cfg(unix)]
@@ -27,14 +28,27 @@ impl AccessControl {
2728
.unwrap_or_default()
2829
.unwrap_or_default();
2930

30-
Self::from_data(has_acl, &selinux_context, &smack_context)
31+
let has_xattr = has_acl
32+
|| !selinux_context.is_empty()
33+
|| !smack_context.is_empty()
34+
|| xattr::list(path)
35+
.map(|x| x.into_iter().count() > 0)
36+
.unwrap_or(false);
37+
38+
Self::from_data(has_acl, has_xattr, &selinux_context, &smack_context)
3139
}
3240

33-
fn from_data(has_acl: bool, selinux_context: &[u8], smack_context: &[u8]) -> Self {
41+
fn from_data(
42+
has_acl: bool,
43+
has_xattr: bool,
44+
selinux_context: &[u8],
45+
smack_context: &[u8],
46+
) -> Self {
3447
let selinux_context = String::from_utf8_lossy(selinux_context).to_string();
3548
let smack_context = String::from_utf8_lossy(smack_context).to_string();
3649
Self {
3750
has_acl,
51+
has_xattr,
3852
selinux_context,
3953
smack_context,
4054
}
@@ -43,6 +57,8 @@ impl AccessControl {
4357
pub fn render_method(&self, colors: &Colors) -> ColoredString {
4458
if self.has_acl {
4559
colors.colorize('+', &Elem::Acl)
60+
} else if self.has_xattr {
61+
colors.colorize('@', &Elem::Acl)
4662
} else if !self.selinux_context.is_empty() || !self.smack_context.is_empty() {
4763
colors.colorize('.', &Elem::Context)
4864
} else {
@@ -92,17 +108,36 @@ mod test {
92108
#[test]
93109
fn test_acl_only_indicator() {
94110
// actual file would collide with proper AC data, no permission to scrub those
95-
let access_control = AccessControl::from_data(true, &[], &[]);
111+
let access_control = AccessControl::from_data(true, false, &[], &[]);
96112

97113
assert_eq!(
98114
String::from("+").with(Color::DarkCyan),
99115
access_control.render_method(&Colors::new(ThemeOption::Default))
100116
);
101117
}
102118

119+
#[test]
120+
fn test_extended_attr_indicator() {
121+
let access_control = AccessControl::from_data(false, true, &[], &[]);
122+
123+
assert_eq!(
124+
String::from("@").with(Color::DarkCyan),
125+
access_control.render_method(&Colors::new(ThemeOption::Default))
126+
);
127+
}
128+
129+
#[test]
130+
fn test_extended_attr_with_acl_indicator() {
131+
let access_control = AccessControl::from_data(true, true, &[], &[]);
132+
133+
assert_eq!(
134+
String::from("+").with(Color::DarkCyan),
135+
access_control.render_method(&Colors::new(ThemeOption::Default))
136+
);
137+
}
103138
#[test]
104139
fn test_smack_only_indicator() {
105-
let access_control = AccessControl::from_data(false, &[], &[b'a']);
140+
let access_control = AccessControl::from_data(false, false, &[], &[b'a']);
106141

107142
assert_eq!(
108143
String::from(".").with(Color::Cyan),
@@ -112,7 +147,7 @@ mod test {
112147

113148
#[test]
114149
fn test_acl_and_selinux_indicator() {
115-
let access_control = AccessControl::from_data(true, &[b'a'], &[]);
150+
let access_control = AccessControl::from_data(true, false, &[b'a'], &[]);
116151

117152
assert_eq!(
118153
String::from("+").with(Color::DarkCyan),
@@ -122,7 +157,7 @@ mod test {
122157

123158
#[test]
124159
fn test_selinux_context() {
125-
let access_control = AccessControl::from_data(false, &[b'a'], &[]);
160+
let access_control = AccessControl::from_data(false, false, &[b'a'], &[]);
126161

127162
assert_eq!(
128163
String::from("a").with(Color::Cyan),
@@ -132,7 +167,7 @@ mod test {
132167

133168
#[test]
134169
fn test_selinux_and_smack_context() {
135-
let access_control = AccessControl::from_data(false, &[b'a'], &[b'b']);
170+
let access_control = AccessControl::from_data(false, false, &[b'a'], &[b'b']);
136171

137172
assert_eq!(
138173
String::from("a+b").with(Color::Cyan),
@@ -142,7 +177,7 @@ mod test {
142177

143178
#[test]
144179
fn test_no_context() {
145-
let access_control = AccessControl::from_data(false, &[], &[]);
180+
let access_control = AccessControl::from_data(false, false, &[], &[]);
146181

147182
assert_eq!(
148183
String::from("?").with(Color::Cyan),

0 commit comments

Comments
 (0)