@@ -782,9 +782,8 @@ fn bsd_tar_list_entries_to(
782782 for row in entries {
783783 let nlink = 0 ; // BSD tar show always 0
784784 let permission = row. permission_mode ( ) ;
785- let has_xattr = !row. xattrs . is_empty ( ) ;
786785 let has_acl = !row. acl . is_empty ( ) ;
787- let perm = bsdtar_permission_string ( & row. entry_type , permission, has_acl) ;
786+ let perm = PermissionDisplay :: bsdtar ( & row. entry_type , permission, has_acl) ;
788787 let size = row. raw_size . unwrap_or ( 0 ) ;
789788 let mtime = bsd_tar_time ( now, row. modified . unwrap_or ( now) ) ;
790789 let ( uname, gname) = match & row. permission {
@@ -1155,63 +1154,64 @@ const fn kind_char(kind: &EntryType) -> char {
11551154 }
11561155}
11571156
1158- const fn bsdtar_kind_char ( kind : & EntryType ) -> char {
1159- match kind {
1160- EntryType :: File ( _) => '-' ,
1161- EntryType :: HardLink ( _, _) => 'h' ,
1162- EntryType :: Directory ( _) => 'd' ,
1163- EntryType :: SymbolicLink ( _, _) => 'l' ,
1164- }
1157+ struct PermissionDisplay {
1158+ kind : char ,
1159+ permission : u16 ,
1160+ indicator : char ,
11651161}
11661162
1167- fn permission_string ( kind : & EntryType , permission : u16 , has_xattr : bool , has_acl : bool ) -> String {
1168- #[ inline( always) ]
1169- const fn paint ( permission : u16 , c : char , bit : u16 ) -> char {
1170- if permission & bit != 0 { c } else { '-' }
1163+ impl PermissionDisplay {
1164+ const fn new ( kind : & EntryType , permission : u16 , has_xattr : bool , has_acl : bool ) -> Self {
1165+ Self {
1166+ kind : kind_char ( kind) ,
1167+ permission,
1168+ indicator : if has_xattr {
1169+ '@'
1170+ } else if has_acl {
1171+ '+'
1172+ } else {
1173+ ' '
1174+ } ,
1175+ }
11711176 }
11721177
1173- format ! (
1174- "{}{}{}{}{}{}{}{}{}{}{}" ,
1175- kind_char( kind) ,
1176- paint( permission, 'r' , 0b100000000 ) , // owner_read
1177- paint( permission, 'w' , 0b010000000 ) , // owner_write
1178- paint( permission, 'x' , 0b001000000 ) , // owner_exec
1179- paint( permission, 'r' , 0b000100000 ) , // group_read
1180- paint( permission, 'w' , 0b000010000 ) , // group_write
1181- paint( permission, 'x' , 0b000001000 ) , // group_exec
1182- paint( permission, 'r' , 0b000000100 ) , // other_read
1183- paint( permission, 'w' , 0b000000010 ) , // other_write
1184- paint( permission, 'x' , 0b000000001 ) , // other_exec
1185- if has_xattr {
1186- '@'
1187- } else if has_acl {
1188- '+'
1189- } else {
1190- ' '
1191- } ,
1192- )
1178+ /// Match bsdtar's `archive_entry_strmode`: `'h'` for hardlinks,
1179+ /// only `'+'` for ACL (no `'@'` for xattr).
1180+ const fn bsdtar ( kind : & EntryType , permission : u16 , has_acl : bool ) -> Self {
1181+ Self {
1182+ kind : match kind {
1183+ EntryType :: File ( _) => '-' ,
1184+ EntryType :: HardLink ( _, _) => 'h' ,
1185+ EntryType :: Directory ( _) => 'd' ,
1186+ EntryType :: SymbolicLink ( _, _) => 'l' ,
1187+ } ,
1188+ permission,
1189+ indicator : if has_acl { '+' } else { ' ' } ,
1190+ }
1191+ }
11931192}
11941193
1195- fn bsdtar_permission_string ( kind : & EntryType , permission : u16 , has_acl : bool ) -> String {
1196- #[ inline( always) ]
1197- const fn paint ( permission : u16 , c : char , bit : u16 ) -> char {
1198- if permission & bit != 0 { c } else { '-' }
1194+ impl fmt:: Display for PermissionDisplay {
1195+ #[ inline]
1196+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
1197+ #[ inline( always) ]
1198+ const fn paint ( permission : u16 , c : char , bit : u16 ) -> char {
1199+ if permission & bit != 0 { c } else { '-' }
1200+ }
1201+ use core:: fmt:: Write ;
1202+ let p = self . permission ;
1203+ f. write_char ( self . kind ) ?;
1204+ f. write_char ( paint ( p, 'r' , 0b100000000 ) ) ?; // owner_read
1205+ f. write_char ( paint ( p, 'w' , 0b010000000 ) ) ?; // owner_write
1206+ f. write_char ( paint ( p, 'x' , 0b001000000 ) ) ?; // owner_exec
1207+ f. write_char ( paint ( p, 'r' , 0b000100000 ) ) ?; // group_read
1208+ f. write_char ( paint ( p, 'w' , 0b000010000 ) ) ?; // group_write
1209+ f. write_char ( paint ( p, 'x' , 0b000001000 ) ) ?; // group_exec
1210+ f. write_char ( paint ( p, 'r' , 0b000000100 ) ) ?; // other_read
1211+ f. write_char ( paint ( p, 'w' , 0b000000010 ) ) ?; // other_write
1212+ f. write_char ( paint ( p, 'x' , 0b000000001 ) ) ?; // other_exec
1213+ f. write_char ( self . indicator )
11991214 }
1200-
1201- format ! (
1202- "{}{}{}{}{}{}{}{}{}{}{}" ,
1203- bsdtar_kind_char( kind) ,
1204- paint( permission, 'r' , 0b100000000 ) ,
1205- paint( permission, 'w' , 0b010000000 ) ,
1206- paint( permission, 'x' , 0b001000000 ) ,
1207- paint( permission, 'r' , 0b000100000 ) ,
1208- paint( permission, 'w' , 0b000010000 ) ,
1209- paint( permission, 'x' , 0b000001000 ) ,
1210- paint( permission, 'r' , 0b000000100 ) ,
1211- paint( permission, 'w' , 0b000000010 ) ,
1212- paint( permission, 'x' , 0b000000001 ) ,
1213- if has_acl { '+' } else { ' ' } ,
1214- )
12151215}
12161216
12171217#[ derive( Serialize , Debug ) ]
@@ -1269,12 +1269,13 @@ fn json_line_entries_to(
12691269 . map_or_else ( String :: new, |it| it. gname ( ) . to_string ( ) ) ;
12701270 FileInfo {
12711271 filename : it. entry_type . name ( ) ,
1272- permissions : permission_string (
1272+ permissions : PermissionDisplay :: new (
12731273 & it. entry_type ,
12741274 permission_mode,
12751275 !it. xattrs . is_empty ( ) ,
12761276 !it. acl . is_empty ( ) ,
1277- ) ,
1277+ )
1278+ . to_string ( ) ,
12781279 owner,
12791280 group,
12801281 raw_size : it. raw_size . unwrap_or_default ( ) ,
@@ -1381,12 +1382,15 @@ fn delimited_entries_to(
13811382
13821383 [
13831384 Some ( row. entry_type . name ( ) . to_string ( ) ) ,
1384- Some ( permission_string (
1385- & row. entry_type ,
1386- permission_mode,
1387- !row. xattrs . is_empty ( ) ,
1388- !row. acl . is_empty ( ) ,
1389- ) ) ,
1385+ Some (
1386+ PermissionDisplay :: new (
1387+ & row. entry_type ,
1388+ permission_mode,
1389+ !row. xattrs . is_empty ( ) ,
1390+ !row. acl . is_empty ( ) ,
1391+ )
1392+ . to_string ( ) ,
1393+ ) ,
13901394 Some ( owner) ,
13911395 Some ( group) ,
13921396 Some ( row. raw_size . unwrap_or ( 0 ) . to_string ( ) ) ,
0 commit comments