dir_view/
dir_entry.rs

1use crate::{DirView, ViewKind};
2use cap_std::fs::{DirEntry, File, FileType, Metadata, OpenOptions};
3#[cfg(not(windows))]
4use rustix::fs::DirEntryExt;
5use std::ffi::OsString;
6use std::{fmt, io};
7
8/// Entries returned by the `ReadDir` iterator.
9///
10/// This corresponds to [`std::fs::DirEntry`].
11///
12/// Unlike `std::fs::DirEntry`, this API has no `DirEntry::path`, because
13/// absolute paths don't interoperate well with the capability model.
14///
15/// There is a `file_name` function, however there are also `open`,
16/// `open_with`, `open_dir`, `remove_file`, and `remove_dir` functions for
17/// opening or removing the entry directly, which can be more efficient and
18/// convenient.
19///
20/// There is no `from_std` method, as `std::fs::DirEntry` doesn't provide a
21/// way to construct a `DirEntry` without opening directories by ambient paths.
22pub struct DirEntryView {
23    pub(crate) entry: DirEntry,
24    pub(crate) view_kind: ViewKind,
25}
26
27impl DirEntryView {
28    /// Open the file for reading.
29    #[inline]
30    pub fn open(&self) -> io::Result<File> {
31        self.entry.open()
32    }
33
34    /// Open the file with the given options.
35    #[inline]
36    pub fn open_with(&self, options: &OpenOptions) -> io::Result<File> {
37        // Override any flag that allows writing.
38        let mut options = options.clone();
39        match self.view_kind {
40            ViewKind::Full => {}
41            ViewKind::Readonly => {
42                // Override any flag that allows writing.
43                options.append(false);
44                options.truncate(false);
45                options.write(false);
46                options.create(false);
47                options.create_new(false);
48            }
49        }
50        self.entry.open_with(&options)
51    }
52
53    /// Open the entry as a directory.
54    #[inline]
55    pub fn open_dir(&self) -> io::Result<DirView> {
56        Ok(DirView {
57            dir: self.entry.open_dir()?,
58            view_kind: self.view_kind,
59        })
60    }
61
62    /// Removes the file from its filesystem.
63    #[inline]
64    pub fn remove_file(&self) -> io::Result<()> {
65        self.check_mutation()?;
66        self.entry.remove_file()
67    }
68
69    /// Removes the directory from its filesystem.
70    #[inline]
71    pub fn remove_dir(&self) -> io::Result<()> {
72        self.check_mutation()?;
73        self.entry.remove_dir()
74    }
75
76    /// Returns the metadata for the file that this entry points at.
77    ///
78    /// This corresponds to [`std::fs::DirEntry::metadata`].
79    #[inline]
80    pub fn metadata(&self) -> io::Result<Metadata> {
81        self.entry.metadata()
82    }
83
84    /// Returns the file type for the file that this entry points at.
85    ///
86    /// This corresponds to [`std::fs::DirEntry::file_type`].
87    #[inline]
88    pub fn file_type(&self) -> io::Result<FileType> {
89        self.entry.file_type()
90    }
91
92    /// Returns the bare file name of this directory entry without any other
93    /// leading path component.
94    ///
95    /// This corresponds to [`std::fs::DirEntry::file_name`].
96    #[inline]
97    pub fn file_name(&self) -> OsString {
98        self.entry.file_name()
99    }
100
101    fn check_mutation(&self) -> io::Result<()> {
102        match self.view_kind {
103            ViewKind::Full => Ok(()),
104            ViewKind::Readonly => Err(Self::readonly()),
105        }
106    }
107
108    fn readonly() -> io::Error {
109        io::Error::new(
110            io::ErrorKind::PermissionDenied,
111            "attempt to modify a directory tree through a read-only `DirView`",
112        )
113    }
114}
115
116#[cfg(not(windows))]
117impl DirEntryExt for DirEntryView {
118    #[inline]
119    fn ino(&self) -> u64 {
120        self.entry.ino()
121    }
122}
123
124#[cfg(windows)]
125#[doc(hidden)]
126impl cap_primitives::fs::_WindowsDirEntryExt for DirEntryView {
127    #[inline]
128    fn full_metadata(&self) -> io::Result<Metadata> {
129        cap_primitives::fs::_WindowsDirEntryExt::full_metadata(&self.entry)
130    }
131}
132
133impl fmt::Debug for DirEntryView {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        self.entry.fmt(f)
136    }
137}
138
139#[cfg(feature = "cap-fs-ext")]
140impl cap_fs_ext::DirEntryExt for DirEntryView {
141    fn full_metadata(&self) -> io::Result<Metadata> {
142        cap_fs_ext::DirEntryExt::full_metadata(&self.entry)
143    }
144}