1 2 use alloc::{boxed::Box, sync::Arc, vec::Vec}; 3 4 use crate::{ 5 arch::asm::{current::current_pcb}, 6 filesystem::vfs::file::FileDescriptorVec, 7 include::bindings::bindings::{ 8 verify_area, AT_REMOVEDIR, PAGE_4K_SIZE, PROC_MAX_FD_NUM, 9 }, 10 io::SeekFrom, 11 kerror, 12 syscall::{Syscall, SystemError}, 13 }; 14 15 use super::{ 16 core::{do_mkdir, do_remove_dir, do_unlink_at}, 17 file::{File, FileMode}, 18 utils::rsplit_path, 19 Dirent, FileType, IndexNode, ROOT_INODE, 20 }; 21 22 pub const SEEK_SET: u32 = 0; 23 pub const SEEK_CUR: u32 = 1; 24 pub const SEEK_END: u32 = 2; 25 pub const SEEK_MAX: u32 = 3; 26 27 impl Syscall { 28 /// @brief 为当前进程打开一个文件 29 /// 30 /// @param path 文件路径 31 /// @param o_flags 打开文件的标志位 32 /// 33 /// @return 文件描述符编号,或者是错误码 34 pub fn open(path: &str, mode: FileMode) -> Result<usize, SystemError> { 35 // 文件名过长 36 if path.len() > PAGE_4K_SIZE as usize { 37 return Err(SystemError::ENAMETOOLONG); 38 } 39 40 let inode: Result<Arc<dyn IndexNode>, SystemError> = ROOT_INODE().lookup(path); 41 42 let inode: Arc<dyn IndexNode> = if inode.is_err() { 43 let errno = inode.unwrap_err(); 44 // 文件不存在,且需要创建 45 if mode.contains(FileMode::O_CREAT) 46 && !mode.contains(FileMode::O_DIRECTORY) 47 && errno == SystemError::ENOENT 48 { 49 let (filename, parent_path) = rsplit_path(path); 50 // 查找父目录 51 let parent_inode: Arc<dyn IndexNode> = 52 ROOT_INODE().lookup(parent_path.unwrap_or("/"))?; 53 // 创建文件 54 let inode: Arc<dyn IndexNode> = 55 parent_inode.create(filename, FileType::File, 0o777)?; 56 inode 57 } else { 58 // 不需要创建文件,因此返回错误码 59 return Err(errno); 60 } 61 } else { 62 inode.unwrap() 63 }; 64 65 let file_type: FileType = inode.metadata()?.file_type; 66 // 如果要打开的是文件夹,而目标不是文件夹 67 if mode.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir { 68 return Err(SystemError::ENOTDIR); 69 } 70 71 // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件 72 if mode.contains(FileMode::O_TRUNC) 73 && (mode.contains(FileMode::O_RDWR) || mode.contains(FileMode::O_WRONLY)) 74 && file_type == FileType::File 75 { 76 inode.truncate(0)?; 77 } 78 79 // 创建文件对象 80 let mut file: File = File::new(inode, mode)?; 81 82 // 打开模式为“追加” 83 if mode.contains(FileMode::O_APPEND) { 84 file.lseek(SeekFrom::SeekEnd(0))?; 85 } 86 87 // 把文件对象存入pcb 88 return current_pcb().alloc_fd(file, None).map(|fd| fd as usize); 89 } 90 91 /// @brief 关闭文件 92 /// 93 /// @param fd 文件描述符编号 94 /// 95 /// @return 成功返回0,失败返回错误码 96 pub fn close(fd: usize) -> Result<usize, SystemError> { 97 return current_pcb().drop_fd(fd as i32).map(|_| 0); 98 } 99 100 /// @brief 根据文件描述符,读取文件数据。尝试读取的数据长度与buf的长度相同。 101 /// 102 /// @param fd 文件描述符编号 103 /// @param buf 输出缓冲区。 104 /// 105 /// @return Ok(usize) 成功读取的数据的字节数 106 /// @return Err(SystemError) 读取失败,返回posix错误码 107 pub fn read(fd: i32, buf: &mut [u8]) -> Result<usize, SystemError> { 108 let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd); 109 if file.is_none() { 110 return Err(SystemError::EBADF); 111 } 112 let file: &mut File = file.unwrap(); 113 114 return file.read(buf.len(), buf); 115 } 116 117 /// @brief 根据文件描述符,向文件写入数据。尝试写入的数据长度与buf的长度相同。 118 /// 119 /// @param fd 文件描述符编号 120 /// @param buf 输入缓冲区。 121 /// 122 /// @return Ok(usize) 成功写入的数据的字节数 123 /// @return Err(SystemError) 写入失败,返回posix错误码 124 pub fn write(fd: i32, buf: &[u8]) -> Result<usize, SystemError> { 125 let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd); 126 if file.is_none() { 127 return Err(SystemError::EBADF); 128 } 129 let file: &mut File = file.unwrap(); 130 131 return file.write(buf.len(), buf); 132 } 133 134 /// @brief 调整文件操作指针的位置 135 /// 136 /// @param fd 文件描述符编号 137 /// @param seek 调整的方式 138 /// 139 /// @return Ok(usize) 调整后,文件访问指针相对于文件头部的偏移量 140 /// @return Err(SystemError) 调整失败,返回posix错误码 141 pub fn lseek(fd: i32, seek: SeekFrom) -> Result<usize, SystemError> { 142 let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd); 143 if file.is_none() { 144 return Err(SystemError::EBADF); 145 } 146 let file: &mut File = file.unwrap(); 147 return file.lseek(seek); 148 } 149 150 /// @brief 切换工作目录 151 /// 152 /// @param dest_path 目标路径 153 /// 154 /// @return 返回码 描述 155 /// 0 | 成功 156 /// 157 /// EACCESS | 权限不足 158 /// 159 /// ELOOP | 解析path时遇到路径循环 160 /// 161 /// ENAMETOOLONG | 路径名过长 162 /// 163 /// ENOENT | 目标文件或目录不存在 164 /// 165 /// ENODIR | 检索期间发现非目录项 166 /// 167 /// ENOMEM | 系统内存不足 168 /// 169 /// EFAULT | 错误的地址 170 /// 171 /// ENAMETOOLONG | 路径过长 172 pub fn chdir(dest_path: &str) -> Result<usize, SystemError> { 173 // Copy path to kernel space to avoid some security issues 174 let path: Box<&str> = Box::new(dest_path); 175 let inode = match ROOT_INODE().lookup(&path) { 176 Err(e) => { 177 kerror!("Change Directory Failed, Error = {:?}", e); 178 return Err(SystemError::ENOENT); 179 } 180 Ok(i) => i, 181 }; 182 183 match inode.metadata() { 184 Err(e) => { 185 kerror!("INode Get MetaData Failed, Error = {:?}", e); 186 return Err(SystemError::ENOENT); 187 } 188 Ok(i) => { 189 if let FileType::Dir = i.file_type { 190 return Ok(0); 191 } else { 192 return Err(SystemError::ENOTDIR); 193 } 194 } 195 } 196 } 197 198 /// @brief 获取目录中的数据 199 /// 200 /// TODO: 这个函数的语义与Linux不一致,需要修改!!! 201 /// 202 /// @param fd 文件描述符号 203 /// @param buf 输出缓冲区 204 /// 205 /// @return 成功返回读取的字节数,失败返回错误码 206 pub fn getdents(fd: i32, buf: &mut [u8]) -> Result<usize, SystemError> { 207 let dirent = 208 unsafe { (buf.as_mut_ptr() as *mut Dirent).as_mut() }.ok_or(SystemError::EFAULT)?; 209 210 if fd < 0 || fd as u32 > PROC_MAX_FD_NUM { 211 return Err(SystemError::EBADF); 212 } 213 214 // 获取fd 215 let file: &mut File = match current_pcb().get_file_mut_by_fd(fd) { 216 None => { 217 return Err(SystemError::EBADF); 218 } 219 Some(file) => file, 220 }; 221 // kdebug!("file={file:?}"); 222 223 return file.readdir(dirent).map(|x| x as usize); 224 } 225 226 /// @brief 创建文件夹 227 /// 228 /// @param path(r8) 路径 / mode(r9) 模式 229 /// 230 /// @return uint64_t 负数错误码 / 0表示成功 231 pub fn mkdir(path: &str, mode: usize) -> Result<usize, SystemError> { 232 return do_mkdir(path, FileMode::from_bits_truncate(mode as u32)).map(|x| x as usize); 233 } 234 235 /// **删除文件夹、取消文件的链接、删除文件的系统调用** 236 /// 237 /// ## 参数 238 /// 239 /// - `dirfd`:文件夹的文件描述符.目前暂未实现 240 /// - `pathname`:文件夹的路径 241 /// - `flags`:标志位 242 /// 243 /// 244 pub fn unlinkat(_dirfd: i32, pathname: &str, flags: u32) -> Result<usize, SystemError> { 245 // kdebug!("sys_unlink_at={path:?}"); 246 if (flags & (!AT_REMOVEDIR)) != 0 { 247 return Err(SystemError::EINVAL); 248 } 249 250 if (flags & AT_REMOVEDIR) > 0 { 251 // kdebug!("rmdir"); 252 match do_remove_dir(&pathname) { 253 Err(err) => { 254 kerror!("Failed to Remove Directory, Error Code = {:?}", err); 255 return Err(err); 256 } 257 Ok(_) => { 258 return Ok(0); 259 } 260 } 261 } 262 263 match do_unlink_at(&pathname, FileMode::from_bits_truncate(flags as u32)) { 264 Err(err) => { 265 kerror!("Failed to Remove Directory, Error Code = {:?}", err); 266 return Err(err); 267 } 268 Ok(_) => { 269 return Ok(0); 270 } 271 } 272 } 273 274 /// @brief 根据提供的文件描述符的fd,复制对应的文件结构体,并返回新复制的文件结构体对应的fd 275 pub fn dup(oldfd: i32) -> Result<usize, SystemError> { 276 if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) { 277 // 获得当前文件描述符数组 278 // 确认oldfd是否有效 279 if FileDescriptorVec::validate_fd(oldfd) { 280 if let Some(file) = &fds.fds[oldfd as usize] { 281 // 尝试获取对应的文件结构体 282 let file_cp: Box<File> = file.try_clone().ok_or(SystemError::EBADF)?; 283 284 // 申请文件描述符,并把文件对象存入其中 285 let res = current_pcb().alloc_fd(*file_cp, None).map(|x| x as usize); 286 return res; 287 } 288 // oldfd对应的文件不存在 289 return Err(SystemError::EBADF); 290 } 291 return Err(SystemError::EBADF); 292 } else { 293 return Err(SystemError::EMFILE); 294 } 295 } 296 297 /// 根据提供的文件描述符的fd,和指定新fd,复制对应的文件结构体, 298 /// 并返回新复制的文件结构体对应的fd. 299 /// 如果新fd已经打开,则会先关闭新fd. 300 /// 301 /// ## 参数 302 /// 303 /// - `oldfd`:旧文件描述符 304 /// - `newfd`:新文件描述符 305 /// 306 /// ## 返回值 307 /// 308 /// - 成功:新文件描述符 309 /// - 失败:错误码 310 pub fn dup2(oldfd: i32, newfd: i32) -> Result<usize, SystemError> { 311 if let Some(fds) = FileDescriptorVec::from_pcb(current_pcb()) { 312 // 获得当前文件描述符数组 313 if FileDescriptorVec::validate_fd(oldfd) && FileDescriptorVec::validate_fd(newfd) { 314 //确认oldfd, newid是否有效 315 if oldfd == newfd { 316 // 若oldfd与newfd相等 317 return Ok(newfd as usize); 318 } 319 320 if let Some(file) = &fds.fds[oldfd as usize] { 321 if fds.fds[newfd as usize].is_some() { 322 // close newfd 323 if let Err(_) = current_pcb().drop_fd(newfd) { 324 // An I/O error occurred while attempting to close fildes2. 325 return Err(SystemError::EIO); 326 } 327 } 328 329 // 尝试获取对应的文件结构体 330 let file_cp = file.try_clone(); 331 if file_cp.is_none() { 332 return Err(SystemError::EBADF); 333 } 334 // 申请文件描述符,并把文件对象存入其中 335 let res = current_pcb() 336 .alloc_fd(*file_cp.unwrap(), Some(newfd)) 337 .map(|x| x as usize); 338 339 return res; 340 } 341 return Err(SystemError::EBADF); 342 } else { 343 return Err(SystemError::EBADF); 344 } 345 } 346 // 从pcb获取文件描述符数组失败 347 return Err(SystemError::EMFILE); 348 } 349 } 350 351 #[repr(C)] 352 #[derive(Debug, Clone, Copy)] 353 pub struct IoVec { 354 /// 缓冲区的起始地址 355 pub iov_base: *mut u8, 356 /// 缓冲区的长度 357 pub iov_len: usize, 358 } 359 360 /// 用于存储多个来自用户空间的IoVec 361 /// 362 /// 由于目前内核中的文件系统还不支持分散读写,所以暂时只支持将用户空间的IoVec聚合成一个缓冲区,然后进行操作。 363 /// TODO:支持分散读写 364 #[derive(Debug)] 365 pub struct IoVecs(Vec<&'static mut [u8]>); 366 367 impl IoVecs { 368 /// 从用户空间的IoVec中构造IoVecs 369 /// 370 /// @param iov 用户空间的IoVec 371 /// @param iovcnt 用户空间的IoVec的数量 372 /// @param readv 是否为readv系统调用 373 /// 374 /// @return 构造成功返回IoVecs,否则返回错误码 375 pub unsafe fn from_user( 376 iov: *const IoVec, 377 iovcnt: usize, 378 _readv: bool, 379 ) -> Result<Self, SystemError> { 380 // 检查iov指针所在空间是否合法 381 if !verify_area( 382 iov as usize as u64, 383 (iovcnt * core::mem::size_of::<IoVec>()) as u64, 384 ) { 385 return Err(SystemError::EFAULT); 386 } 387 388 // 将用户空间的IoVec转换为引用(注意:这里的引用是静态的,因为用户空间的IoVec不会被释放) 389 let iovs: &[IoVec] = core::slice::from_raw_parts(iov, iovcnt); 390 391 let mut slices: Vec<&mut [u8]> = vec![]; 392 slices.reserve(iovs.len()); 393 394 for iov in iovs.iter() { 395 if iov.iov_len == 0 { 396 continue; 397 } 398 399 if !verify_area(iov.iov_base as usize as u64, iov.iov_len as u64) { 400 return Err(SystemError::EFAULT); 401 } 402 403 slices.push(core::slice::from_raw_parts_mut(iov.iov_base, iov.iov_len)); 404 } 405 406 return Ok(Self(slices)); 407 } 408 409 /// @brief 将IoVecs中的数据聚合到一个缓冲区中 410 /// 411 /// @return 返回聚合后的缓冲区 412 pub fn gather(&self) -> Vec<u8> { 413 let mut buf = Vec::new(); 414 for slice in self.0.iter() { 415 buf.extend_from_slice(slice); 416 } 417 return buf; 418 } 419 420 /// @brief 将给定的数据分散写入到IoVecs中 421 pub fn scatter(&mut self, data: &[u8]) { 422 let mut data: &[u8] = data; 423 for slice in self.0.iter_mut() { 424 let len = core::cmp::min(slice.len(), data.len()); 425 if len == 0 { 426 continue; 427 } 428 429 slice[..len].copy_from_slice(&data[..len]); 430 data = &data[len..]; 431 } 432 } 433 434 /// @brief 创建与IoVecs等长的缓冲区 435 /// 436 /// @param set_len 是否设置返回的Vec的len。 437 /// 如果为true,则返回的Vec的len为所有IoVec的长度之和; 438 /// 否则返回的Vec的len为0,capacity为所有IoVec的长度之和. 439 /// 440 /// @return 返回创建的缓冲区 441 pub fn new_buf(&self, set_len: bool) -> Vec<u8> { 442 let total_len: usize = self.0.iter().map(|slice| slice.len()).sum(); 443 let mut buf: Vec<u8> = Vec::with_capacity(total_len); 444 445 if set_len { 446 unsafe { 447 buf.set_len(total_len); 448 } 449 } 450 return buf; 451 } 452 } 453