xref: /DragonOS/kernel/src/filesystem/vfs/syscall.rs (revision 676b8ef62e1a0a1e52d65b40c53c1636a2954040)
1 use core::ffi::{c_char, CStr};
2 
3 use alloc::{boxed::Box, string::ToString};
4 
5 use crate::{
6     arch::asm::{current::current_pcb, ptrace::user_mode},
7     include::bindings::bindings::{
8         pt_regs, verify_area, AT_REMOVEDIR, PAGE_2M_SIZE, PAGE_4K_SIZE, PROC_MAX_FD_NUM, SEEK_CUR, SEEK_END, SEEK_MAX, SEEK_SET,
9     },
10     io::SeekFrom,
11     kerror, syscall::SystemError,
12 };
13 
14 use super::{
15     core::{do_lseek, do_mkdir, do_open, do_read, do_remove_dir, do_unlink_at, do_write},
16     file::{File, FileMode},
17     Dirent, FileType, ROOT_INODE,
18 };
19 
20 /// @brief 打开文件
21 ///
22 /// @param regs->r8 path 文件路径
23 /// @param regs->r9 o_flags 打开文件的标志位
24 ///
25 /// @return u64 文件描述符编号,或者是错误码
26 #[no_mangle]
27 pub extern "C" fn sys_open(regs: &pt_regs) -> u64 {
28     let path: &CStr = unsafe { CStr::from_ptr(regs.r8 as usize as *const c_char) };
29     let path: Result<&str, core::str::Utf8Error> = path.to_str();
30     if path.is_err() {
31         return SystemError::EINVAL.to_posix_errno() as u64;
32     }
33     let path: &str = path.unwrap();
34     let flags = regs.r9;
35     let open_flags: FileMode = FileMode::from_bits_truncate(flags as u32);
36     let r: Result<i32, SystemError> = do_open(path, open_flags);
37 
38     if r.is_ok() {
39         return r.unwrap() as u64;
40     } else {
41         return r.unwrap_err().to_posix_errno() as u64;
42     }
43 }
44 
45 /// @brief 关闭文件的系统调用函数
46 ///
47 /// @param regs->r8 fd:文件描述符编号
48 #[no_mangle]
49 pub extern "C" fn sys_close(regs: &pt_regs) -> u64 {
50     let fd = regs.r8 as i32;
51     let r: Result<(), SystemError> = current_pcb().drop_fd(fd);
52 
53     if r.is_ok() {
54         return 0;
55     } else {
56         return r.unwrap_err().to_posix_errno() as u64;
57     }
58 }
59 
60 /// @brief 读取文件的系统调用函数
61 ///
62 /// @param regs->r8 文件描述符编号
63 /// @param regs->r9 输出缓冲区
64 /// @param regs->r10 要读取的长度
65 #[no_mangle]
66 pub extern "C" fn sys_read(regs: &pt_regs) -> u64 {
67     let fd = regs.r8 as i32;
68     let buf_vaddr = regs.r9 as usize;
69     let len = regs.r10 as usize;
70 
71     // 判断缓冲区是否来自用户态,进行权限校验
72     if user_mode(regs) && unsafe { !verify_area(buf_vaddr as u64, len as u64) } {
73         // 来自用户态,而buffer在内核态,这样的操作不被允许
74         return SystemError::EPERM.to_posix_errno() as u64;
75     }
76 
77     let buf: &mut [u8] =
78         unsafe { core::slice::from_raw_parts_mut::<'static, u8>(buf_vaddr as *mut u8, len) };
79 
80     let r: Result<usize, SystemError> = do_read(fd, buf);
81 
82     if r.is_ok() {
83         return r.unwrap() as u64;
84     } else {
85         return r.unwrap_err().to_posix_errno() as u64;
86     }
87 }
88 
89 /// @brief 向文件写入数据的系统调用函数
90 ///
91 /// @param regs->r8 文件描述符编号
92 /// @param regs->r9 输入缓冲区
93 /// @param regs->r10 要写入的长度
94 #[no_mangle]
95 pub extern "C" fn sys_write(regs: &pt_regs) -> u64 {
96     let fd = regs.r8 as i32;
97     let buf_vaddr = regs.r9 as usize;
98     let len = regs.r10 as usize;
99 
100     // 判断缓冲区是否来自用户态,进行权限校验
101     if user_mode(regs) && unsafe { !verify_area(buf_vaddr as u64, len as u64) } {
102         // 来自用户态,而buffer在内核态,这样的操作不被允许
103         return SystemError::EPERM.to_posix_errno() as u64;
104     }
105 
106     let buf: &[u8] =
107         unsafe { core::slice::from_raw_parts::<'static, u8>(buf_vaddr as *mut u8, len) };
108 
109     let r: Result<usize, SystemError> = do_write(fd, buf);
110 
111     if r.is_ok() {
112         return r.unwrap() as u64;
113     } else {
114         return r.unwrap_err().to_posix_errno() as u64;
115     }
116 }
117 
118 /// @brief 调整文件访问指针位置的系统调用函数
119 ///
120 /// @param regs->r8 文件描述符编号
121 /// @param regs->r9 调整偏移量
122 /// @param regs->r10 调整的模式
123 #[no_mangle]
124 pub extern "C" fn sys_lseek(regs: &pt_regs) -> u64 {
125     let fd = regs.r8 as i32;
126     let offset = regs.r9 as i64;
127     let whence = regs.r10 as u32;
128 
129     let w: SeekFrom = match whence {
130         SEEK_SET => SeekFrom::SeekSet(offset),
131         SEEK_CUR => SeekFrom::SeekCurrent(offset),
132         SEEK_END => SeekFrom::SeekEnd(offset),
133         SEEK_MAX => SeekFrom::SeekEnd(0),
134         _ => return SystemError::EINVAL.to_posix_errno() as u64,
135     };
136 
137     let r: Result<usize, SystemError> = do_lseek(fd, w);
138     if r.is_ok() {
139         return r.unwrap() as u64;
140     } else {
141         return r.unwrap_err().to_posix_errno() as u64;
142     }
143 }
144 
145 /// @brief 切换工作目录
146 ///
147 /// @param dest_path 目标路径
148 ///
149 /// @return   返回码  描述
150 ///      0       |          成功
151 ///
152 ///   EACCESS    |        权限不足
153 ///
154 ///    ELOOP     | 解析path时遇到路径循环
155 ///
156 /// ENAMETOOLONG |       路径名过长
157 ///
158 ///    ENOENT    |  目标文件或目录不存在
159 ///
160 ///    ENODIR    |  检索期间发现非目录项
161 ///
162 ///    ENOMEM    |      系统内存不足
163 ///
164 ///    EFAULT    |       错误的地址
165 ///
166 /// ENAMETOOLONG |        路径过长
167 #[no_mangle]
168 pub extern "C" fn sys_chdir(regs: &pt_regs) -> u64 {
169     if regs.r8 == 0 {
170         return SystemError::EFAULT.to_posix_errno() as u64;
171     }
172     let ptr = regs.r8 as usize as *const c_char;
173     // 权限校验
174     if ptr.is_null()
175         || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
176     {
177         return SystemError::EINVAL.to_posix_errno() as u64;
178     }
179 
180     let dest_path: &CStr = unsafe { CStr::from_ptr(ptr) };
181     let dest_path: Result<&str, core::str::Utf8Error> = dest_path.to_str();
182 
183     if dest_path.is_err() {
184         return SystemError::EINVAL.to_posix_errno() as u64;
185     }
186 
187     let dest_path: &str = dest_path.unwrap();
188 
189     if dest_path.len() == 0 {
190         return SystemError::EINVAL.to_posix_errno() as u64;
191     } else if dest_path.len() >= PAGE_4K_SIZE as usize {
192         return SystemError::ENAMETOOLONG.to_posix_errno() as u64;
193     }
194 
195     let path = Box::new(dest_path.clone());
196     let inode = match ROOT_INODE().lookup(&path) {
197         Err(e) => {
198             kerror!("Change Directory Failed, Error = {:?}", e);
199             return SystemError::ENOENT.to_posix_errno() as u64;
200         }
201         Ok(i) => i,
202     };
203 
204     match inode.metadata() {
205         Err(e) => {
206             kerror!("INode Get MetaData Failed, Error = {:?}", e);
207             return SystemError::ENOENT.to_posix_errno() as u64;
208         }
209         Ok(i) => {
210             if let FileType::Dir = i.file_type {
211                 return 0;
212             } else {
213                 return SystemError::ENOTDIR.to_posix_errno() as u64;
214             }
215         }
216     }
217 }
218 
219 /// @brief 获取目录中的数据
220 ///
221 /// @param fd 文件描述符号
222 /// @return uint64_t dirent的总大小
223 #[no_mangle]
224 pub extern "C" fn sys_getdents(regs: &pt_regs) -> u64 {
225     let fd = regs.r8 as i32;
226     let count = regs.r10 as i64;
227     let dirent = match unsafe { (regs.r9 as usize as *mut Dirent).as_mut() } {
228         None => {
229             return 0;
230         }
231         Some(dirent) => dirent,
232     };
233 
234     if fd < 0 || fd as u32 > PROC_MAX_FD_NUM {
235         return SystemError::EBADF.to_posix_errno() as u64;
236     }
237 
238     if count < 0 {
239         return SystemError::EINVAL.to_posix_errno() as u64;
240     }
241 
242     // 获取fd
243     let file: &mut File = match current_pcb().get_file_mut_by_fd(fd) {
244         None => {
245             return SystemError::EBADF.to_posix_errno() as u64;
246         }
247         Some(file) => file,
248     };
249     // kdebug!("file={file:?}");
250 
251     return match file.readdir(dirent) {
252         Err(_) => 0,
253         Ok(len) => len,
254     };
255 }
256 
257 /// @brief 创建文件夹
258 ///
259 /// @param path(r8) 路径 / mode(r9) 模式
260 ///
261 /// @return uint64_t 负数错误码 / 0表示成功
262 #[no_mangle]
263 pub extern "C" fn sys_mkdir(regs: &pt_regs) -> u64 {
264     let ptr = regs.r8 as usize as *const c_char;
265     if ptr.is_null()
266         || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
267     {
268         return SystemError::EINVAL.to_posix_errno() as u64;
269     }
270     let path: &CStr = unsafe { CStr::from_ptr(ptr) };
271     let path: Result<&str, core::str::Utf8Error> = path.to_str();
272     let mode = regs.r9;
273 
274     if path.is_err() {
275         return SystemError::EINVAL.to_posix_errno() as u64;
276     }
277 
278     let path = &path.unwrap().to_string();
279     if path.trim() == "" {
280         return SystemError::EINVAL.to_posix_errno() as u64;
281     }
282 
283     return match do_mkdir(&path.trim(), FileMode::from_bits_truncate(mode as u32)) {
284         Err(err) => {
285             kerror!("Failed in do_mkdir, Error Code = {:#?}", err);
286             err.to_posix_errno() as u64
287         }
288         Ok(_) => 0,
289     };
290 }
291 
292 ///@brief 删除文件夹、取消文件的链接、删除文件的系统调用
293 ///
294 ///@param regs->r8 dfd 进程相对路径基准目录的文件描述符(见fcntl.h)
295 ///
296 ///@param regs->r9 路径名称字符串
297 ///
298 ///@param regs->r10 flag 预留的标志位,暂时未使用,请置为0。
299 ///
300 ///@return uint64_t 错误码
301 #[no_mangle]
302 pub extern "C" fn sys_unlink_at(regs: &pt_regs) -> u64 {
303     let _dfd = regs.r8;
304     let ptr = regs.r9 as usize as *const c_char;
305     if ptr.is_null()
306         || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
307     {
308         return SystemError::EINVAL.to_posix_errno() as u64;
309     }
310     let path: &CStr = unsafe { CStr::from_ptr(ptr) };
311     let path: Result<&str, core::str::Utf8Error> = path.to_str();
312     let flag = regs.r10;
313     if path.is_err() {
314         return SystemError::EINVAL.to_posix_errno() as u64;
315     }
316 
317     let path = &path.unwrap().to_string();
318     // kdebug!("sys_unlink_at={path:?}");
319     if (flag & (!(AT_REMOVEDIR as u64))) != 0_u64 {
320         return SystemError::EINVAL.to_posix_errno() as u64;
321     }
322 
323     if (flag & (AT_REMOVEDIR as u64)) > 0 {
324         // kdebug!("rmdir");
325         match do_remove_dir(&path) {
326             Err(err) => {
327                 kerror!("Failed to Remove Directory, Error Code = {:?}", err);
328                 return err.to_posix_errno() as u64;
329             }
330             Ok(_) => {
331                 return 0;
332             }
333         }
334     }
335 
336     // kdebug!("rm");
337     match do_unlink_at(&path, FileMode::from_bits_truncate(flag as u32)) {
338         Err(err) => {
339             kerror!("Failed to Remove Directory, Error Code = {:?}", err);
340             return err.to_posix_errno() as u64;
341         }
342         Ok(_) => {
343             return 0;
344         }
345     }
346 }
347