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::{ 13 driver::base::block::SeekFrom, process::ProcessManager, 14 syscall::user_access::check_and_clone_cstr, 15 }; 16 use crate::{filesystem::vfs::syscall::UtimensFlags, process::cred::Kgid}; 17 use crate::{ 18 process::cred::GroupInfo, 19 time::{syscall::PosixTimeval, PosixTimeSpec}, 20 }; 21 use alloc::string::String; 22 23 pub(super) fn do_faccessat( 24 dirfd: i32, 25 path: *const u8, 26 mode: ModeType, 27 flags: u32, 28 ) -> Result<usize, SystemError> { 29 if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 { 30 return Err(SystemError::EINVAL); 31 } 32 33 if (flags 34 & (!((AtFlags::AT_EACCESS | AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH).bits() 35 as u32))) 36 != 0 37 { 38 return Err(SystemError::EINVAL); 39 } 40 41 // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0; 42 43 let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; 44 let path = path.to_str().map_err(|_| SystemError::EINVAL)?; 45 46 let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?; 47 48 // 如果找不到文件,则返回错误码ENOENT 49 let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; 50 51 // todo: 接着完善(可以借鉴linux 6.1.9的do_faccessat) 52 return Ok(0); 53 } 54 55 pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize, SystemError> { 56 let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; 57 let path = path.to_str().map_err(|_| SystemError::EINVAL)?; 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 warn!("do_fchmodat: not implemented yet\n"); 65 // todo: 真正去改变文件的权限 66 67 return Ok(0); 68 } 69 70 pub fn do_fchownat( 71 dirfd: i32, 72 path: &str, 73 uid: usize, 74 gid: usize, 75 flag: AtFlags, 76 ) -> Result<usize, SystemError> { 77 // 检查flag是否合法 78 if flag.contains(!(AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH)) { 79 return Err(SystemError::EINVAL); 80 } 81 82 let follow_symlink = flag.contains(!AtFlags::AT_SYMLINK_NOFOLLOW); 83 let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?; 84 85 // 如果找不到文件,则返回错误码ENOENT 86 let inode = if follow_symlink { 87 inode.lookup_follow_symlink2(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES, false) 88 } else { 89 inode.lookup(path.as_str()) 90 }; 91 92 if inode.is_err() { 93 let errno = inode.clone().unwrap_err(); 94 // 文件不存在 95 if errno == SystemError::ENOENT { 96 return Err(SystemError::ENOENT); 97 } 98 } 99 100 let inode = inode.unwrap(); 101 102 return chown_common(inode, uid, gid); 103 } 104 105 fn chown_common(inode: Arc<dyn IndexNode>, uid: usize, gid: usize) -> Result<usize, SystemError> { 106 let mut meta = inode.metadata()?; 107 let cred = ProcessManager::current_pcb().cred(); 108 let current_uid = cred.uid.data(); 109 let current_gid = cred.gid.data(); 110 let mut group_info = GroupInfo::default(); 111 if let Some(info) = cred.group_info.as_ref() { 112 group_info = info.clone(); 113 } 114 115 // 检查权限 116 match current_uid { 117 0 => { 118 meta.uid = uid; 119 meta.gid = gid; 120 } 121 _ => { 122 // 非文件所有者不能更改信息,且不能更改uid 123 if current_uid != meta.uid || uid != meta.uid { 124 return Err(SystemError::EPERM); 125 } 126 if gid != current_gid && !group_info.gids.contains(&Kgid::from(gid)) { 127 return Err(SystemError::EPERM); 128 } 129 meta.gid = gid; 130 } 131 } 132 133 meta.mode.remove(ModeType::S_ISUID | ModeType::S_ISGID); 134 inode.set_metadata(&meta)?; 135 136 return Ok(0); 137 } 138 139 pub fn ksys_fchown(fd: i32, uid: usize, gid: usize) -> Result<usize, SystemError> { 140 let fd_table = &ProcessManager::current_pcb().fd_table(); 141 let fd_table = fd_table.read(); 142 143 let inode = fd_table.get_file_by_fd(fd).unwrap().inode(); 144 145 let result = chown_common(inode, uid, gid); 146 147 drop(fd_table); 148 149 return result; 150 } 151 152 pub(super) fn do_sys_open( 153 dfd: i32, 154 path: &str, 155 o_flags: FileMode, 156 mode: ModeType, 157 follow_symlink: bool, 158 ) -> Result<usize, SystemError> { 159 let how = OpenHow::new(o_flags, mode, OpenHowResolve::empty()); 160 return do_sys_openat2(dfd, path, how, follow_symlink); 161 } 162 163 fn do_sys_openat2( 164 dirfd: i32, 165 path: &str, 166 how: OpenHow, 167 follow_symlink: bool, 168 ) -> Result<usize, SystemError> { 169 // debug!("open path: {}, how: {:?}", path, how); 170 let path = path.trim(); 171 172 let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?; 173 let inode: Result<Arc<dyn IndexNode>, SystemError> = inode_begin.lookup_follow_symlink( 174 &path, 175 if follow_symlink { 176 VFS_MAX_FOLLOW_SYMLINK_TIMES 177 } else { 178 0 179 }, 180 ); 181 182 let inode: Arc<dyn IndexNode> = match inode { 183 Ok(inode) => inode, 184 Err(errno) => { 185 // 文件不存在,且需要创建 186 if how.o_flags.contains(FileMode::O_CREAT) 187 && !how.o_flags.contains(FileMode::O_DIRECTORY) 188 && errno == SystemError::ENOENT 189 { 190 let (filename, parent_path) = rsplit_path(&path); 191 // 查找父目录 192 let parent_inode: Arc<dyn IndexNode> = 193 ROOT_INODE().lookup(parent_path.unwrap_or("/"))?; 194 // 创建文件 195 let inode: Arc<dyn IndexNode> = parent_inode.create( 196 filename, 197 FileType::File, 198 ModeType::from_bits_truncate(0o755), 199 )?; 200 inode 201 } else { 202 // 不需要创建文件,因此返回错误码 203 return Err(errno); 204 } 205 } 206 }; 207 208 let file_type: FileType = inode.metadata()?.file_type; 209 // 如果要打开的是文件夹,而目标不是文件夹 210 if how.o_flags.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir { 211 return Err(SystemError::ENOTDIR); 212 } 213 214 // 创建文件对象 215 216 let file: File = File::new(inode, how.o_flags)?; 217 218 // 打开模式为“追加” 219 if how.o_flags.contains(FileMode::O_APPEND) { 220 file.lseek(SeekFrom::SeekEnd(0))?; 221 } 222 223 // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件 224 if how.o_flags.contains(FileMode::O_TRUNC) 225 && (how.o_flags.contains(FileMode::O_RDWR) || how.o_flags.contains(FileMode::O_WRONLY)) 226 && file_type == FileType::File 227 { 228 file.ftruncate(0)?; 229 } 230 // 把文件对象存入pcb 231 let r = ProcessManager::current_pcb() 232 .fd_table() 233 .write() 234 .alloc_fd(file, None) 235 .map(|fd| fd as usize); 236 237 return r; 238 } 239 240 /// On Linux, futimens() is a library function implemented on top of 241 /// the utimensat() system call. To support this, the Linux 242 /// utimensat() system call implements a nonstandard feature: if 243 /// pathname is NULL, then the call modifies the timestamps of the 244 /// file referred to by the file descriptor dirfd (which may refer to 245 /// any type of file). 246 pub fn do_utimensat( 247 dirfd: i32, 248 pathname: Option<String>, 249 times: Option<[PosixTimeSpec; 2]>, 250 flags: UtimensFlags, 251 ) -> Result<usize, SystemError> { 252 const UTIME_NOW: i64 = (1i64 << 30) - 1i64; 253 const UTIME_OMIT: i64 = (1i64 << 30) - 2i64; 254 // log::debug!("do_utimensat: dirfd:{}, pathname:{:?}, times:{:?}, flags:{:?}", dirfd, pathname, times, flags); 255 let inode = match pathname { 256 Some(path) => { 257 let (inode_begin, path) = 258 user_path_at(&ProcessManager::current_pcb(), dirfd, path.as_str())?; 259 let inode = if flags.contains(UtimensFlags::AT_SYMLINK_NOFOLLOW) { 260 inode_begin.lookup(path.as_str())? 261 } else { 262 inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)? 263 }; 264 inode 265 } 266 None => { 267 let binding = ProcessManager::current_pcb().fd_table(); 268 let fd_table_guard = binding.write(); 269 let file = fd_table_guard 270 .get_file_by_fd(dirfd) 271 .ok_or(SystemError::EBADF)?; 272 file.inode() 273 } 274 }; 275 let now = PosixTimeSpec::now(); 276 let mut meta = inode.metadata()?; 277 278 if let Some([atime, mtime]) = times { 279 if atime.tv_nsec == UTIME_NOW { 280 meta.atime = now; 281 } else if atime.tv_nsec != UTIME_OMIT { 282 meta.atime = atime; 283 } 284 if mtime.tv_nsec == UTIME_NOW { 285 meta.mtime = now; 286 } else if mtime.tv_nsec != UTIME_OMIT { 287 meta.mtime = mtime; 288 } 289 inode.set_metadata(&meta).unwrap(); 290 } else { 291 meta.atime = now; 292 meta.mtime = now; 293 inode.set_metadata(&meta).unwrap(); 294 } 295 return Ok(0); 296 } 297 298 pub fn do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError> { 299 // log::debug!("do_utimes: path:{:?}, times:{:?}", path, times); 300 let (inode_begin, path) = user_path_at( 301 &ProcessManager::current_pcb(), 302 AtFlags::AT_FDCWD.bits(), 303 path, 304 )?; 305 let inode = inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; 306 let mut meta = inode.metadata()?; 307 308 if let Some([atime, mtime]) = times { 309 meta.atime = PosixTimeSpec::from(atime); 310 meta.mtime = PosixTimeSpec::from(mtime); 311 inode.set_metadata(&meta)?; 312 } else { 313 let now = PosixTimeSpec::now(); 314 meta.atime = now; 315 meta.mtime = now; 316 inode.set_metadata(&meta)?; 317 } 318 return Ok(0); 319 } 320