@@ -4,14 +4,15 @@ use std::path::Path;
44#[ derive( Clone , Debug ) ]
55pub struct AccessControl {
66 has_acl : bool ,
7+ has_xattr : bool ,
78 selinux_context : String ,
89 smack_context : String ,
910}
1011
1112impl 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