xref: /DragonOS/kernel/src/filesystem/vfs/syscall.rs (revision cde5492f725681ed89abe1e6eb088e05d943d793)
1 use core::ffi::{c_char, CStr};
2 
3 use alloc::{boxed::Box, string::ToString, vec::Vec};
4 
5 use crate::{
6     arch::asm::{current::current_pcb, ptrace::user_mode},
7     filesystem::vfs::file::FileDescriptorVec,
8     include::bindings::bindings::{
9         pt_regs, verify_area, AT_REMOVEDIR, PAGE_2M_SIZE, PAGE_4K_SIZE, PROC_MAX_FD_NUM, SEEK_CUR,
10         SEEK_END, SEEK_MAX, SEEK_SET,
11     },
12     io::SeekFrom,
13     kerror,
14     syscall::SystemError,
15 };
16 
17 use super::{
18     core::{do_lseek, do_mkdir, do_open, do_read, do_remove_dir, do_unlink_at, do_write},
19     file::{File, FileMode},
20     Dirent, FileType, ROOT_INODE,
21 };
22 
23 /// @brief 打开文件
24 ///
25 /// @param regs->r8 path 文件路径
26 /// @param regs->r9 o_flags 打开文件的标志位
27 ///
28 /// @return u64 文件描述符编号,或者是错误码
29 #[no_mangle]
30 pub extern "C" fn sys_open(regs: &pt_regs) -> u64 {
31     let path: &CStr = unsafe { CStr::from_ptr(regs.r8 as usize as *const c_char) };
32     let path: Result<&str, core::str::Utf8Error> = path.to_str();
33     if path.is_err() {
34         return SystemError::EINVAL.to_posix_errno() as u64;
35     }
36     let path: &str = path.unwrap();
37     let flags = regs.r9;
38     let open_flags: FileMode = FileMode::from_bits_truncate(flags as u32);
39     let r: Result<i32, SystemError> = do_open(path, open_flags);
40 
41     if r.is_ok() {
42         return r.unwrap() as u64;
43     } else {
44         return r.unwrap_err().to_posix_errno() as u64;
45     }
46 }
47 
48 /// @brief 关闭文件的系统调用函数
49 ///
50 /// @param regs->r8 fd:文件描述符编号
51 #[no_mangle]
52 pub extern "C" fn sys_close(regs: &pt_regs) -> u64 {
53     let fd = regs.r8 as i32;
54     let r: Result<(), SystemError> = current_pcb().drop_fd(fd);
55 
56     if r.is_ok() {
57         return 0;
58     } else {
59         return r.unwrap_err().to_posix_errno() as u64;
60     }
61 }
62 
63 /// @brief 读取文件的系统调用函数
64 ///
65 /// @param regs->r8 文件描述符编号
66 /// @param regs->r9 输出缓冲区
67 /// @param regs->r10 要读取的长度
68 #[no_mangle]
69 pub extern "C" fn sys_read(regs: &pt_regs) -> u64 {
70     let fd = regs.r8 as i32;
71     let buf_vaddr = regs.r9 as usize;
72     let len = regs.r10 as usize;
73 
74     // 判断缓冲区是否来自用户态,进行权限校验
75     if user_mode(regs) && unsafe { !verify_area(buf_vaddr as u64, len as u64) } {
76         // 来自用户态,而buffer在内核态,这样的操作不被允许
77         return SystemError::EPERM.to_posix_errno() as u64;
78     }
79 
80     let buf: &mut [u8] =
81         unsafe { core::slice::from_raw_parts_mut::<'static, u8>(buf_vaddr as *mut u8, len) };
82 
83     let r: Result<usize, SystemError> = do_read(fd, buf);
84 
85     if r.is_ok() {
86         return r.unwrap() as u64;
87     } else {
88         return r.unwrap_err().to_posix_errno() as u64;
89     }
90 }
91 
92 /// @brief 向文件写入数据的系统调用函数
93 ///
94 /// @param regs->r8 文件描述符编号
95 /// @param regs->r9 输入缓冲区
96 /// @param regs->r10 要写入的长度
97 #[no_mangle]
98 pub extern "C" fn sys_write(regs: &pt_regs) -> u64 {
99     let fd = regs.r8 as i32;
100     let buf_vaddr = regs.r9 as usize;
101     let len = regs.r10 as usize;
102 
103     // 判断缓冲区是否来自用户态,进行权限校验
104     if user_mode(regs) && unsafe { !verify_area(buf_vaddr as u64, len as u64) } {
105         // 来自用户态,而buffer在内核态,这样的操作不被允许
106         return SystemError::EPERM.to_posix_errno() as u64;
107     }
108 
109     let buf: &[u8] =
110         unsafe { core::slice::from_raw_parts::<'static, u8>(buf_vaddr as *mut u8, len) };
111 
112     let r: Result<usize, SystemError> = do_write(fd, buf);
113 
114     if r.is_ok() {
115         return r.unwrap() as u64;
116     } else {
117         return r.unwrap_err().to_posix_errno() as u64;
118     }
119 }
120 
121 /// @brief 调整文件访问指针位置的系统调用函数
122 ///
123 /// @param regs->r8 文件描述符编号
124 /// @param regs->r9 调整偏移量
125 /// @param regs->r10 调整的模式
126 #[no_mangle]
127 pub extern "C" fn sys_lseek(regs: &pt_regs) -> u64 {
128     let fd = regs.r8 as i32;
129     let offset = regs.r9 as i64;
130     let whence = regs.r10 as u32;
131 
132     let w: SeekFrom = match whence {
133         SEEK_SET => SeekFrom::SeekSet(offset),
134         SEEK_CUR => SeekFrom::SeekCurrent(offset),
135         SEEK_END => SeekFrom::SeekEnd(offset),
136         SEEK_MAX => SeekFrom::SeekEnd(0),
137         _ => return SystemError::EINVAL.to_posix_errno() as u64,
138     };
139 
140     let r: Result<usize, SystemError> = do_lseek(fd, w);
141     if r.is_ok() {
142         return r.unwrap() as u64;
143     } else {
144         return r.unwrap_err().to_posix_errno() as u64;
145     }
146 }
147 
148 /// @brief 切换工作目录
149 ///
150 /// @param dest_path 目标路径
151 ///
152 /// @return   返回码  描述
153 ///      0       |          成功
154 ///
155 ///   EACCESS    |        权限不足
156 ///
157 ///    ELOOP     | 解析path时遇到路径循环
158 ///
159 /// ENAMETOOLONG |       路径名过长
160 ///
161 ///    ENOENT    |  目标文件或目录不存在
162 ///
163 ///    ENODIR    |  检索期间发现非目录项
164 ///
165 ///    ENOMEM    |      系统内存不足
166 ///
167 ///    EFAULT    |       错误的地址
168 ///
169 /// ENAMETOOLONG |        路径过长
170 #[no_mangle]
171 pub extern "C" fn sys_chdir(regs: &pt_regs) -> u64 {
172     if regs.r8 == 0 {
173         return SystemError::EFAULT.to_posix_errno() as u64;
174     }
175     let ptr = regs.r8 as usize as *const c_char;
176     // 权限校验
177     if ptr.is_null()
178         || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
179     {
180         return SystemError::EINVAL.to_posix_errno() as u64;
181     }
182 
183     let dest_path: &CStr = unsafe { CStr::from_ptr(ptr) };
184     let dest_path: Result<&str, core::str::Utf8Error> = dest_path.to_str();
185 
186     if dest_path.is_err() {
187         return SystemError::EINVAL.to_posix_errno() as u64;
188     }
189 
190     let dest_path: &str = dest_path.unwrap();
191 
192     if dest_path.len() == 0 {
193         return SystemError::EINVAL.to_posix_errno() as u64;
194     } else if dest_path.len() >= PAGE_4K_SIZE as usize {
195         return SystemError::ENAMETOOLONG.to_posix_errno() as u64;
196     }
197 
198     let path = Box::new(dest_path.clone());
199     let inode = match ROOT_INODE().lookup(&path) {
200         Err(e) => {
201             kerror!("Change Directory Failed, Error = {:?}", e);
202             return SystemError::ENOENT.to_posix_errno() as u64;
203         }
204         Ok(i) => i,
205     };
206 
207     match inode.metadata() {
208         Err(e) => {
209             kerror!("INode Get MetaData Failed, Error = {:?}", e);
210             return SystemError::ENOENT.to_posix_errno() as u64;
211         }
212         Ok(i) => {
213             if let FileType::Dir = i.file_type {
214                 return 0;
215             } else {
216                 return SystemError::ENOTDIR.to_posix_errno() as u64;
217             }
218         }
219     }
220 }
221 
222 /// @brief 获取目录中的数据
223 ///
224 /// @param fd 文件描述符号
225 /// @return uint64_t dirent的总大小
226 #[no_mangle]
227 pub extern "C" fn sys_getdents(regs: &pt_regs) -> u64 {
228     let fd = regs.r8 as i32;
229     let count = regs.r10 as i64;
230     let dirent = match unsafe { (regs.r9 as usize as *mut Dirent).as_mut() } {
231         None => {
232             return 0;
233         }
234         Some(dirent) => dirent,
235     };
236 
237     if fd < 0 || fd as u32 > PROC_MAX_FD_NUM {
238         return SystemError::EBADF.to_posix_errno() as u64;
239     }
240 
241     if count < 0 {
242         return SystemError::EINVAL.to_posix_errno() as u64;
243     }
244 
245     // 获取fd
246     let file: &mut File = match current_pcb().get_file_mut_by_fd(fd) {
247         None => {
248             return SystemError::EBADF.to_posix_errno() as u64;
249         }
250         Some(file) => file,
251     };
252     // kdebug!("file={file:?}");
253 
254     return match file.readdir(dirent) {
255         Err(_) => 0,
256         Ok(len) => len,
257     };
258 }
259 
260 /// @brief 创建文件夹
261 ///
262 /// @param path(r8) 路径 / mode(r9) 模式
263 ///
264 /// @return uint64_t 负数错误码 / 0表示成功
265 #[no_mangle]
266 pub extern "C" fn sys_mkdir(regs: &pt_regs) -> u64 {
267     let ptr = regs.r8 as usize as *const c_char;
268     if ptr.is_null()
269         || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
270     {
271         return SystemError::EINVAL.to_posix_errno() as u64;
272     }
273     let path: &CStr = unsafe { CStr::from_ptr(ptr) };
274     let path: Result<&str, core::str::Utf8Error> = path.to_str();
275     let mode = regs.r9;
276 
277     if path.is_err() {
278         return SystemError::EINVAL.to_posix_errno() as u64;
279     }
280 
281     let path = &path.unwrap().to_string();
282     if path.trim() == "" {
283         return SystemError::EINVAL.to_posix_errno() as u64;
284     }
285 
286     return match do_mkdir(&path.trim(), FileMode::from_bits_truncate(mode as u32)) {
287         Err(err) => {
288             kerror!("Failed in do_mkdir, Error Code = {:#?}", err);
289             err.to_posix_errno() as u64
290         }
291         Ok(_) => 0,
292     };
293 }
294 
295 ///@brief 删除文件夹、取消文件的链接、删除文件的系统调用
296 ///
297 ///@param regs->r8 dfd 进程相对路径基准目录的文件描述符(见fcntl.h)
298 ///
299 ///@param regs->r9 路径名称字符串
300 ///
301 ///@param regs->r10 flag 预留的标志位,暂时未使用,请置为0。
302 ///
303 ///@return uint64_t 错误码
304 #[no_mangle]
305 pub extern "C" fn sys_unlink_at(regs: &pt_regs) -> u64 {
306     let _dfd = regs.r8;
307     let ptr = regs.r9 as usize as *const c_char;
308     if ptr.is_null()
309         || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) })
310     {
311         return SystemError::EINVAL.to_posix_errno() as u64;
312     }
313     let path: &CStr = unsafe { CStr::from_ptr(ptr) };
314     let path: Result<&str, core::str::Utf8Error> = path.to_str();
315     let flag = regs.r10;
316     if path.is_err() {
317         return SystemError::EINVAL.to_posix_errno() as u64;
318     }
319 
320     let path = &path.unwrap().to_string();
321     // kdebug!("sys_unlink_at={path:?}");
322     if (flag & (!(AT_REMOVEDIR as u64))) != 0_u64 {
323         return SystemError::EINVAL.to_posix_errno() as u64;
324     }
325 
326     if (flag & (AT_REMOVEDIR as u64)) > 0 {
327         // kdebug!("rmdir");
328         match do_remove_dir(&path) {
329             Err(err) => {
330                 kerror!("Failed to Remove Directory, Error Code = {:?}", err);
331                 return err.to_posix_errno() as u64;
332             }
333             Ok(_) => {
334                 return 0;
335             }
336         }
337     }
338 
339     // kdebug!("rm");
340     match do_unlink_at(&path, FileMode::from_bits_truncate(flag as u32)) {
341         Err(err) => {
342             kerror!("Failed to Remove Directory, Error Code = {:?}", err);
343             return err.to_posix_errno() as u64;
344         }
345         Ok(_) => {
346             return 0;
347         }
348     }
349 }
350 
351 fn do_dup(oldfd: i32) -> Result<i32, SystemError> {
352     if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
353         // 获得当前文件描述符数组
354         // 确认oldfd是否有效
355         if FileDescriptorVec::validate_fd(oldfd) {
356             if let Some(file) = &fds.fds[oldfd as usize] {
357                 // 尝试获取对应的文件结构体
358                 let file_cp = (file).try_clone();
359                 if file_cp.is_none() {
360                     return Err(SystemError::EBADF);
361                 }
362                 let res = current_pcb().alloc_fd(*file_cp.unwrap(), None);
363                 // 申请文件描述符,并把文件对象存入其中
364                 return res;
365             }
366             // oldfd对应的文件不存在
367             return Err(SystemError::EBADF);
368         }
369         return Err(SystemError::EBADF);
370     } else {
371         return Err(SystemError::EMFILE);
372     }
373 }
374 
375 #[no_mangle]
376 /// @brief 根据提供的文件描述符的fd,复制对应的文件结构体,并返回新复制的文件结构体对应的fd
377 pub extern "C" fn sys_dup(regs: &pt_regs) -> u64 {
378     let fd: i32 = regs.r8 as i32;
379     let r = do_dup(fd);
380     if r.is_ok() {
381         return r.unwrap() as u64;
382     } else {
383         return r.unwrap_err().to_posix_errno() as u64;
384     }
385 }
386 
387 fn do_dup2(oldfd: i32, newfd: i32) -> Result<i32, SystemError> {
388     if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) {
389         // 获得当前文件描述符数组
390         if FileDescriptorVec::validate_fd(oldfd) && FileDescriptorVec::validate_fd(newfd) {
391             //确认oldfd, newid是否有效
392             if oldfd == newfd {
393                 // 若oldfd与newfd相等
394                 return Ok(newfd);
395             }
396 
397             if let Some(file) = &fds.fds[oldfd as usize] {
398                 if fds.fds[newfd as usize].is_some() {
399                     // close newfd
400                     if let Err(_) = current_pcb().drop_fd(newfd) {
401                         // An I/O error occurred while attempting to close fildes2.
402                         return Err(SystemError::EIO);
403                     }
404                 }
405 
406                 // 尝试获取对应的文件结构体
407                 let file_cp = file.try_clone();
408                 if file_cp.is_none() {
409                     return Err(SystemError::EBADF);
410                 }
411                 // 申请文件描述符,并把文件对象存入其中
412                 let res = current_pcb().alloc_fd(*file_cp.unwrap(), Some(newfd));
413 
414                 return res;
415             }
416             return Err(SystemError::EBADF);
417         } else {
418             return Err(SystemError::EBADF);
419         }
420     }
421     // 从pcb获取文件描述符数组失败
422     return Err(SystemError::EMFILE);
423 }
424 
425 #[no_mangle]
426 /// @brief 根据提供的文件描述符的fd,和指定新fd,复制对应的文件结构体,
427 /// 并返回新复制的文件结构体对应的fd
428 pub extern "C" fn sys_dup2(regs: &pt_regs) -> u64 {
429     let ofd = regs.r8 as i32;
430     let nfd = regs.r9 as i32;
431     let r = do_dup2(ofd, nfd);
432     if r.is_ok() {
433         return r.unwrap() as u64;
434     } else {
435         return r.unwrap_err().to_posix_errno() as u64;
436     }
437 }
438 
439 #[repr(C)]
440 #[derive(Debug, Clone, Copy)]
441 pub struct IoVec {
442     /// 缓冲区的起始地址
443     pub iov_base: *mut u8,
444     /// 缓冲区的长度
445     pub iov_len: usize,
446 }
447 
448 /// 用于存储多个来自用户空间的IoVec
449 ///
450 /// 由于目前内核中的文件系统还不支持分散读写,所以暂时只支持将用户空间的IoVec聚合成一个缓冲区,然后进行操作。
451 /// TODO:支持分散读写
452 #[derive(Debug)]
453 pub struct IoVecs(Vec<&'static mut [u8]>);
454 
455 impl IoVecs {
456     /// 从用户空间的IoVec中构造IoVecs
457     ///
458     /// @param iov 用户空间的IoVec
459     /// @param iovcnt 用户空间的IoVec的数量
460     /// @param readv 是否为readv系统调用
461     ///
462     /// @return 构造成功返回IoVecs,否则返回错误码
463     pub unsafe fn from_user(
464         iov: *const IoVec,
465         iovcnt: usize,
466         _readv: bool,
467     ) -> Result<Self, SystemError> {
468         // 检查iov指针所在空间是否合法
469         if !verify_area(
470             iov as usize as u64,
471             (iovcnt * core::mem::size_of::<IoVec>()) as u64,
472         ) {
473             return Err(SystemError::EFAULT);
474         }
475 
476         // 将用户空间的IoVec转换为引用(注意:这里的引用是静态的,因为用户空间的IoVec不会被释放)
477         let iovs: &[IoVec] = core::slice::from_raw_parts(iov, iovcnt);
478 
479         let mut slices: Vec<&mut [u8]> = vec![];
480         slices.reserve(iovs.len());
481 
482         for iov in iovs.iter() {
483             if iov.iov_len == 0 {
484                 continue;
485             }
486 
487             if !verify_area(iov.iov_base as usize as u64, iov.iov_len as u64) {
488                 return Err(SystemError::EFAULT);
489             }
490 
491             slices.push(core::slice::from_raw_parts_mut(iov.iov_base, iov.iov_len));
492         }
493 
494         return Ok(Self(slices));
495     }
496 
497     /// @brief 将IoVecs中的数据聚合到一个缓冲区中
498     ///
499     /// @return 返回聚合后的缓冲区
500     pub fn gather(&self) -> Vec<u8> {
501         let mut buf = Vec::new();
502         for slice in self.0.iter() {
503             buf.extend_from_slice(slice);
504         }
505         return buf;
506     }
507 
508     /// @brief 将给定的数据分散写入到IoVecs中
509     pub fn scatter(&mut self, data: &[u8]) {
510         let mut data: &[u8] = data;
511         for slice in self.0.iter_mut() {
512             let len = core::cmp::min(slice.len(), data.len());
513             if len == 0 {
514                 continue;
515             }
516 
517             slice[..len].copy_from_slice(&data[..len]);
518             data = &data[len..];
519         }
520     }
521 
522     /// @brief 创建与IoVecs等长的缓冲区
523     ///
524     /// @param set_len 是否设置返回的Vec的len。
525     /// 如果为true,则返回的Vec的len为所有IoVec的长度之和;
526     /// 否则返回的Vec的len为0,capacity为所有IoVec的长度之和.
527     ///
528     /// @return 返回创建的缓冲区
529     pub fn new_buf(&self, set_len: bool) -> Vec<u8> {
530         let total_len: usize = self.0.iter().map(|slice| slice.len()).sum();
531         let mut buf: Vec<u8> = Vec::with_capacity(total_len);
532 
533         if set_len {
534             unsafe {
535                 buf.set_len(total_len);
536             }
537         }
538         return buf;
539     }
540 }
541