standard_lib/fs/dir/
dir.rs

1use std::ffi::CString;
2use std::io::RawOsError;
3
4use libc::{O_DIRECTORY, c_int};
5
6use crate::collections::contiguous::Array;
7use crate::fs::dir::DirEntries;
8use crate::fs::file::{CloneError, CloseError, MetadataError};
9use crate::fs::path::{Abs, Path};
10use crate::fs::{Fd, Metadata};
11use crate::util;
12
13use super::BUFFER_SIZE;
14
15// TODO: Verify that all ..at syscalls support this constant.
16// TODO: This might be better placed in an env module or something.
17/// A special constant [`Directory`] that always represents to current directory of the process. Can
18/// be passed to functions in place of a manually opened `Directory` to indicate that the operation
19/// should use the process's cwd.
20pub const CWD: Directory = Directory {
21    fd: Fd(libc::AT_FDCWD),
22};
23
24/// An open directory that is guaranteed to exist for the lifetime of the `Directory`. Can also be
25/// used to obtain an iterator over each contained [`DirEntry`](super::DirEntry).
26#[derive(Debug)]
27pub struct Directory {
28    pub(crate) fd: Fd,
29}
30
31impl Directory {
32    pub fn open<P: AsRef<Path<Abs>>>(dir_path: P) -> Result<Directory, RawOsError> {
33        let pathname = CString::from(dir_path.as_ref().to_owned());
34
35        let flags: c_int = O_DIRECTORY; // Can't open as O_PATH because we need to read entries.
36
37        match unsafe { libc::open(pathname.as_ptr().cast(), flags) } {
38            -1 => Err(util::fs::err_no()),
39            fd => Ok(Directory {
40                fd: Fd(fd),
41            }),
42        }
43    }
44
45    // pub fn create<P: AsRef<Path<Abs>>>(dir_path: P) -> Result<Directory, RawOsError>;
46
47    // TODO: relative open/create variants.
48
49    pub fn read_entries<'a>(&'a self) -> DirEntries<'a> {
50        let buf = Array::new_uninit(BUFFER_SIZE);
51        DirEntries {
52            dir: self,
53            head: buf.ptr,
54            buf,
55            rem: 0,
56        }
57    }
58
59    pub fn metadata(&self) -> Result<Metadata, MetadataError> {
60        self.fd.metadata()
61    }
62
63    pub fn close(self) -> Result<(), CloseError> {
64        self.fd.close()
65    }
66
67    pub fn try_clone(&self) -> Result<Directory, CloneError> {
68        self.fd.try_clone().map(|new_fd| Directory {
69            fd: new_fd,
70        })
71    }
72}