1use core::fmt;
18
19use ax_cap_access::{Cap, WithCap};
20use ax_errno::{AxError, AxResult, ax_err_type};
21use ax_fs_vfs::VfsNodeRef;
22use ax_io::SeekFrom;
23
24pub type FileType = ax_fs_vfs::VfsNodeType;
26pub type DirEntry = ax_fs_vfs::VfsDirEntry;
28pub type FileAttr = ax_fs_vfs::VfsNodeAttr;
30pub type FilePerm = ax_fs_vfs::VfsNodePerm;
32
33pub struct File {
35 node: WithCap<VfsNodeRef>,
36 is_append: bool,
37 offset: u64,
38}
39
40pub struct Directory {
43 node: WithCap<VfsNodeRef>,
44 entry_idx: usize,
45}
46
47#[derive(Clone)]
49pub struct OpenOptions {
50 read: bool,
52 write: bool,
53 append: bool,
54 truncate: bool,
55 create: bool,
56 create_new: bool,
57 _custom_flags: i32,
59 _mode: u32,
60}
61
62impl Default for OpenOptions {
63 fn default() -> Self {
64 Self::new()
65 }
66}
67
68impl OpenOptions {
69 pub const fn new() -> Self {
71 Self {
72 read: false,
74 write: false,
75 append: false,
76 truncate: false,
77 create: false,
78 create_new: false,
79 _custom_flags: 0,
81 _mode: 0o666,
82 }
83 }
84 pub fn read(&mut self, read: bool) {
86 self.read = read;
87 }
88 pub fn write(&mut self, write: bool) {
90 self.write = write;
91 }
92 pub fn append(&mut self, append: bool) {
94 self.append = append;
95 }
96 pub fn truncate(&mut self, truncate: bool) {
98 self.truncate = truncate;
99 }
100 pub fn create(&mut self, create: bool) {
102 self.create = create;
103 }
104 pub fn create_new(&mut self, create_new: bool) {
106 self.create_new = create_new;
107 }
108
109 const fn is_valid(&self) -> bool {
110 if !self.read && !self.write && !self.append {
111 return false;
112 }
113 match (self.write, self.append) {
114 (true, false) => {}
115 (false, false) => {
116 if self.truncate || self.create || self.create_new {
117 return false;
118 }
119 }
120 (_, true) => {
121 if self.truncate && !self.create_new {
122 return false;
123 }
124 }
125 }
126 true
127 }
128}
129
130impl File {
131 fn access_node(&self, cap: Cap) -> AxResult<&VfsNodeRef> {
132 self.node.access_or_err(cap, AxError::PermissionDenied)
133 }
134
135 fn _open_at(dir: Option<&VfsNodeRef>, path: &str, opts: &OpenOptions) -> AxResult<Self> {
136 debug!("open file: {} {:?}", path, opts);
137 if !opts.is_valid() {
138 return Err(AxError::InvalidInput);
139 }
140
141 let node_option = crate::root::lookup(dir, path);
142 let node = if opts.create || opts.create_new {
143 match node_option {
144 Ok(node) => {
145 if opts.create_new {
147 return Err(AxError::AlreadyExists);
148 }
149 node
150 }
151 Err(AxError::NotFound) => crate::root::create_file(dir, path)?,
153 Err(e) => return Err(e),
154 }
155 } else {
156 node_option?
158 };
159
160 let attr = node.get_attr()?;
161 if attr.is_dir()
162 && (opts.create || opts.create_new || opts.write || opts.append || opts.truncate)
163 {
164 return Err(AxError::IsADirectory);
165 }
166 let access_cap = opts.into();
167 if !perm_to_cap(attr.perm()).contains(access_cap) {
168 return Err(AxError::PermissionDenied);
169 }
170
171 node.open()?;
172 if opts.truncate {
173 node.truncate(0)?;
174 }
175 Ok(Self {
176 node: WithCap::new(node, access_cap),
177 is_append: opts.append,
178 offset: 0,
179 })
180 }
181
182 pub fn open(path: &str, opts: &OpenOptions) -> AxResult<Self> {
185 Self::_open_at(None, path, opts)
186 }
187
188 pub fn truncate(&self, size: u64) -> AxResult {
190 self.access_node(Cap::WRITE)?.truncate(size)?;
191 Ok(())
192 }
193
194 pub fn read(&mut self, buf: &mut [u8]) -> AxResult<usize> {
199 let node = self.access_node(Cap::READ)?;
200 let read_len = node.read_at(self.offset, buf)?;
201 self.offset += read_len as u64;
202 Ok(read_len)
203 }
204
205 pub fn read_at(&self, offset: u64, buf: &mut [u8]) -> AxResult<usize> {
209 let node = self.access_node(Cap::READ)?;
210 let read_len = node.read_at(offset, buf)?;
211 Ok(read_len)
212 }
213
214 pub fn write(&mut self, buf: &[u8]) -> AxResult<usize> {
220 let offset = if self.is_append {
221 self.get_attr()?.size()
222 } else {
223 self.offset
224 };
225 let node = self.access_node(Cap::WRITE)?;
226 let write_len = node.write_at(offset, buf)?;
227 self.offset = offset + write_len as u64;
228 Ok(write_len)
229 }
230
231 pub fn write_at(&self, offset: u64, buf: &[u8]) -> AxResult<usize> {
236 let node = self.access_node(Cap::WRITE)?;
237 let write_len = node.write_at(offset, buf)?;
238 Ok(write_len)
239 }
240
241 pub fn flush(&self) -> AxResult {
243 self.access_node(Cap::WRITE)?.fsync()?;
244 Ok(())
245 }
246
247 pub fn seek(&mut self, pos: SeekFrom) -> AxResult<u64> {
250 let size = self.get_attr()?.size();
251 let new_offset = match pos {
252 SeekFrom::Start(pos) => Some(pos),
253 SeekFrom::Current(off) => self.offset.checked_add_signed(off),
254 SeekFrom::End(off) => size.checked_add_signed(off),
255 }
256 .ok_or_else(|| ax_err_type!(InvalidInput))?;
257 self.offset = new_offset;
258 Ok(new_offset)
259 }
260
261 pub fn get_attr(&self) -> AxResult<FileAttr> {
263 self.access_node(Cap::empty())?.get_attr()
264 }
265}
266
267impl Directory {
268 fn access_node(&self, cap: Cap) -> AxResult<&VfsNodeRef> {
269 self.node.access_or_err(cap, AxError::PermissionDenied)
270 }
271
272 fn _open_dir_at(dir: Option<&VfsNodeRef>, path: &str, opts: &OpenOptions) -> AxResult<Self> {
273 debug!("open dir: {}", path);
274 if !opts.read {
275 return Err(AxError::InvalidInput);
276 }
277 if opts.create || opts.create_new || opts.write || opts.append || opts.truncate {
278 return Err(AxError::InvalidInput);
279 }
280
281 let node = crate::root::lookup(dir, path)?;
282 let attr = node.get_attr()?;
283 if !attr.is_dir() {
284 return Err(AxError::NotADirectory);
285 }
286 let access_cap = opts.into();
287 if !perm_to_cap(attr.perm()).contains(access_cap) {
288 return Err(AxError::PermissionDenied);
289 }
290
291 node.open()?;
292 Ok(Self {
293 node: WithCap::new(node, access_cap),
294 entry_idx: 0,
295 })
296 }
297
298 fn access_at(&self, path: &str) -> AxResult<Option<&VfsNodeRef>> {
299 if path.starts_with('/') {
300 Ok(None)
301 } else {
302 Ok(Some(self.access_node(Cap::EXECUTE)?))
303 }
304 }
305
306 pub fn open_dir(path: &str, opts: &OpenOptions) -> AxResult<Self> {
309 Self::_open_dir_at(None, path, opts)
310 }
311
312 pub fn open_dir_at(&self, path: &str, opts: &OpenOptions) -> AxResult<Self> {
315 Self::_open_dir_at(self.access_at(path)?, path, opts)
316 }
317
318 pub fn open_file_at(&self, path: &str, opts: &OpenOptions) -> AxResult<File> {
321 File::_open_at(self.access_at(path)?, path, opts)
322 }
323
324 pub fn create_file(&self, path: &str) -> AxResult<VfsNodeRef> {
326 crate::root::create_file(self.access_at(path)?, path)
327 }
328
329 pub fn create_dir(&self, path: &str) -> AxResult {
331 crate::root::create_dir(self.access_at(path)?, path)
332 }
333
334 pub fn remove_file(&self, path: &str) -> AxResult {
336 crate::root::remove_file(self.access_at(path)?, path)
337 }
338
339 pub fn remove_dir(&self, path: &str) -> AxResult {
341 crate::root::remove_dir(self.access_at(path)?, path)
342 }
343
344 pub fn read_dir(&mut self, dirents: &mut [DirEntry]) -> AxResult<usize> {
350 let n = self
351 .access_node(Cap::READ)?
352 .read_dir(self.entry_idx, dirents)?;
353 self.entry_idx += n;
354 Ok(n)
355 }
356
357 pub fn rename(&self, old: &str, new: &str) -> AxResult {
362 crate::root::rename(old, new)
363 }
364}
365
366impl Drop for File {
367 fn drop(&mut self) {
368 unsafe { self.node.access_unchecked().release().ok() };
369 }
370}
371
372impl Drop for Directory {
373 fn drop(&mut self) {
374 unsafe { self.node.access_unchecked().release().ok() };
375 }
376}
377
378impl fmt::Debug for OpenOptions {
379 #[allow(unused_assignments)]
380 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
381 let mut written = false;
382 macro_rules! fmt_opt {
383 ($field:ident, $label:literal) => {
384 if self.$field {
385 if written {
386 write!(f, " | ")?;
387 }
388 write!(f, $label)?;
389 written = true;
390 }
391 };
392 }
393 fmt_opt!(read, "READ");
394 fmt_opt!(write, "WRITE");
395 fmt_opt!(append, "APPEND");
396 fmt_opt!(truncate, "TRUNC");
397 fmt_opt!(create, "CREATE");
398 fmt_opt!(create_new, "CREATE_NEW");
399 Ok(())
400 }
401}
402
403impl From<&OpenOptions> for Cap {
404 fn from(opts: &OpenOptions) -> Cap {
405 let mut cap = Cap::empty();
406 if opts.read {
407 cap |= Cap::READ;
408 }
409 if opts.write | opts.append {
410 cap |= Cap::WRITE;
411 }
412 cap
413 }
414}
415
416fn perm_to_cap(perm: FilePerm) -> Cap {
417 let mut cap = Cap::empty();
418 if perm.owner_readable() {
419 cap |= Cap::READ;
420 }
421 if perm.owner_writable() {
422 cap |= Cap::WRITE;
423 }
424 if perm.owner_executable() {
425 cap |= Cap::EXECUTE;
426 }
427 cap
428}