1
1
// miri has some special hacks here that make things unused.
2
2
#![ cfg_attr( miri, allow( unused) ) ]
3
3
4
+ #[ cfg( test) ]
5
+ mod tests;
6
+
4
7
use crate :: os:: unix:: prelude:: * ;
5
8
6
9
use crate :: ffi:: { CStr , OsStr , OsString } ;
7
- use crate :: fmt;
10
+ use crate :: fmt:: { self , Write as _ } ;
8
11
use crate :: io:: { self , BorrowedCursor , Error , IoSlice , IoSliceMut , SeekFrom } ;
9
12
use crate :: mem;
10
13
use crate :: os:: unix:: io:: { AsFd , AsRawFd , BorrowedFd , FromRawFd , IntoRawFd } ;
@@ -356,7 +359,7 @@ pub struct DirEntry {
356
359
entry : dirent64 ,
357
360
}
358
361
359
- #[ derive( Clone , Debug ) ]
362
+ #[ derive( Clone ) ]
360
363
pub struct OpenOptions {
361
364
// generic
362
365
read : bool ,
@@ -370,7 +373,7 @@ pub struct OpenOptions {
370
373
mode : mode_t ,
371
374
}
372
375
373
- #[ derive( Clone , PartialEq , Eq , Debug ) ]
376
+ #[ derive( Clone , PartialEq , Eq ) ]
374
377
pub struct FilePermissions {
375
378
mode : mode_t ,
376
379
}
@@ -389,7 +392,7 @@ pub struct FileTimes {
389
392
created : Option < SystemTime > ,
390
393
}
391
394
392
- #[ derive( Copy , Clone , Eq , Debug ) ]
395
+ #[ derive( Copy , Clone , Eq ) ]
393
396
pub struct FileType {
394
397
mode : mode_t ,
395
398
}
@@ -406,11 +409,13 @@ impl core::hash::Hash for FileType {
406
409
}
407
410
}
408
411
409
- #[ derive( Debug ) ]
410
412
pub struct DirBuilder {
411
413
mode : mode_t ,
412
414
}
413
415
416
+ #[ derive( Copy , Clone ) ]
417
+ struct Mode ( mode_t ) ;
418
+
414
419
cfg_has_statx ! { {
415
420
impl FileAttr {
416
421
fn from_stat64( stat: stat64) -> Self {
@@ -689,12 +694,26 @@ impl FileType {
689
694
}
690
695
}
691
696
697
+ impl fmt:: Debug for FileType {
698
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
699
+ let FileType { mode } = self ;
700
+ f. debug_struct ( "FileType" ) . field ( "mode" , & Mode ( * mode) ) . finish ( )
701
+ }
702
+ }
703
+
692
704
impl FromInner < u32 > for FilePermissions {
693
705
fn from_inner ( mode : u32 ) -> FilePermissions {
694
706
FilePermissions { mode : mode as mode_t }
695
707
}
696
708
}
697
709
710
+ impl fmt:: Debug for FilePermissions {
711
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
712
+ let FilePermissions { mode } = self ;
713
+ f. debug_struct ( "FilePermissions" ) . field ( "mode" , & Mode ( * mode) ) . finish ( )
714
+ }
715
+ }
716
+
698
717
impl fmt:: Debug for ReadDir {
699
718
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
700
719
// This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
@@ -1135,6 +1154,23 @@ impl OpenOptions {
1135
1154
}
1136
1155
}
1137
1156
1157
+ impl fmt:: Debug for OpenOptions {
1158
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1159
+ let OpenOptions { read, write, append, truncate, create, create_new, custom_flags, mode } =
1160
+ self ;
1161
+ f. debug_struct ( "OpenOptions" )
1162
+ . field ( "read" , read)
1163
+ . field ( "write" , write)
1164
+ . field ( "append" , append)
1165
+ . field ( "truncate" , truncate)
1166
+ . field ( "create" , create)
1167
+ . field ( "create_new" , create_new)
1168
+ . field ( "custom_flags" , custom_flags)
1169
+ . field ( "mode" , & Mode ( * mode) )
1170
+ . finish ( )
1171
+ }
1172
+ }
1173
+
1138
1174
impl File {
1139
1175
pub fn open ( path : & Path , opts : & OpenOptions ) -> io:: Result < File > {
1140
1176
run_path_with_cstr ( path, & |path| File :: open_c ( path, opts) )
@@ -1425,6 +1461,13 @@ impl DirBuilder {
1425
1461
}
1426
1462
}
1427
1463
1464
+ impl fmt:: Debug for DirBuilder {
1465
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1466
+ let DirBuilder { mode } = self ;
1467
+ f. debug_struct ( "DirBuilder" ) . field ( "mode" , & Mode ( * mode) ) . finish ( )
1468
+ }
1469
+ }
1470
+
1428
1471
impl AsInner < FileDesc > for File {
1429
1472
#[ inline]
1430
1473
fn as_inner ( & self ) -> & FileDesc {
@@ -1597,6 +1640,73 @@ impl fmt::Debug for File {
1597
1640
}
1598
1641
}
1599
1642
1643
+ // Format in octal, followed by the mode format used in `ls -l`.
1644
+ //
1645
+ // References:
1646
+ // https://pubs.opengroup.org/onlinepubs/009696899/utilities/ls.html
1647
+ // https://www.gnu.org/software/libc/manual/html_node/Testing-File-Type.html
1648
+ // https://www.gnu.org/software/libc/manual/html_node/Permission-Bits.html
1649
+ //
1650
+ // Example:
1651
+ // 0o100664 (-rw-rw-r--)
1652
+ impl fmt:: Debug for Mode {
1653
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1654
+ let Self ( mode) = * self ;
1655
+ write ! ( f, "0o{mode:06o}" ) ?;
1656
+
1657
+ let entry_type = match mode & libc:: S_IFMT {
1658
+ libc:: S_IFDIR => 'd' ,
1659
+ libc:: S_IFBLK => 'b' ,
1660
+ libc:: S_IFCHR => 'c' ,
1661
+ libc:: S_IFLNK => 'l' ,
1662
+ libc:: S_IFIFO => 'p' ,
1663
+ libc:: S_IFREG => '-' ,
1664
+ _ => return Ok ( ( ) ) ,
1665
+ } ;
1666
+
1667
+ f. write_str ( " (" ) ?;
1668
+ f. write_char ( entry_type) ?;
1669
+
1670
+ // Owner permissions
1671
+ f. write_char ( if mode & libc:: S_IRUSR != 0 { 'r' } else { '-' } ) ?;
1672
+ f. write_char ( if mode & libc:: S_IWUSR != 0 { 'w' } else { '-' } ) ?;
1673
+ let owner_executable = mode & libc:: S_IXUSR != 0 ;
1674
+ let setuid = mode as c_int & libc:: S_ISUID as c_int != 0 ;
1675
+ f. write_char ( match ( owner_executable, setuid) {
1676
+ ( true , true ) => 's' , // executable and setuid
1677
+ ( false , true ) => 'S' , // setuid
1678
+ ( true , false ) => 'x' , // executable
1679
+ ( false , false ) => '-' ,
1680
+ } ) ?;
1681
+
1682
+ // Group permissions
1683
+ f. write_char ( if mode & libc:: S_IRGRP != 0 { 'r' } else { '-' } ) ?;
1684
+ f. write_char ( if mode & libc:: S_IWGRP != 0 { 'w' } else { '-' } ) ?;
1685
+ let group_executable = mode & libc:: S_IXGRP != 0 ;
1686
+ let setgid = mode as c_int & libc:: S_ISGID as c_int != 0 ;
1687
+ f. write_char ( match ( group_executable, setgid) {
1688
+ ( true , true ) => 's' , // executable and setgid
1689
+ ( false , true ) => 'S' , // setgid
1690
+ ( true , false ) => 'x' , // executable
1691
+ ( false , false ) => '-' ,
1692
+ } ) ?;
1693
+
1694
+ // Other permissions
1695
+ f. write_char ( if mode & libc:: S_IROTH != 0 { 'r' } else { '-' } ) ?;
1696
+ f. write_char ( if mode & libc:: S_IWOTH != 0 { 'w' } else { '-' } ) ?;
1697
+ let other_executable = mode & libc:: S_IXOTH != 0 ;
1698
+ let sticky = mode as c_int & libc:: S_ISVTX as c_int != 0 ;
1699
+ f. write_char ( match ( entry_type, other_executable, sticky) {
1700
+ ( 'd' , true , true ) => 't' , // searchable and restricted deletion
1701
+ ( 'd' , false , true ) => 'T' , // restricted deletion
1702
+ ( _, true , _) => 'x' , // executable
1703
+ ( _, false , _) => '-' ,
1704
+ } ) ?;
1705
+
1706
+ f. write_char ( ')' )
1707
+ }
1708
+ }
1709
+
1600
1710
pub fn readdir ( path : & Path ) -> io:: Result < ReadDir > {
1601
1711
let ptr = run_path_with_cstr ( path, & |p| unsafe { Ok ( libc:: opendir ( p. as_ptr ( ) ) ) } ) ?;
1602
1712
if ptr. is_null ( ) {
0 commit comments