arceos_posix_api/imp/
fs.rs1use alloc::sync::Arc;
2use core::ffi::{c_char, c_int};
3
4use axerrno::{LinuxError, LinuxResult};
5use axfs::fops::OpenOptions;
6use axio::{PollState, SeekFrom};
7use axsync::Mutex;
8
9use super::fd_ops::{FileLike, get_file_like};
10use crate::{ctypes, utils::char_ptr_to_str};
11
12pub struct File {
13 inner: Mutex<axfs::fops::File>,
14}
15
16impl File {
17 fn new(inner: axfs::fops::File) -> Self {
18 Self {
19 inner: Mutex::new(inner),
20 }
21 }
22
23 fn add_to_fd_table(self) -> LinuxResult<c_int> {
24 super::fd_ops::add_file_like(Arc::new(self))
25 }
26
27 fn from_fd(fd: c_int) -> LinuxResult<Arc<Self>> {
28 let f = super::fd_ops::get_file_like(fd)?;
29 f.into_any()
30 .downcast::<Self>()
31 .map_err(|_| LinuxError::EINVAL)
32 }
33}
34
35impl FileLike for File {
36 fn read(&self, buf: &mut [u8]) -> LinuxResult<usize> {
37 Ok(self.inner.lock().read(buf)?)
38 }
39
40 fn write(&self, buf: &[u8]) -> LinuxResult<usize> {
41 Ok(self.inner.lock().write(buf)?)
42 }
43
44 fn stat(&self) -> LinuxResult<ctypes::stat> {
45 let metadata = self.inner.lock().get_attr()?;
46 let ty = metadata.file_type() as u8;
47 let perm = metadata.perm().bits() as u32;
48 let st_mode = ((ty as u32) << 12) | perm;
49 Ok(ctypes::stat {
50 st_ino: 1,
51 st_nlink: 1,
52 st_mode,
53 st_uid: 1000,
54 st_gid: 1000,
55 st_size: metadata.size() as _,
56 st_blocks: metadata.blocks() as _,
57 st_blksize: 512,
58 ..Default::default()
59 })
60 }
61
62 fn into_any(self: Arc<Self>) -> Arc<dyn core::any::Any + Send + Sync> {
63 self
64 }
65
66 fn poll(&self) -> LinuxResult<PollState> {
67 Ok(PollState {
68 readable: true,
69 writable: true,
70 })
71 }
72
73 fn set_nonblocking(&self, _nonblocking: bool) -> LinuxResult {
74 Ok(())
75 }
76}
77
78fn flags_to_options(flags: c_int, _mode: ctypes::mode_t) -> OpenOptions {
80 let flags = flags as u32;
81 let mut options = OpenOptions::new();
82 match flags & 0b11 {
83 ctypes::O_RDONLY => options.read(true),
84 ctypes::O_WRONLY => options.write(true),
85 _ => {
86 options.read(true);
87 options.write(true);
88 }
89 };
90 if flags & ctypes::O_APPEND != 0 {
91 options.append(true);
92 }
93 if flags & ctypes::O_TRUNC != 0 {
94 options.truncate(true);
95 }
96 if flags & ctypes::O_CREAT != 0 {
97 options.create(true);
98 }
99 if flags & ctypes::O_EXEC != 0 {
100 options.create_new(true);
101 }
102 options
103}
104
105pub fn sys_open(filename: *const c_char, flags: c_int, mode: ctypes::mode_t) -> c_int {
110 let filename = char_ptr_to_str(filename);
111 debug!("sys_open <= {:?} {:#o} {:#o}", filename, flags, mode);
112 syscall_body!(sys_open, {
113 let options = flags_to_options(flags, mode);
114 let file = axfs::fops::File::open(filename?, &options)?;
115 File::new(file).add_to_fd_table()
116 })
117}
118
119pub fn sys_lseek(fd: c_int, offset: ctypes::off_t, whence: c_int) -> ctypes::off_t {
123 debug!("sys_lseek <= {} {} {}", fd, offset, whence);
124 syscall_body!(sys_lseek, {
125 let pos = match whence {
126 0 => SeekFrom::Start(offset as _),
127 1 => SeekFrom::Current(offset as _),
128 2 => SeekFrom::End(offset as _),
129 _ => return Err(LinuxError::EINVAL),
130 };
131 let off = File::from_fd(fd)?.inner.lock().seek(pos)?;
132 Ok(off)
133 })
134}
135
136pub unsafe fn sys_stat(path: *const c_char, buf: *mut ctypes::stat) -> c_int {
140 let path = char_ptr_to_str(path);
141 debug!("sys_stat <= {:?} {:#x}", path, buf as usize);
142 syscall_body!(sys_stat, {
143 if buf.is_null() {
144 return Err(LinuxError::EFAULT);
145 }
146 let mut options = OpenOptions::new();
147 options.read(true);
148 let file = axfs::fops::File::open(path?, &options)?;
149 let st = File::new(file).stat()?;
150 unsafe { *buf = st };
151 Ok(0)
152 })
153}
154
155pub unsafe fn sys_fstat(fd: c_int, buf: *mut ctypes::stat) -> c_int {
159 debug!("sys_fstat <= {} {:#x}", fd, buf as usize);
160 syscall_body!(sys_fstat, {
161 if buf.is_null() {
162 return Err(LinuxError::EFAULT);
163 }
164
165 unsafe { *buf = get_file_like(fd)?.stat()? };
166 Ok(0)
167 })
168}
169
170pub unsafe fn sys_lstat(path: *const c_char, buf: *mut ctypes::stat) -> ctypes::ssize_t {
174 let path = char_ptr_to_str(path);
175 debug!("sys_lstat <= {:?} {:#x}", path, buf as usize);
176 syscall_body!(sys_lstat, {
177 if buf.is_null() {
178 return Err(LinuxError::EFAULT);
179 }
180 unsafe { *buf = Default::default() }; Ok(0)
182 })
183}
184
185#[allow(clippy::unnecessary_cast)] pub fn sys_getcwd(buf: *mut c_char, size: usize) -> *mut c_char {
188 debug!("sys_getcwd <= {:#x} {}", buf as usize, size);
189 syscall_body!(sys_getcwd, {
190 if buf.is_null() {
191 return Ok(core::ptr::null::<c_char>() as _);
192 }
193 let dst = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, size as _) };
194 let cwd = axfs::api::current_dir()?;
195 let cwd = cwd.as_bytes();
196 if cwd.len() < size {
197 dst[..cwd.len()].copy_from_slice(cwd);
198 dst[cwd.len()] = 0;
199 Ok(buf)
200 } else {
201 Err(LinuxError::ERANGE)
202 }
203 })
204}
205
206pub fn sys_rename(old: *const c_char, new: *const c_char) -> c_int {
211 syscall_body!(sys_rename, {
212 let old_path = char_ptr_to_str(old)?;
213 let new_path = char_ptr_to_str(new)?;
214 debug!("sys_rename <= old: {:?}, new: {:?}", old_path, new_path);
215 axfs::api::rename(old_path, new_path)?;
216 Ok(0)
217 })
218}