1 use alloc::sync::Arc; 2 use log::warn; 3 use system_error::SystemError; 4 5 use super::{ 6 fcntl::AtFlags, 7 file::{File, FileMode}, 8 syscall::{ModeType, OpenHow, OpenHowResolve}, 9 utils::{rsplit_path, user_path_at}, 10 FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES, 11 }; 12 use crate::filesystem::vfs::syscall::UtimensFlags; 13 use crate::time::{syscall::PosixTimeval, PosixTimeSpec}; 14 use crate::{ 15 driver::base::block::SeekFrom, process::ProcessManager, 16 syscall::user_access::check_and_clone_cstr, 17 }; 18 use alloc::string::String; 19 20 pub(super) fn do_faccessat( 21 dirfd: i32, 22 path: *const u8, 23 mode: ModeType, 24 flags: u32, 25 ) -> Result<usize, SystemError> { 26 if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 { 27 return Err(SystemError::EINVAL); 28 } 29 30 if (flags 31 & (!((AtFlags::AT_EACCESS | AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH).bits() 32 as u32))) 33 != 0 34 { 35 return Err(SystemError::EINVAL); 36 } 37 38 // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0; 39 40 let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; 41 let path = path.to_str().map_err(|_| SystemError::EINVAL)?; 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 let path = path.to_str().map_err(|_| SystemError::EINVAL)?; 55 56 let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?; 57 58 // 如果找不到文件,则返回错误码ENOENT 59 let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; 60 61 warn!("do_fchmodat: not implemented yet\n"); 62 // todo: 真正去改变文件的权限 63 64 return Ok(0); 65 } 66 67 pub(super) fn do_sys_open( 68 dfd: i32, 69 path: &str, 70 o_flags: FileMode, 71 mode: ModeType, 72 follow_symlink: bool, 73 ) -> Result<usize, SystemError> { 74 let how = OpenHow::new(o_flags, mode, OpenHowResolve::empty()); 75 return do_sys_openat2(dfd, path, how, follow_symlink); 76 } 77 78 fn do_sys_openat2( 79 dirfd: i32, 80 path: &str, 81 how: OpenHow, 82 follow_symlink: bool, 83 ) -> Result<usize, SystemError> { 84 // debug!("open path: {}, how: {:?}", path, how); 85 let path = path.trim(); 86 87 let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?; 88 let inode: Result<Arc<dyn IndexNode>, SystemError> = inode_begin.lookup_follow_symlink( 89 &path, 90 if follow_symlink { 91 VFS_MAX_FOLLOW_SYMLINK_TIMES 92 } else { 93 0 94 }, 95 ); 96 97 let inode: Arc<dyn IndexNode> = match inode { 98 Ok(inode) => inode, 99 Err(errno) => { 100 // 文件不存在,且需要创建 101 if how.o_flags.contains(FileMode::O_CREAT) 102 && !how.o_flags.contains(FileMode::O_DIRECTORY) 103 && errno == SystemError::ENOENT 104 { 105 let (filename, parent_path) = rsplit_path(&path); 106 // 查找父目录 107 let parent_inode: Arc<dyn IndexNode> = 108 ROOT_INODE().lookup(parent_path.unwrap_or("/"))?; 109 // 创建文件 110 let inode: Arc<dyn IndexNode> = parent_inode.create( 111 filename, 112 FileType::File, 113 ModeType::from_bits_truncate(0o755), 114 )?; 115 inode 116 } else { 117 // 不需要创建文件,因此返回错误码 118 return Err(errno); 119 } 120 } 121 }; 122 123 let file_type: FileType = inode.metadata()?.file_type; 124 // 如果要打开的是文件夹,而目标不是文件夹 125 if how.o_flags.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir { 126 return Err(SystemError::ENOTDIR); 127 } 128 129 // 创建文件对象 130 131 let file: File = File::new(inode, how.o_flags)?; 132 133 // 打开模式为“追加” 134 if how.o_flags.contains(FileMode::O_APPEND) { 135 file.lseek(SeekFrom::SeekEnd(0))?; 136 } 137 138 // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件 139 if how.o_flags.contains(FileMode::O_TRUNC) 140 && (how.o_flags.contains(FileMode::O_RDWR) || how.o_flags.contains(FileMode::O_WRONLY)) 141 && file_type == FileType::File 142 { 143 file.ftruncate(0)?; 144 } 145 // 把文件对象存入pcb 146 let r = ProcessManager::current_pcb() 147 .fd_table() 148 .write() 149 .alloc_fd(file, None) 150 .map(|fd| fd as usize); 151 152 return r; 153 } 154 155 /// On Linux, futimens() is a library function implemented on top of 156 /// the utimensat() system call. To support this, the Linux 157 /// utimensat() system call implements a nonstandard feature: if 158 /// pathname is NULL, then the call modifies the timestamps of the 159 /// file referred to by the file descriptor dirfd (which may refer to 160 /// any type of file). 161 pub fn do_utimensat( 162 dirfd: i32, 163 pathname: Option<String>, 164 times: Option<[PosixTimeSpec; 2]>, 165 flags: UtimensFlags, 166 ) -> Result<usize, SystemError> { 167 const UTIME_NOW: i64 = (1i64 << 30) - 1i64; 168 const UTIME_OMIT: i64 = (1i64 << 30) - 2i64; 169 // log::debug!("do_utimensat: dirfd:{}, pathname:{:?}, times:{:?}, flags:{:?}", dirfd, pathname, times, flags); 170 let inode = match pathname { 171 Some(path) => { 172 let (inode_begin, path) = 173 user_path_at(&ProcessManager::current_pcb(), dirfd, path.as_str())?; 174 let inode = if flags.contains(UtimensFlags::AT_SYMLINK_NOFOLLOW) { 175 inode_begin.lookup(path.as_str())? 176 } else { 177 inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)? 178 }; 179 inode 180 } 181 None => { 182 let binding = ProcessManager::current_pcb().fd_table(); 183 let fd_table_guard = binding.write(); 184 let file = fd_table_guard 185 .get_file_by_fd(dirfd) 186 .ok_or(SystemError::EBADF)?; 187 file.inode() 188 } 189 }; 190 let now = PosixTimeSpec::now(); 191 let mut meta = inode.metadata()?; 192 193 if let Some([atime, mtime]) = times { 194 if atime.tv_nsec == UTIME_NOW { 195 meta.atime = now; 196 } else if atime.tv_nsec != UTIME_OMIT { 197 meta.atime = atime; 198 } 199 if mtime.tv_nsec == UTIME_NOW { 200 meta.mtime = now; 201 } else if mtime.tv_nsec != UTIME_OMIT { 202 meta.mtime = mtime; 203 } 204 inode.set_metadata(&meta).unwrap(); 205 } else { 206 meta.atime = now; 207 meta.mtime = now; 208 inode.set_metadata(&meta).unwrap(); 209 } 210 return Ok(0); 211 } 212 213 pub fn do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError> { 214 // log::debug!("do_utimes: path:{:?}, times:{:?}", path, times); 215 let (inode_begin, path) = user_path_at( 216 &ProcessManager::current_pcb(), 217 AtFlags::AT_FDCWD.bits(), 218 path, 219 )?; 220 let inode = inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; 221 let mut meta = inode.metadata()?; 222 223 if let Some([atime, mtime]) = times { 224 meta.atime = PosixTimeSpec::from(atime); 225 meta.mtime = PosixTimeSpec::from(mtime); 226 inode.set_metadata(&meta)?; 227 } else { 228 let now = PosixTimeSpec::now(); 229 meta.atime = now; 230 meta.mtime = now; 231 inode.set_metadata(&meta)?; 232 } 233 return Ok(0); 234 } 235