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
11pub 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
21pub struct DirEntry<'a> {
23 dir_path: &'a str,
24 entry_name: String,
25 entry_type: FileType,
26}
27
28#[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 pub fn path(&self) -> String {
102 String::from(self.dir_path.trim_end_matches('/')) + "/" + &self.entry_name
103 }
104
105 pub fn file_name(&self) -> String {
108 self.entry_name.clone()
109 }
110
111 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 pub fn new() -> Self {
127 Self { recursive: false }
128 }
129
130 pub fn recursive(&mut self, recursive: bool) -> &mut Self {
134 self.recursive = recursive;
135 self
136 }
137
138 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}