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