1use alloc::string::String;
2use axio::Result;
3use core::fmt;
4
5use super::FileType;
6use crate::fops;
7
8pub 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
18pub struct DirEntry<'a> {
20 dir_path: &'a str,
21 entry_name: String,
22 entry_type: FileType,
23}
24
25#[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 pub fn path(&self) -> String {
98 String::from(self.dir_path.trim_end_matches('/')) + "/" + &self.entry_name
99 }
100
101 pub fn file_name(&self) -> String {
104 self.entry_name.clone()
105 }
106
107 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 pub fn new() -> Self {
123 Self { recursive: false }
124 }
125
126 pub fn recursive(&mut self, recursive: bool) -> &mut Self {
130 self.recursive = recursive;
131 self
132 }
133
134 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}