axfs/api/
dir.rs

1use alloc::string::String;
2use axio::Result;
3use core::fmt;
4
5use super::FileType;
6use crate::fops;
7
8/// Iterator over the entries in a directory.
9pub struct ReadDir<'a> {
10    path: &'a str,
11    inner: fops::Directory,
12    buf_pos: usize,
13    buf_end: usize,
14    end_of_stream: bool,
15    dirent_buf: [fops::DirEntry; 31],
16}
17
18/// Entries returned by the [`ReadDir`] iterator.
19pub struct DirEntry<'a> {
20    dir_path: &'a str,
21    entry_name: String,
22    entry_type: FileType,
23}
24
25/// A builder used to create directories in various manners.
26#[derive(Default, Debug)]
27pub struct DirBuilder {
28    recursive: bool,
29}
30
31impl<'a> ReadDir<'a> {
32    pub(super) fn new(path: &'a str) -> Result<Self> {
33        let mut opts = fops::OpenOptions::new();
34        opts.read(true);
35        let inner = fops::Directory::open_dir(path, &opts)?;
36        const EMPTY: fops::DirEntry = fops::DirEntry::default();
37        let dirent_buf = [EMPTY; 31];
38        Ok(ReadDir {
39            path,
40            inner,
41            end_of_stream: false,
42            buf_pos: 0,
43            buf_end: 0,
44            dirent_buf,
45        })
46    }
47}
48
49impl<'a> Iterator for ReadDir<'a> {
50    type Item = Result<DirEntry<'a>>;
51
52    fn next(&mut self) -> Option<Result<DirEntry<'a>>> {
53        if self.end_of_stream {
54            return None;
55        }
56
57        loop {
58            if self.buf_pos >= self.buf_end {
59                match self.inner.read_dir(&mut self.dirent_buf) {
60                    Ok(n) => {
61                        if n == 0 {
62                            self.end_of_stream = true;
63                            return None;
64                        }
65                        self.buf_pos = 0;
66                        self.buf_end = n;
67                    }
68                    Err(e) => {
69                        self.end_of_stream = true;
70                        return Some(Err(e));
71                    }
72                }
73            }
74            let entry = &self.dirent_buf[self.buf_pos];
75            self.buf_pos += 1;
76            let name_bytes = entry.name_as_bytes();
77            if name_bytes == b"." || name_bytes == b".." {
78                continue;
79            }
80            let entry_name = unsafe { core::str::from_utf8_unchecked(name_bytes).into() };
81            let entry_type = entry.entry_type();
82
83            return Some(Ok(DirEntry {
84                dir_path: self.path,
85                entry_name,
86                entry_type,
87            }));
88        }
89    }
90}
91
92impl DirEntry<'_> {
93    /// Returns the full path to the file that this entry represents.
94    ///
95    /// The full path is created by joining the original path to `read_dir`
96    /// with the filename of this entry.
97    pub fn path(&self) -> String {
98        String::from(self.dir_path.trim_end_matches('/')) + "/" + &self.entry_name
99    }
100
101    /// Returns the bare file name of this directory entry without any other
102    /// leading path component.
103    pub fn file_name(&self) -> String {
104        self.entry_name.clone()
105    }
106
107    /// Returns the file type for the file that this entry points at.
108    pub fn file_type(&self) -> FileType {
109        self.entry_type
110    }
111}
112
113impl fmt::Debug for DirEntry<'_> {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        f.debug_tuple("DirEntry").field(&self.path()).finish()
116    }
117}
118
119impl DirBuilder {
120    /// Creates a new set of options with default mode/security settings for all
121    /// platforms and also non-recursive.
122    pub fn new() -> Self {
123        Self { recursive: false }
124    }
125
126    /// Indicates that directories should be created recursively, creating all
127    /// parent directories. Parents that do not exist are created with the same
128    /// security and permissions settings.
129    pub fn recursive(&mut self, recursive: bool) -> &mut Self {
130        self.recursive = recursive;
131        self
132    }
133
134    /// Creates the specified directory with the options configured in this
135    /// builder.
136    pub fn create(&self, path: &str) -> Result<()> {
137        if self.recursive {
138            self.create_dir_all(path)
139        } else {
140            crate::root::create_dir(None, path)
141        }
142    }
143
144    fn create_dir_all(&self, _path: &str) -> Result<()> {
145        axerrno::ax_err!(
146            Unsupported,
147            "Recursive directory creation is not supported yet"
148        )
149    }
150}