@@ -20,8 +20,8 @@ use clap::{
20
20
ArgGroup , Parser ,
21
21
} ;
22
22
use pna:: {
23
- prelude:: * , Compression , DataKind , Encryption , ExtendedAttribute , NormalEntry , Permission ,
24
- RawChunk , ReadEntry , ReadOptions , SolidHeader ,
23
+ prelude:: * , Compression , DataKind , Encryption , ExtendedAttribute , NormalEntry , RawChunk ,
24
+ ReadEntry , ReadOptions , SolidHeader ,
25
25
} ;
26
26
use rayon:: prelude:: * ;
27
27
use serde:: { Deserialize , Serialize } ;
@@ -118,9 +118,10 @@ impl FromStr for Format {
118
118
}
119
119
120
120
struct TableRow {
121
+ data_kind : DataKind ,
121
122
encryption : String ,
122
123
compression : String ,
123
- permissions : String ,
124
+ permission_mode : u16 ,
124
125
raw_size : Option < u128 > ,
125
126
compressed_size : usize ,
126
127
user : Option < Subject > ,
@@ -163,9 +164,8 @@ where
163
164
let header = entry. header ( ) ;
164
165
let metadata = entry. metadata ( ) ;
165
166
let acl = entry. acl ( ) ?;
166
- let has_acl = !acl. is_empty ( ) ;
167
- let has_xattr = !entry. xattrs ( ) . is_empty ( ) ;
168
167
Ok ( Self {
168
+ data_kind : header. data_kind ( ) ,
169
169
encryption : match solid
170
170
. map ( |s| ( s. encryption ( ) , s. cipher_mode ( ) ) )
171
171
. unwrap_or_else ( || ( header. encryption ( ) , header. cipher_mode ( ) ) )
@@ -186,12 +186,7 @@ where
186
186
( method, None ) => format ! ( "{:?}" , method) . to_ascii_lowercase ( ) ,
187
187
( method, Some ( _) ) => format ! ( "{:?}(solid)" , method) . to_ascii_lowercase ( ) ,
188
188
} ,
189
- permissions : paint_permission (
190
- header. data_kind ( ) ,
191
- metadata. permission ( ) ,
192
- has_xattr,
193
- has_acl,
194
- ) ,
189
+ permission_mode : metadata. permission ( ) . map_or ( 0 , |it| it. permissions ( ) ) ,
195
190
raw_size : metadata. raw_file_size ( ) ,
196
191
compressed_size : metadata. compressed_size ( ) ,
197
192
user : metadata. permission ( ) . map ( |p| Subject {
@@ -406,10 +401,17 @@ fn detail_list_entries(entries: impl Iterator<Item = TableRow>, options: ListOpt
406
401
builder. push_record ( header) ;
407
402
}
408
403
for content in entries {
404
+ let has_acl = !content. acl . is_empty ( ) ;
405
+ let has_xattr = !content. xattrs . is_empty ( ) ;
409
406
builder. push_record ( [
410
407
content. encryption ,
411
408
content. compression ,
412
- content. permissions ,
409
+ paint_permission (
410
+ content. data_kind ,
411
+ content. permission_mode ,
412
+ has_xattr,
413
+ has_acl,
414
+ ) ,
413
415
content
414
416
. raw_size
415
417
. map_or_else ( || "-" . into ( ) , |size| size. to_string ( ) ) ,
@@ -564,13 +566,7 @@ fn kind_paint(kind: DataKind) -> impl Display + 'static {
564
566
}
565
567
}
566
568
567
- fn paint_permission (
568
- kind : DataKind ,
569
- permission : Option < & Permission > ,
570
- has_xattr : bool ,
571
- has_acl : bool ,
572
- ) -> String {
573
- let permission = permission. map ( |p| p. permissions ( ) ) . unwrap_or_default ( ) ;
569
+ fn paint_permission ( kind : DataKind , permission : u16 , has_xattr : bool , has_acl : bool ) -> String {
574
570
let paint = |style : & ' static Style , c : char , bit : u16 | {
575
571
if permission & bit != 0 {
576
572
style. paint ( c)
@@ -601,6 +597,46 @@ fn paint_permission(
601
597
)
602
598
}
603
599
600
+ fn kind_char ( kind : DataKind ) -> char {
601
+ match kind {
602
+ DataKind :: File | DataKind :: HardLink => '.' ,
603
+ DataKind :: Directory => 'd' ,
604
+ DataKind :: SymbolicLink => 'l' ,
605
+ }
606
+ }
607
+
608
+ fn permission_string ( kind : DataKind , permission : u16 , has_xattr : bool , has_acl : bool ) -> String {
609
+ #[ inline( always) ]
610
+ fn paint ( permission : u16 , c : char , bit : u16 ) -> char {
611
+ if permission & bit != 0 {
612
+ c
613
+ } else {
614
+ '-'
615
+ }
616
+ }
617
+
618
+ format ! (
619
+ "{}{}{}{}{}{}{}{}{}{}{}" ,
620
+ kind_char( kind) ,
621
+ paint( permission, 'r' , 0b100000000 ) , // owner_read
622
+ paint( permission, 'w' , 0b010000000 ) , // owner_write
623
+ paint( permission, 'x' , 0b001000000 ) , // owner_exec
624
+ paint( permission, 'r' , 0b000100000 ) , // group_read
625
+ paint( permission, 'w' , 0b000010000 ) , // group_write
626
+ paint( permission, 'x' , 0b000001000 ) , // group_exec
627
+ paint( permission, 'r' , 0b000000100 ) , // other_read
628
+ paint( permission, 'w' , 0b000000010 ) , // other_write
629
+ paint( permission, 'x' , 0b000000001 ) , // other_exec
630
+ if has_xattr {
631
+ '@'
632
+ } else if has_acl {
633
+ '+'
634
+ } else {
635
+ ' '
636
+ } ,
637
+ )
638
+ }
639
+
604
640
#[ derive( Serialize , Deserialize , Debug ) ]
605
641
struct FileInfo {
606
642
filename : String ,
@@ -634,7 +670,12 @@ fn json_line_entries(entries: impl Iterator<Item = TableRow>) {
634
670
let mut stdout = io:: stdout ( ) . lock ( ) ;
635
671
for line in entries. map ( |it| FileInfo {
636
672
filename : it. name ,
637
- permissions : it. permissions ,
673
+ permissions : permission_string (
674
+ it. data_kind ,
675
+ it. permission_mode ,
676
+ !it. xattrs . is_empty ( ) ,
677
+ !it. acl . is_empty ( ) ,
678
+ ) ,
638
679
owner : it. user . map_or_else ( || "" . into ( ) , |it| it. name ) ,
639
680
group : it. group . map_or_else ( || "" . into ( ) , |it| it. name ) ,
640
681
raw_size : it. raw_size . unwrap_or_default ( ) ,
0 commit comments