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