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