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