1use alloc::string::String;
16use core::fmt;
17
18use ax_io::Result;
19
20use super::FileType;
21use crate::fops;
22
23pub struct ReadDir<'a> {
25 path: &'a str,
26 inner: fops::Directory,
27 buf_pos: usize,
28 buf_end: usize,
29 end_of_stream: bool,
30 dirent_buf: [fops::DirEntry; 31],
31}
32
33pub struct DirEntry<'a> {
35 dir_path: &'a str,
36 entry_name: String,
37 entry_type: FileType,
38}
39
40#[derive(Default, Debug)]
42pub struct DirBuilder {
43 recursive: bool,
44}
45
46impl<'a> ReadDir<'a> {
47 pub(super) fn new(path: &'a str) -> Result<Self> {
48 let mut opts = fops::OpenOptions::new();
49 opts.read(true);
50 let inner = fops::Directory::open_dir(path, &opts)?;
51 const EMPTY: fops::DirEntry = fops::DirEntry::default();
52 let dirent_buf = [EMPTY; 31];
53 Ok(ReadDir {
54 path,
55 inner,
56 end_of_stream: false,
57 buf_pos: 0,
58 buf_end: 0,
59 dirent_buf,
60 })
61 }
62}
63
64impl<'a> Iterator for ReadDir<'a> {
65 type Item = Result<DirEntry<'a>>;
66
67 fn next(&mut self) -> Option<Result<DirEntry<'a>>> {
68 if self.end_of_stream {
69 return None;
70 }
71
72 loop {
73 if self.buf_pos >= self.buf_end {
74 match self.inner.read_dir(&mut self.dirent_buf) {
75 Ok(n) => {
76 if n == 0 {
77 self.end_of_stream = true;
78 return None;
79 }
80 self.buf_pos = 0;
81 self.buf_end = n;
82 }
83 Err(e) => {
84 self.end_of_stream = true;
85 return Some(Err(e));
86 }
87 }
88 }
89 let entry = &self.dirent_buf[self.buf_pos];
90 self.buf_pos += 1;
91 let name_bytes = entry.name_as_bytes();
92 if name_bytes == b"." || name_bytes == b".." {
93 continue;
94 }
95 let entry_name = unsafe { core::str::from_utf8_unchecked(name_bytes).into() };
96 let entry_type = entry.entry_type();
97
98 return Some(Ok(DirEntry {
99 dir_path: self.path,
100 entry_name,
101 entry_type,
102 }));
103 }
104 }
105}
106
107impl DirEntry<'_> {
108 pub fn path(&self) -> String {
113 String::from(self.dir_path.trim_end_matches('/')) + "/" + &self.entry_name
114 }
115
116 pub fn file_name(&self) -> String {
119 self.entry_name.clone()
120 }
121
122 pub fn file_type(&self) -> FileType {
124 self.entry_type
125 }
126}
127
128impl fmt::Debug for DirEntry<'_> {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 f.debug_tuple("DirEntry").field(&self.path()).finish()
131 }
132}
133
134impl DirBuilder {
135 pub fn new() -> Self {
138 Self { recursive: false }
139 }
140
141 pub fn recursive(&mut self, recursive: bool) -> &mut Self {
145 self.recursive = recursive;
146 self
147 }
148
149 pub fn create(&self, path: &str) -> Result<()> {
152 if self.recursive {
153 self.create_dir_all(path)
154 } else {
155 crate::root::create_dir(None, path)
156 }
157 }
158
159 fn create_dir_all(&self, _path: &str) -> Result<()> {
160 Err(ax_errno::AxError::Unsupported)
161 }
162}