axstd/fs/
dir.rs

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