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(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        match unsafe { libc::mkdir(pathname.as_ptr().cast(), file_mode as mode_t) } {
68            -1 => Err(util::fs::err_no()), // TODO: interpret raw error
69            fd => Ok(Directory {
70                fd: Fd(fd),
71            }),
72        }
73    }
74
75    pub fn read_entries<'a>(&'a self) -> DirEntries<'a> {
76        let buf = Array::new_uninit(BUFFER_SIZE);
77        DirEntries {
78            dir: self,
79            head: buf.ptr,
80            buf,
81            rem: 0,
82        }
83    }
84
85    pub fn metadata(&self) -> Result<Metadata, MetadataError> {
86        self.fd.metadata()
87    }
88
89    pub fn close(self) -> Result<(), CloseError> {
90        self.fd.close()
91    }
92
93    pub fn try_clone(&self) -> Result<Directory, CloneError> {
94        self.fd.try_clone().map(|new_fd| Directory {
95            fd: new_fd,
96        })
97    }
98}