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 } ;
@@ -354,7 +357,7 @@ pub struct DirEntry {
354
357
entry : dirent64 ,
355
358
}
356
359
357
- #[ derive( Clone , Debug ) ]
360
+ #[ derive( Clone ) ]
358
361
pub struct OpenOptions {
359
362
// generic
360
363
read : bool ,
@@ -368,7 +371,7 @@ pub struct OpenOptions {
368
371
mode : mode_t ,
369
372
}
370
373
371
- #[ derive( Clone , PartialEq , Eq , Debug ) ]
374
+ #[ derive( Clone , PartialEq , Eq ) ]
372
375
pub struct FilePermissions {
373
376
mode : mode_t ,
374
377
}
@@ -381,7 +384,7 @@ pub struct FileTimes {
381
384
created : Option < SystemTime > ,
382
385
}
383
386
384
- #[ derive( Copy , Clone , Eq , Debug ) ]
387
+ #[ derive( Copy , Clone , Eq ) ]
385
388
pub struct FileType {
386
389
mode : mode_t ,
387
390
}
@@ -398,11 +401,13 @@ impl core::hash::Hash for FileType {
398
401
}
399
402
}
400
403
401
- #[ derive( Debug ) ]
402
404
pub struct DirBuilder {
403
405
mode : mode_t ,
404
406
}
405
407
408
+ #[ derive( Copy , Clone ) ]
409
+ struct Mode ( mode_t ) ;
410
+
406
411
cfg_has_statx ! { {
407
412
impl FileAttr {
408
413
fn from_stat64( stat: stat64) -> Self {
@@ -673,12 +678,26 @@ impl FileType {
673
678
}
674
679
}
675
680
681
+ impl fmt:: Debug for FileType {
682
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
683
+ let FileType { mode } = self ;
684
+ f. debug_struct ( "FileType" ) . field ( "mode" , & Mode ( * mode) ) . finish ( )
685
+ }
686
+ }
687
+
676
688
impl FromInner < u32 > for FilePermissions {
677
689
fn from_inner ( mode : u32 ) -> FilePermissions {
678
690
FilePermissions { mode : mode as mode_t }
679
691
}
680
692
}
681
693
694
+ impl fmt:: Debug for FilePermissions {
695
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
696
+ let FilePermissions { mode } = self ;
697
+ f. debug_struct ( "FilePermissions" ) . field ( "mode" , & Mode ( * mode) ) . finish ( )
698
+ }
699
+ }
700
+
682
701
impl fmt:: Debug for ReadDir {
683
702
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
684
703
// This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
@@ -1116,6 +1135,23 @@ impl OpenOptions {
1116
1135
}
1117
1136
}
1118
1137
1138
+ impl fmt:: Debug for OpenOptions {
1139
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1140
+ let OpenOptions { read, write, append, truncate, create, create_new, custom_flags, mode } =
1141
+ self ;
1142
+ f. debug_struct ( "OpenOptions" )
1143
+ . field ( "read" , read)
1144
+ . field ( "write" , write)
1145
+ . field ( "append" , append)
1146
+ . field ( "truncate" , truncate)
1147
+ . field ( "create" , create)
1148
+ . field ( "create_new" , create_new)
1149
+ . field ( "custom_flags" , custom_flags)
1150
+ . field ( "mode" , & Mode ( * mode) )
1151
+ . finish ( )
1152
+ }
1153
+ }
1154
+
1119
1155
impl File {
1120
1156
pub fn open ( path : & Path , opts : & OpenOptions ) -> io:: Result < File > {
1121
1157
run_path_with_cstr ( path, & |path| File :: open_c ( path, opts) )
@@ -1402,6 +1438,13 @@ impl DirBuilder {
1402
1438
}
1403
1439
}
1404
1440
1441
+ impl fmt:: Debug for DirBuilder {
1442
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1443
+ let DirBuilder { mode } = self ;
1444
+ f. debug_struct ( "DirBuilder" ) . field ( "mode" , & Mode ( * mode) ) . finish ( )
1445
+ }
1446
+ }
1447
+
1405
1448
impl AsInner < FileDesc > for File {
1406
1449
#[ inline]
1407
1450
fn as_inner ( & self ) -> & FileDesc {
@@ -1574,6 +1617,73 @@ impl fmt::Debug for File {
1574
1617
}
1575
1618
}
1576
1619
1620
+ // Format in octal, followed by the mode format used in `ls -l`.
1621
+ //
1622
+ // References:
1623
+ // https://pubs.opengroup.org/onlinepubs/009696899/utilities/ls.html
1624
+ // https://www.gnu.org/software/libc/manual/html_node/Testing-File-Type.html
1625
+ // https://www.gnu.org/software/libc/manual/html_node/Permission-Bits.html
1626
+ //
1627
+ // Example:
1628
+ // 0o100664 (-rw-rw-r--)
1629
+ impl fmt:: Debug for Mode {
1630
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1631
+ let Self ( mode) = * self ;
1632
+ write ! ( f, "0o{mode:06o}" ) ?;
1633
+
1634
+ let entry_type = match mode & libc:: S_IFMT {
1635
+ libc:: S_IFDIR => 'd' ,
1636
+ libc:: S_IFBLK => 'b' ,
1637
+ libc:: S_IFCHR => 'c' ,
1638
+ libc:: S_IFLNK => 'l' ,
1639
+ libc:: S_IFIFO => 'p' ,
1640
+ libc:: S_IFREG => '-' ,
1641
+ _ => return Ok ( ( ) ) ,
1642
+ } ;
1643
+
1644
+ f. write_str ( " (" ) ?;
1645
+ f. write_char ( entry_type) ?;
1646
+
1647
+ // Owner permissions
1648
+ f. write_char ( if mode & libc:: S_IRUSR != 0 { 'r' } else { '-' } ) ?;
1649
+ f. write_char ( if mode & libc:: S_IWUSR != 0 { 'w' } else { '-' } ) ?;
1650
+ let owner_executable = mode & libc:: S_IXUSR != 0 ;
1651
+ let setuid = mode as c_int & libc:: S_ISUID as c_int != 0 ;
1652
+ f. write_char ( match ( owner_executable, setuid) {
1653
+ ( true , true ) => 's' , // executable and setuid
1654
+ ( false , true ) => 'S' , // setuid
1655
+ ( true , false ) => 'x' , // executable
1656
+ ( false , false ) => '-' ,
1657
+ } ) ?;
1658
+
1659
+ // Group permissions
1660
+ f. write_char ( if mode & libc:: S_IRGRP != 0 { 'r' } else { '-' } ) ?;
1661
+ f. write_char ( if mode & libc:: S_IWGRP != 0 { 'w' } else { '-' } ) ?;
1662
+ let group_executable = mode & libc:: S_IXGRP != 0 ;
1663
+ let setgid = mode as c_int & libc:: S_ISGID as c_int != 0 ;
1664
+ f. write_char ( match ( group_executable, setgid) {
1665
+ ( true , true ) => 's' , // executable and setgid
1666
+ ( false , true ) => 'S' , // setgid
1667
+ ( true , false ) => 'x' , // executable
1668
+ ( false , false ) => '-' ,
1669
+ } ) ?;
1670
+
1671
+ // Other permissions
1672
+ f. write_char ( if mode & libc:: S_IROTH != 0 { 'r' } else { '-' } ) ?;
1673
+ f. write_char ( if mode & libc:: S_IWOTH != 0 { 'w' } else { '-' } ) ?;
1674
+ let other_executable = mode & libc:: S_IXOTH != 0 ;
1675
+ let sticky = mode as c_int & libc:: S_ISVTX as c_int != 0 ;
1676
+ f. write_char ( match ( entry_type, other_executable, sticky) {
1677
+ ( 'd' , true , true ) => 't' , // searchable and restricted deletion
1678
+ ( 'd' , false , true ) => 'T' , // restricted deletion
1679
+ ( _, true , _) => 'x' , // executable
1680
+ ( _, false , _) => '-' ,
1681
+ } ) ?;
1682
+
1683
+ f. write_char ( ')' )
1684
+ }
1685
+ }
1686
+
1577
1687
pub fn readdir ( path : & Path ) -> io:: Result < ReadDir > {
1578
1688
let ptr = run_path_with_cstr ( path, & |p| unsafe { Ok ( libc:: opendir ( p. as_ptr ( ) ) ) } ) ?;
1579
1689
if ptr. is_null ( ) {
0 commit comments