standard_lib/fs/dir/
dir.rs

1use std::ffi::CString;
2use std::io::RawOsError;
3
4use libc::{O_DIRECTORY, c_int, mode_t};
5
6use crate::collections::contiguous::Array;
7use crate::fs::dir::{DirEntries, DirEntry};
8#[doc(inline)]
9pub use crate::fs::file::{CloneError, CloseError, MetadataError, OpenError};
10use crate::fs::{Abs, Fd, FileType, Metadata, OwnedPath, Path, Rel};
11use crate::util;
12
13use super::BUFFER_SIZE;
14
15pub(crate) const DEF_DIR_MODE: c_int = 0o777;
16
17// TODO: This might be better placed in an env module or something.
18/// A special constant [`Directory`] that always represents to current directory of the process. Can
19/// be passed to functions in place of a manually opened `Directory` to indicate that the operation
20/// should use the process's cwd.
21pub const CWD: Directory = Directory {
22    fd: Fd(libc::AT_FDCWD),
23};
24
25/// An open directory that is guaranteed to exist for the lifetime of the `Directory`. Can also be
26/// used to obtain an iterator over each contained [`DirEntry`](super::DirEntry).
27#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Directory {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f, "Directory",
            "fd", &&self.fd)
    }
}Debug)]
28pub struct Directory {
29    pub(crate) fd: Fd,
30}
31
32impl Directory {
33    // TODO: Fix dir_path, file_path naming scheme to path and parent_path
34    pub fn open<P: Into<OwnedPath<Abs>>>(dir_path: P) -> Result<Directory, OpenError> {
35        match Fd::open(dir_path, O_DIRECTORY, DEF_DIR_MODE) {
36            Ok(fd) => Ok(Directory {
37                fd: fd.assert_type(FileType::Directory)?,
38            }),
39            Err(e) => Err(OpenError::interpret_raw_error(e)),
40        }
41    }
42
43    pub fn open_rel<P: Into<OwnedPath<Rel>>>(
44        &self,
45        relative_to: &Directory,
46        dir_path: P
47    ) -> Result<Directory, OpenError> {
48        match Fd::open_rel(relative_to, dir_path, O_DIRECTORY, DEF_DIR_MODE) {
49            Ok(fd) => Ok(Directory {
50                fd: fd.assert_type(FileType::Directory)?,
51            }),
52            Err(e) => Err(OpenError::interpret_raw_error(e)),
53        }
54    }
55
56    pub fn open_dir_entry(&self, dir_ent: &DirEntry) -> Result<Directory, OpenError> {
57        // TODO: This could take ownership of DirEntry instead of cloning?
58        self.open_rel(dir_ent.parent, dir_ent.path.clone())
59    }
60
61    pub fn create<P: AsRef<Path<Abs>>>(
62        dir_path: P,
63        file_mode: u16
64    ) -> Result<Directory, RawOsError> {
65        let pathname = CString::from(dir_path.as_ref().to_owned());
66
67        // SAFETY: pathname.as_ptr() is a valid pointer to a null-terminated C string for the
68        // lifetime of `pathname`. CString guarantees no interior null bytes. file_mode is cast to
69        // the appropriate type for the mode parameter.
70        match unsafe { libc::mkdir(pathname.as_ptr().cast(), file_mode as mode_t) } {
71            -1 => Err(util::fs::err_no()), // TODO: interpret raw error
72            fd => Ok(Directory {
73                fd: Fd(fd),
74            }),
75        }
76    }
77
78    pub fn read_entries<'a>(&'a self) -> DirEntries<'a> {
79        let buf = Array::new_uninit(BUFFER_SIZE);
80        DirEntries {
81            dir: self,
82            head: buf.ptr,
83            buf,
84            rem: 0,
85        }
86    }
87
88    pub fn metadata(&self) -> Result<Metadata, MetadataError> {
89        self.fd.metadata()
90    }
91
92    pub fn close(self) -> Result<(), CloseError> {
93        self.fd.close()
94    }
95
96    pub fn try_clone(&self) -> Result<Directory, CloneError> {
97        self.fd.try_clone().map(|new_fd| Directory {
98            fd: new_fd,
99        })
100    }
101}