1use axerrno::{AxError, AxResult, ax_err, ax_err_type};
4use axfs_vfs::{VfsError, VfsNodeRef};
5use axio::SeekFrom;
6use cap_access::{Cap, WithCap};
7use core::fmt;
8
9#[cfg(feature = "myfs")]
10pub use crate::dev::Disk;
11#[cfg(feature = "myfs")]
12pub use crate::fs::myfs::MyFileSystemIf;
13
14pub type FileType = axfs_vfs::VfsNodeType;
16pub type DirEntry = axfs_vfs::VfsDirEntry;
18pub type FileAttr = axfs_vfs::VfsNodeAttr;
20pub type FilePerm = axfs_vfs::VfsNodePerm;
22
23pub struct File {
25 node: WithCap<VfsNodeRef>,
26 is_append: bool,
27 offset: u64,
28}
29
30pub struct Directory {
33 node: WithCap<VfsNodeRef>,
34 entry_idx: usize,
35}
36
37#[derive(Clone)]
39pub struct OpenOptions {
40 read: bool,
42 write: bool,
43 append: bool,
44 truncate: bool,
45 create: bool,
46 create_new: bool,
47 _custom_flags: i32,
49 _mode: u32,
50}
51
52impl Default for OpenOptions {
53 fn default() -> Self {
54 Self::new()
55 }
56}
57
58impl OpenOptions {
59 pub const fn new() -> Self {
61 Self {
62 read: false,
64 write: false,
65 append: false,
66 truncate: false,
67 create: false,
68 create_new: false,
69 _custom_flags: 0,
71 _mode: 0o666,
72 }
73 }
74 pub fn read(&mut self, read: bool) {
76 self.read = read;
77 }
78 pub fn write(&mut self, write: bool) {
80 self.write = write;
81 }
82 pub fn append(&mut self, append: bool) {
84 self.append = append;
85 }
86 pub fn truncate(&mut self, truncate: bool) {
88 self.truncate = truncate;
89 }
90 pub fn create(&mut self, create: bool) {
92 self.create = create;
93 }
94 pub fn create_new(&mut self, create_new: bool) {
96 self.create_new = create_new;
97 }
98
99 const fn is_valid(&self) -> bool {
100 if !self.read && !self.write && !self.append {
101 return false;
102 }
103 match (self.write, self.append) {
104 (true, false) => {}
105 (false, false) => {
106 if self.truncate || self.create || self.create_new {
107 return false;
108 }
109 }
110 (_, true) => {
111 if self.truncate && !self.create_new {
112 return false;
113 }
114 }
115 }
116 true
117 }
118}
119
120impl File {
121 fn access_node(&self, cap: Cap) -> AxResult<&VfsNodeRef> {
122 self.node.access_or_err(cap, AxError::PermissionDenied)
123 }
124
125 fn _open_at(dir: Option<&VfsNodeRef>, path: &str, opts: &OpenOptions) -> AxResult<Self> {
126 debug!("open file: {} {:?}", path, opts);
127 if !opts.is_valid() {
128 return ax_err!(InvalidInput);
129 }
130
131 let node_option = crate::root::lookup(dir, path);
132 let node = if opts.create || opts.create_new {
133 match node_option {
134 Ok(node) => {
135 if opts.create_new {
137 return ax_err!(AlreadyExists);
138 }
139 node
140 }
141 Err(VfsError::NotFound) => crate::root::create_file(dir, path)?,
143 Err(e) => return Err(e),
144 }
145 } else {
146 node_option?
148 };
149
150 let attr = node.get_attr()?;
151 if attr.is_dir()
152 && (opts.create || opts.create_new || opts.write || opts.append || opts.truncate)
153 {
154 return ax_err!(IsADirectory);
155 }
156 let access_cap = opts.into();
157 if !perm_to_cap(attr.perm()).contains(access_cap) {
158 return ax_err!(PermissionDenied);
159 }
160
161 node.open()?;
162 if opts.truncate {
163 node.truncate(0)?;
164 }
165 Ok(Self {
166 node: WithCap::new(node, access_cap),
167 is_append: opts.append,
168 offset: 0,
169 })
170 }
171
172 pub fn open(path: &str, opts: &OpenOptions) -> AxResult<Self> {
175 Self::_open_at(None, path, opts)
176 }
177
178 pub fn truncate(&self, size: u64) -> AxResult {
180 self.access_node(Cap::WRITE)?.truncate(size)?;
181 Ok(())
182 }
183
184 pub fn read(&mut self, buf: &mut [u8]) -> AxResult<usize> {
189 let node = self.access_node(Cap::READ)?;
190 let read_len = node.read_at(self.offset, buf)?;
191 self.offset += read_len as u64;
192 Ok(read_len)
193 }
194
195 pub fn read_at(&self, offset: u64, buf: &mut [u8]) -> AxResult<usize> {
199 let node = self.access_node(Cap::READ)?;
200 let read_len = node.read_at(offset, buf)?;
201 Ok(read_len)
202 }
203
204 pub fn write(&mut self, buf: &[u8]) -> AxResult<usize> {
210 let offset = if self.is_append {
211 self.get_attr()?.size()
212 } else {
213 self.offset
214 };
215 let node = self.access_node(Cap::WRITE)?;
216 let write_len = node.write_at(offset, buf)?;
217 self.offset = offset + write_len as u64;
218 Ok(write_len)
219 }
220
221 pub fn write_at(&self, offset: u64, buf: &[u8]) -> AxResult<usize> {
226 let node = self.access_node(Cap::WRITE)?;
227 let write_len = node.write_at(offset, buf)?;
228 Ok(write_len)
229 }
230
231 pub fn flush(&self) -> AxResult {
233 self.access_node(Cap::WRITE)?.fsync()?;
234 Ok(())
235 }
236
237 pub fn seek(&mut self, pos: SeekFrom) -> AxResult<u64> {
240 let size = self.get_attr()?.size();
241 let new_offset = match pos {
242 SeekFrom::Start(pos) => Some(pos),
243 SeekFrom::Current(off) => self.offset.checked_add_signed(off),
244 SeekFrom::End(off) => size.checked_add_signed(off),
245 }
246 .ok_or_else(|| ax_err_type!(InvalidInput))?;
247 self.offset = new_offset;
248 Ok(new_offset)
249 }
250
251 pub fn get_attr(&self) -> AxResult<FileAttr> {
253 self.access_node(Cap::empty())?.get_attr()
254 }
255}
256
257impl Directory {
258 fn access_node(&self, cap: Cap) -> AxResult<&VfsNodeRef> {
259 self.node.access_or_err(cap, AxError::PermissionDenied)
260 }
261
262 fn _open_dir_at(dir: Option<&VfsNodeRef>, path: &str, opts: &OpenOptions) -> AxResult<Self> {
263 debug!("open dir: {}", path);
264 if !opts.read {
265 return ax_err!(InvalidInput);
266 }
267 if opts.create || opts.create_new || opts.write || opts.append || opts.truncate {
268 return ax_err!(InvalidInput);
269 }
270
271 let node = crate::root::lookup(dir, path)?;
272 let attr = node.get_attr()?;
273 if !attr.is_dir() {
274 return ax_err!(NotADirectory);
275 }
276 let access_cap = opts.into();
277 if !perm_to_cap(attr.perm()).contains(access_cap) {
278 return ax_err!(PermissionDenied);
279 }
280
281 node.open()?;
282 Ok(Self {
283 node: WithCap::new(node, access_cap),
284 entry_idx: 0,
285 })
286 }
287
288 fn access_at(&self, path: &str) -> AxResult<Option<&VfsNodeRef>> {
289 if path.starts_with('/') {
290 Ok(None)
291 } else {
292 Ok(Some(self.access_node(Cap::EXECUTE)?))
293 }
294 }
295
296 pub fn open_dir(path: &str, opts: &OpenOptions) -> AxResult<Self> {
299 Self::_open_dir_at(None, path, opts)
300 }
301
302 pub fn open_dir_at(&self, path: &str, opts: &OpenOptions) -> AxResult<Self> {
305 Self::_open_dir_at(self.access_at(path)?, path, opts)
306 }
307
308 pub fn open_file_at(&self, path: &str, opts: &OpenOptions) -> AxResult<File> {
311 File::_open_at(self.access_at(path)?, path, opts)
312 }
313
314 pub fn create_file(&self, path: &str) -> AxResult<VfsNodeRef> {
316 crate::root::create_file(self.access_at(path)?, path)
317 }
318
319 pub fn create_dir(&self, path: &str) -> AxResult {
321 crate::root::create_dir(self.access_at(path)?, path)
322 }
323
324 pub fn remove_file(&self, path: &str) -> AxResult {
326 crate::root::remove_file(self.access_at(path)?, path)
327 }
328
329 pub fn remove_dir(&self, path: &str) -> AxResult {
331 crate::root::remove_dir(self.access_at(path)?, path)
332 }
333
334 pub fn read_dir(&mut self, dirents: &mut [DirEntry]) -> AxResult<usize> {
340 let n = self
341 .access_node(Cap::READ)?
342 .read_dir(self.entry_idx, dirents)?;
343 self.entry_idx += n;
344 Ok(n)
345 }
346
347 pub fn rename(&self, old: &str, new: &str) -> AxResult {
352 crate::root::rename(old, new)
353 }
354}
355
356impl Drop for File {
357 fn drop(&mut self) {
358 unsafe { self.node.access_unchecked().release().ok() };
359 }
360}
361
362impl Drop for Directory {
363 fn drop(&mut self) {
364 unsafe { self.node.access_unchecked().release().ok() };
365 }
366}
367
368impl fmt::Debug for OpenOptions {
369 #[allow(unused_assignments)]
370 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371 let mut written = false;
372 macro_rules! fmt_opt {
373 ($field: ident, $label: literal) => {
374 if self.$field {
375 if written {
376 write!(f, " | ")?;
377 }
378 write!(f, $label)?;
379 written = true;
380 }
381 };
382 }
383 fmt_opt!(read, "READ");
384 fmt_opt!(write, "WRITE");
385 fmt_opt!(append, "APPEND");
386 fmt_opt!(truncate, "TRUNC");
387 fmt_opt!(create, "CREATE");
388 fmt_opt!(create_new, "CREATE_NEW");
389 Ok(())
390 }
391}
392
393impl From<&OpenOptions> for Cap {
394 fn from(opts: &OpenOptions) -> Cap {
395 let mut cap = Cap::empty();
396 if opts.read {
397 cap |= Cap::READ;
398 }
399 if opts.write | opts.append {
400 cap |= Cap::WRITE;
401 }
402 cap
403 }
404}
405
406fn perm_to_cap(perm: FilePerm) -> Cap {
407 let mut cap = Cap::empty();
408 if perm.owner_readable() {
409 cap |= Cap::READ;
410 }
411 if perm.owner_writable() {
412 cap |= Cap::WRITE;
413 }
414 if perm.owner_executable() {
415 cap |= Cap::EXECUTE;
416 }
417 cap
418}