Skip to main content

compio_fs/metadata/
mod.rs

1#[cfg(unix)]
2#[path = "unix.rs"]
3mod sys;
4
5#[cfg(windows)]
6#[path = "windows.rs"]
7mod sys;
8
9use std::{io, path::Path, time::SystemTime};
10
11#[cfg(unix)]
12use compio_driver::op::{FileAttr, Stat};
13
14/// Given a path, query the file system to get information about a file,
15/// directory, etc.
16pub async fn metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
17    sys::metadata(path).await.map(Metadata)
18}
19
20/// Query the metadata about a file without following symlinks.
21pub async fn symlink_metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
22    sys::symlink_metadata(path).await.map(Metadata)
23}
24
25#[cfg(dirfd)]
26pub(crate) async fn metadata_at(dir: &crate::File, path: impl AsRef<Path>) -> io::Result<Metadata> {
27    sys::metadata_at(dir, path).await.map(Metadata)
28}
29
30#[cfg(dirfd)]
31pub(crate) async fn symlink_metadata_at(
32    dir: &crate::File,
33    path: impl AsRef<Path>,
34) -> io::Result<Metadata> {
35    sys::symlink_metadata_at(dir, path).await.map(Metadata)
36}
37
38/// Changes the permissions found on a file or a directory.
39pub async fn set_permissions(path: impl AsRef<Path>, perm: Permissions) -> io::Result<()> {
40    sys::set_permissions(path, perm.0).await
41}
42
43/// Metadata information about a file.
44#[derive(Clone)]
45pub struct Metadata(sys::Metadata);
46
47impl Metadata {
48    /// Returns the file type for this metadata.
49    pub fn file_type(&self) -> FileType {
50        FileType(self.0.file_type())
51    }
52
53    /// Returns `true` if this metadata is for a directory.
54    pub fn is_dir(&self) -> bool {
55        self.0.is_dir()
56    }
57
58    /// Returns `true` if this metadata is for a regular file.
59    pub fn is_file(&self) -> bool {
60        self.0.is_file()
61    }
62
63    /// Returns `true` if this metadata is for a symbolic link.
64    pub fn is_symlink(&self) -> bool {
65        self.0.is_symlink()
66    }
67
68    /// Returns the size of the file, in bytes, this metadata is for.
69    #[allow(clippy::len_without_is_empty)]
70    pub fn len(&self) -> u64 {
71        self.0.len()
72    }
73
74    /// Returns the permissions of the file this metadata is for.
75    pub fn permissions(&self) -> Permissions {
76        Permissions(self.0.permissions())
77    }
78
79    /// Returns the last modification time listed in this metadata.
80    ///
81    /// ## Platform specific
82    /// * Windows: The returned value corresponds to the `ftLastWriteTime`
83    ///   field.
84    /// * Unix: The returned value corresponds to the `mtime` field.
85    pub fn modified(&self) -> io::Result<SystemTime> {
86        self.0.modified()
87    }
88
89    /// Returns the last access time of this metadata.
90    ///
91    /// ## Platform specific
92    /// * Windows: The returned value corresponds to the `ftLastAccessTime`
93    ///   field.
94    /// * Unix: The returned value corresponds to the `atime` field.
95    pub fn accessed(&self) -> io::Result<SystemTime> {
96        self.0.accessed()
97    }
98
99    /// Returns the creation (birth) time listed in this metadata.
100    ///
101    /// ## Platform specific
102    /// * Windows: The returned value corresponds to the `ftCreationTime` field.
103    /// * Linux: The returned value corresponds to the `stx_btime` field of
104    ///   `statx`. Returns an error if the filesystem does not report a birth
105    ///   time.
106    /// * Other Unix (BSD/Apple): The returned value corresponds to the
107    ///   `st_birthtime` field of
108    #[cfg_attr(all(unix, not(gnulinux)), doc = "[`libc::stat`](struct@libc::stat).")]
109    #[cfg_attr(gnulinux, doc = "[`libc::stat64`](struct@libc::stat64).")]
110    #[cfg_attr(
111        windows,
112        doc = "[`libc::stat`](https://docs.rs/libc/latest/libc/struct.stat.html)."
113    )]
114    pub fn created(&self) -> io::Result<SystemTime> {
115        self.0.created()
116    }
117}
118
119// The below methods are Windows specific. We cannot impl `MetadataExt` because
120// it is going to be sealed.
121#[cfg(windows)]
122impl Metadata {
123    /// Create [`Metadata`] from [`std::fs::Metadata`].
124    pub fn from_std(m: std::fs::Metadata) -> Self {
125        Self(sys::Metadata::from(m))
126    }
127
128    /// Returns the value of the `dwFileAttributes` field of this metadata.
129    pub fn file_attributes(&self) -> u32 {
130        self.0.file_attributes()
131    }
132
133    /// Returns the value of the `ftCreationTime` field of this metadata.
134    pub fn creation_time(&self) -> u64 {
135        self.0.creation_time()
136    }
137
138    /// Returns the value of the `ftLastAccessTime` field of this metadata.
139    pub fn last_access_time(&self) -> u64 {
140        self.0.last_access_time()
141    }
142
143    /// Returns the value of the `ftLastWriteTime` field of this metadata.
144    pub fn last_write_time(&self) -> u64 {
145        self.0.last_write_time()
146    }
147}
148
149#[cfg(all(windows, feature = "windows_by_handle"))]
150impl Metadata {
151    /// Returns the value of the `dwVolumeSerialNumber` field of this
152    /// metadata.
153    pub fn volume_serial_number(&self) -> Option<u32> {
154        self.0.volume_serial_number()
155    }
156
157    /// Returns the value of the `nNumberOfLinks` field of this
158    /// metadata.
159    pub fn number_of_links(&self) -> Option<u32> {
160        self.0.number_of_links()
161    }
162
163    /// Returns the value of the `nFileIndex{Low,High}` fields of this
164    /// metadata.
165    pub fn file_index(&self) -> Option<u64> {
166        self.0.file_index()
167    }
168}
169
170#[cfg(unix)]
171impl Metadata {
172    /// Create from
173    #[cfg_attr(not(gnulinux), doc = "[`libc::stat`](struct@libc::stat).")]
174    #[cfg_attr(gnulinux, doc = "[`libc::stat64`](struct@libc::stat64).")]
175    pub fn from_stat(stat: Stat) -> Self {
176        Self(sys::Metadata::from_stat(stat))
177    }
178
179    /// Create from [`FileAttr`].
180    pub(crate) fn from_attr(attr: FileAttr) -> Self {
181        Self(sys::Metadata::from_attr(attr))
182    }
183}
184
185#[cfg(unix)]
186impl std::os::unix::prelude::MetadataExt for Metadata {
187    fn dev(&self) -> u64 {
188        self.0.dev()
189    }
190
191    fn ino(&self) -> u64 {
192        self.0.ino()
193    }
194
195    fn mode(&self) -> u32 {
196        self.0.mode()
197    }
198
199    fn nlink(&self) -> u64 {
200        self.0.nlink()
201    }
202
203    fn uid(&self) -> u32 {
204        self.0.uid()
205    }
206
207    fn gid(&self) -> u32 {
208        self.0.gid()
209    }
210
211    fn rdev(&self) -> u64 {
212        self.0.rdev()
213    }
214
215    fn size(&self) -> u64 {
216        self.0.size()
217    }
218
219    fn atime(&self) -> i64 {
220        self.0.atime()
221    }
222
223    fn atime_nsec(&self) -> i64 {
224        self.0.atime_nsec()
225    }
226
227    fn mtime(&self) -> i64 {
228        self.0.mtime()
229    }
230
231    fn mtime_nsec(&self) -> i64 {
232        self.0.mtime_nsec()
233    }
234
235    fn ctime(&self) -> i64 {
236        self.0.ctime()
237    }
238
239    fn ctime_nsec(&self) -> i64 {
240        self.0.ctime_nsec()
241    }
242
243    fn blksize(&self) -> u64 {
244        self.0.blksize()
245    }
246
247    fn blocks(&self) -> u64 {
248        self.0.blocks()
249    }
250}
251
252/// A structure representing a type of file with accessors for each file type.
253#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
254pub struct FileType(sys::FileType);
255
256impl FileType {
257    /// Tests whether this file type represents a directory.
258    pub fn is_dir(&self) -> bool {
259        self.0.is_dir()
260    }
261
262    /// Tests whether this file type represents a regular file.
263    pub fn is_file(&self) -> bool {
264        self.0.is_file()
265    }
266
267    /// Tests whether this file type represents a symbolic link.
268    pub fn is_symlink(&self) -> bool {
269        self.0.is_symlink()
270    }
271}
272
273// The below methods are Windows specific. We cannot impl `FileTypeExt` because
274// it is sealed.
275
276#[cfg(windows)]
277impl FileType {
278    /// Returns `true` if this file type is a symbolic link that is also a
279    /// directory.
280    pub fn is_symlink_dir(&self) -> bool {
281        self.0.is_symlink_dir()
282    }
283
284    /// Returns `true` if this file type is a symbolic link that is also a file.
285    pub fn is_symlink_file(&self) -> bool {
286        self.0.is_symlink_file()
287    }
288}
289
290#[cfg(unix)]
291impl std::os::unix::prelude::FileTypeExt for FileType {
292    fn is_block_device(&self) -> bool {
293        self.0.is_block_device()
294    }
295
296    fn is_char_device(&self) -> bool {
297        self.0.is_char_device()
298    }
299
300    fn is_fifo(&self) -> bool {
301        self.0.is_fifo()
302    }
303
304    fn is_socket(&self) -> bool {
305        self.0.is_socket()
306    }
307}
308
309/// Representation of the various permissions on a file.
310#[derive(Clone, PartialEq, Eq, Debug)]
311pub struct Permissions(pub(crate) sys::Permissions);
312
313impl Permissions {
314    /// Returns `true` if these permissions describe a readonly (unwritable)
315    /// file.
316    pub fn readonly(&self) -> bool {
317        self.0.readonly()
318    }
319
320    /// Modifies the readonly flag for this set of permissions.
321    ///
322    /// This operation does **not** modify the files attributes.
323    pub fn set_readonly(&mut self, readonly: bool) {
324        self.0.set_readonly(readonly)
325    }
326}
327
328#[cfg(unix)]
329impl std::os::unix::prelude::PermissionsExt for Permissions {
330    fn mode(&self) -> u32 {
331        self.0.mode()
332    }
333
334    fn set_mode(&mut self, mode: u32) {
335        self.0.set_mode(mode)
336    }
337
338    fn from_mode(mode: u32) -> Self {
339        Self(sys::Permissions::from_mode(mode))
340    }
341}