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