1 use alloc::sync::Arc; 2 3 use crate::{ 4 driver::base::block::SeekFrom, 5 process::ProcessManager, 6 syscall::{user_access::check_and_clone_cstr, SystemError}, 7 }; 8 9 use super::{ 10 fcntl::AtFlags, 11 file::{File, FileMode}, 12 syscall::{ModeType, OpenHow, OpenHowResolve}, 13 utils::{rsplit_path, user_path_at}, 14 FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES, 15 }; 16 17 pub(super) fn do_faccessat( 18 dirfd: i32, 19 path: *const u8, 20 mode: ModeType, 21 flags: u32, 22 ) -> Result<usize, SystemError> { 23 if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 { 24 return Err(SystemError::EINVAL); 25 } 26 27 if (flags 28 & (!((AtFlags::AT_EACCESS | AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH).bits() 29 as u32))) 30 != 0 31 { 32 return Err(SystemError::EINVAL); 33 } 34 35 // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0; 36 37 let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; 38 39 if path.len() == 0 { 40 return Err(SystemError::EINVAL); 41 } 42 43 let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, &path)?; 44 45 // 如果找不到文件,则返回错误码ENOENT 46 let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; 47 48 // todo: 接着完善(可以借鉴linux 6.1.9的do_faccessat) 49 return Ok(0); 50 } 51 52 pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize, SystemError> { 53 let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; 54 55 if path.len() == 0 { 56 return Err(SystemError::EINVAL); 57 } 58 59 let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, &path)?; 60 61 // 如果找不到文件,则返回错误码ENOENT 62 let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; 63 64 kwarn!("do_fchmodat: not implemented yet\n"); 65 // todo: 真正去改变文件的权限 66 67 return Ok(0); 68 } 69 70 pub(super) fn do_sys_open( 71 dfd: i32, 72 path: &str, 73 o_flags: FileMode, 74 mode: ModeType, 75 follow_symlink: bool, 76 ) -> Result<usize, SystemError> { 77 let how = OpenHow::new(o_flags, mode, OpenHowResolve::empty()); 78 return do_sys_openat2(dfd, path, how, follow_symlink); 79 } 80 81 fn do_sys_openat2( 82 dirfd: i32, 83 path: &str, 84 how: OpenHow, 85 follow_symlink: bool, 86 ) -> Result<usize, SystemError> { 87 // kdebug!("open: path: {}, mode: {:?}", path, mode); 88 // 文件名过长 89 if path.len() > MAX_PATHLEN as usize { 90 return Err(SystemError::ENAMETOOLONG); 91 } 92 let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?; 93 let inode: Result<Arc<dyn IndexNode>, SystemError> = inode_begin.lookup_follow_symlink( 94 &path, 95 if follow_symlink { 96 VFS_MAX_FOLLOW_SYMLINK_TIMES 97 } else { 98 0 99 }, 100 ); 101 102 let inode: Arc<dyn IndexNode> = if inode.is_err() { 103 let errno = inode.unwrap_err(); 104 // 文件不存在,且需要创建 105 if how.o_flags.contains(FileMode::O_CREAT) 106 && !how.o_flags.contains(FileMode::O_DIRECTORY) 107 && errno == SystemError::ENOENT 108 { 109 let (filename, parent_path) = rsplit_path(&path); 110 // 查找父目录 111 let parent_inode: Arc<dyn IndexNode> = 112 ROOT_INODE().lookup(parent_path.unwrap_or("/"))?; 113 // 创建文件 114 let inode: Arc<dyn IndexNode> = parent_inode.create( 115 filename, 116 FileType::File, 117 ModeType::from_bits_truncate(0o755), 118 )?; 119 inode 120 } else { 121 // 不需要创建文件,因此返回错误码 122 return Err(errno); 123 } 124 } else { 125 inode.unwrap() 126 }; 127 128 let file_type: FileType = inode.metadata()?.file_type; 129 // 如果要打开的是文件夹,而目标不是文件夹 130 if how.o_flags.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir { 131 return Err(SystemError::ENOTDIR); 132 } 133 134 // 创建文件对象 135 136 let mut file: File = File::new(inode, how.o_flags)?; 137 138 // 打开模式为“追加” 139 if how.o_flags.contains(FileMode::O_APPEND) { 140 file.lseek(SeekFrom::SeekEnd(0))?; 141 } 142 143 // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件 144 if how.o_flags.contains(FileMode::O_TRUNC) 145 && (how.o_flags.contains(FileMode::O_RDWR) || how.o_flags.contains(FileMode::O_WRONLY)) 146 && file_type == FileType::File 147 { 148 file.ftruncate(0)?; 149 } 150 // 把文件对象存入pcb 151 let r = ProcessManager::current_pcb() 152 .fd_table() 153 .write() 154 .alloc_fd(file, None) 155 .map(|fd| fd as usize); 156 157 return r; 158 } 159