starry_api/file/
fs.rs

1use core::{any::Any, ffi::c_int};
2
3use alloc::{string::String, sync::Arc};
4use axerrno::{LinuxError, LinuxResult};
5use axfs::fops::DirEntry;
6use axio::PollState;
7use axsync::{Mutex, MutexGuard};
8use linux_raw_sys::general::S_IFDIR;
9
10use super::{FileLike, Kstat, get_file_like};
11
12/// File wrapper for `axfs::fops::File`.
13pub struct File {
14    inner: Mutex<axfs::fops::File>,
15    path: String,
16}
17
18impl File {
19    pub fn new(inner: axfs::fops::File, path: String) -> Self {
20        Self {
21            inner: Mutex::new(inner),
22            path,
23        }
24    }
25
26    /// Get the path of the file.
27    pub fn path(&self) -> &str {
28        &self.path
29    }
30
31    /// Get the inner node of the file.
32    pub fn inner(&self) -> MutexGuard<axfs::fops::File> {
33        self.inner.lock()
34    }
35}
36
37impl FileLike for File {
38    fn read(&self, buf: &mut [u8]) -> LinuxResult<usize> {
39        Ok(self.inner().read(buf)?)
40    }
41
42    fn write(&self, buf: &[u8]) -> LinuxResult<usize> {
43        Ok(self.inner().write(buf)?)
44    }
45
46    fn stat(&self) -> LinuxResult<Kstat> {
47        let metadata = self.inner().get_attr()?;
48        let ty = metadata.file_type() as u8;
49        let perm = metadata.perm().bits() as u32;
50
51        Ok(Kstat {
52            mode: ((ty as u32) << 12) | perm,
53            size: metadata.size(),
54            blocks: metadata.blocks(),
55            blksize: 512,
56            ..Default::default()
57        })
58    }
59
60    fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
61        self
62    }
63
64    fn poll(&self) -> LinuxResult<PollState> {
65        Ok(PollState {
66            readable: true,
67            writable: true,
68        })
69    }
70
71    fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult {
72        Ok(())
73    }
74}
75
76/// Directory wrapper for `axfs::fops::Directory`.
77pub struct Directory {
78    inner: Mutex<axfs::fops::Directory>,
79    path: String,
80    last_dirent: Mutex<Option<DirEntry>>,
81}
82
83impl Directory {
84    pub fn new(inner: axfs::fops::Directory, path: String) -> Self {
85        Self {
86            inner: Mutex::new(inner),
87            path,
88            last_dirent: Mutex::new(None),
89        }
90    }
91
92    /// Get the path of the directory.
93    pub fn path(&self) -> &str {
94        &self.path
95    }
96
97    /// Get the inner node of the directory.
98    pub fn inner(&self) -> MutexGuard<axfs::fops::Directory> {
99        self.inner.lock()
100    }
101
102    /// Get the last directory entry.
103    pub fn last_dirent(&self) -> MutexGuard<Option<DirEntry>> {
104        self.last_dirent.lock()
105    }
106}
107
108impl FileLike for Directory {
109    fn read(&self, _buf: &mut [u8]) -> LinuxResult<usize> {
110        Err(LinuxError::EBADF)
111    }
112
113    fn write(&self, _buf: &[u8]) -> LinuxResult<usize> {
114        Err(LinuxError::EBADF)
115    }
116
117    fn stat(&self) -> LinuxResult<Kstat> {
118        Ok(Kstat {
119            mode: S_IFDIR | 0o755u32, // rwxr-xr-x
120            ..Default::default()
121        })
122    }
123
124    fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
125        self
126    }
127
128    fn poll(&self) -> LinuxResult<PollState> {
129        Ok(PollState {
130            readable: true,
131            writable: false,
132        })
133    }
134
135    fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult {
136        Ok(())
137    }
138
139    fn from_fd(fd: c_int) -> LinuxResult<Arc<Self>> {
140        get_file_like(fd)?
141            .into_any()
142            .downcast::<Self>()
143            .map_err(|_| LinuxError::ENOTDIR)
144    }
145}