10fb515b0SLoGin use alloc::sync::Arc; 22eab6dd7S曾俊 use log::warn; 391e9d4abSLoGin use system_error::SystemError; 40fb515b0SLoGin 5bf4a4899SLoGin use super::{ 60fb515b0SLoGin fcntl::AtFlags, 70fb515b0SLoGin file::{File, FileMode}, 80fb515b0SLoGin syscall::{ModeType, OpenHow, OpenHowResolve}, 90fb515b0SLoGin utils::{rsplit_path, user_path_at}, 100fb515b0SLoGin FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES, 11bf4a4899SLoGin }; 12*6f189d27Slinfeng use crate::filesystem::vfs::syscall::UtimensFlags; 13*6f189d27Slinfeng use crate::time::{syscall::PosixTimeval, PosixTimeSpec}; 14*6f189d27Slinfeng use crate::{ 15*6f189d27Slinfeng driver::base::block::SeekFrom, process::ProcessManager, 16*6f189d27Slinfeng syscall::user_access::check_and_clone_cstr, 17*6f189d27Slinfeng }; 18*6f189d27Slinfeng use alloc::string::String; 199b0abe6dSLoGin 209b0abe6dSLoGin pub(super) fn do_faccessat( 21bf4a4899SLoGin dirfd: i32, 22bf4a4899SLoGin path: *const u8, 239b0abe6dSLoGin mode: ModeType, 249b0abe6dSLoGin flags: u32, 259b0abe6dSLoGin ) -> Result<usize, SystemError> { 26bf4a4899SLoGin if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 { 279b0abe6dSLoGin return Err(SystemError::EINVAL); 289b0abe6dSLoGin } 299b0abe6dSLoGin 309b0abe6dSLoGin if (flags 319b0abe6dSLoGin & (!((AtFlags::AT_EACCESS | AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH).bits() 329b0abe6dSLoGin as u32))) 339b0abe6dSLoGin != 0 349b0abe6dSLoGin { 359b0abe6dSLoGin return Err(SystemError::EINVAL); 369b0abe6dSLoGin } 379b0abe6dSLoGin 389b0abe6dSLoGin // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0; 399b0abe6dSLoGin 40bf4a4899SLoGin let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; 41bf4a4899SLoGin 420fb515b0SLoGin let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, &path)?; 43bf4a4899SLoGin 44bf4a4899SLoGin // 如果找不到文件,则返回错误码ENOENT 45bf4a4899SLoGin let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; 46bf4a4899SLoGin 479b0abe6dSLoGin // todo: 接着完善(可以借鉴linux 6.1.9的do_faccessat) 489b0abe6dSLoGin return Ok(0); 499b0abe6dSLoGin } 50bf4a4899SLoGin 51bf4a4899SLoGin pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize, SystemError> { 52bf4a4899SLoGin let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?; 53bf4a4899SLoGin 540fb515b0SLoGin let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, &path)?; 55bf4a4899SLoGin 56bf4a4899SLoGin // 如果找不到文件,则返回错误码ENOENT 57bf4a4899SLoGin let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; 58bf4a4899SLoGin 592eab6dd7S曾俊 warn!("do_fchmodat: not implemented yet\n"); 60bf4a4899SLoGin // todo: 真正去改变文件的权限 61bf4a4899SLoGin 62bf4a4899SLoGin return Ok(0); 63bf4a4899SLoGin } 640fb515b0SLoGin 650fb515b0SLoGin pub(super) fn do_sys_open( 660fb515b0SLoGin dfd: i32, 670fb515b0SLoGin path: &str, 680fb515b0SLoGin o_flags: FileMode, 690fb515b0SLoGin mode: ModeType, 700fb515b0SLoGin follow_symlink: bool, 710fb515b0SLoGin ) -> Result<usize, SystemError> { 720fb515b0SLoGin let how = OpenHow::new(o_flags, mode, OpenHowResolve::empty()); 730fb515b0SLoGin return do_sys_openat2(dfd, path, how, follow_symlink); 740fb515b0SLoGin } 750fb515b0SLoGin 760fb515b0SLoGin fn do_sys_openat2( 770fb515b0SLoGin dirfd: i32, 780fb515b0SLoGin path: &str, 790fb515b0SLoGin how: OpenHow, 800fb515b0SLoGin follow_symlink: bool, 810fb515b0SLoGin ) -> Result<usize, SystemError> { 822eab6dd7S曾俊 // debug!("open path: {}, how: {:?}", path, how); 8382df0a13Shmt let path = path.trim(); 8482df0a13Shmt 850fb515b0SLoGin let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?; 860fb515b0SLoGin let inode: Result<Arc<dyn IndexNode>, SystemError> = inode_begin.lookup_follow_symlink( 870fb515b0SLoGin &path, 880fb515b0SLoGin if follow_symlink { 890fb515b0SLoGin VFS_MAX_FOLLOW_SYMLINK_TIMES 900fb515b0SLoGin } else { 910fb515b0SLoGin 0 920fb515b0SLoGin }, 930fb515b0SLoGin ); 940fb515b0SLoGin 95b5b571e0SLoGin let inode: Arc<dyn IndexNode> = match inode { 96b5b571e0SLoGin Ok(inode) => inode, 97b5b571e0SLoGin Err(errno) => { 980fb515b0SLoGin // 文件不存在,且需要创建 990fb515b0SLoGin if how.o_flags.contains(FileMode::O_CREAT) 1000fb515b0SLoGin && !how.o_flags.contains(FileMode::O_DIRECTORY) 1010fb515b0SLoGin && errno == SystemError::ENOENT 1020fb515b0SLoGin { 1030fb515b0SLoGin let (filename, parent_path) = rsplit_path(&path); 1040fb515b0SLoGin // 查找父目录 1050fb515b0SLoGin let parent_inode: Arc<dyn IndexNode> = 1060fb515b0SLoGin ROOT_INODE().lookup(parent_path.unwrap_or("/"))?; 1070fb515b0SLoGin // 创建文件 1080fb515b0SLoGin let inode: Arc<dyn IndexNode> = parent_inode.create( 1090fb515b0SLoGin filename, 1100fb515b0SLoGin FileType::File, 1110fb515b0SLoGin ModeType::from_bits_truncate(0o755), 1120fb515b0SLoGin )?; 1130fb515b0SLoGin inode 1140fb515b0SLoGin } else { 1150fb515b0SLoGin // 不需要创建文件,因此返回错误码 1160fb515b0SLoGin return Err(errno); 1170fb515b0SLoGin } 118b5b571e0SLoGin } 1190fb515b0SLoGin }; 1200fb515b0SLoGin 1210fb515b0SLoGin let file_type: FileType = inode.metadata()?.file_type; 1220fb515b0SLoGin // 如果要打开的是文件夹,而目标不是文件夹 1230fb515b0SLoGin if how.o_flags.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir { 1240fb515b0SLoGin return Err(SystemError::ENOTDIR); 1250fb515b0SLoGin } 1260fb515b0SLoGin 1270fb515b0SLoGin // 创建文件对象 1280fb515b0SLoGin 129dfe53cf0SGnoCiYeH let file: File = File::new(inode, how.o_flags)?; 1300fb515b0SLoGin 1310fb515b0SLoGin // 打开模式为“追加” 1320fb515b0SLoGin if how.o_flags.contains(FileMode::O_APPEND) { 1330fb515b0SLoGin file.lseek(SeekFrom::SeekEnd(0))?; 1340fb515b0SLoGin } 1350fb515b0SLoGin 1360fb515b0SLoGin // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件 1370fb515b0SLoGin if how.o_flags.contains(FileMode::O_TRUNC) 1380fb515b0SLoGin && (how.o_flags.contains(FileMode::O_RDWR) || how.o_flags.contains(FileMode::O_WRONLY)) 1390fb515b0SLoGin && file_type == FileType::File 1400fb515b0SLoGin { 1410fb515b0SLoGin file.ftruncate(0)?; 1420fb515b0SLoGin } 1430fb515b0SLoGin // 把文件对象存入pcb 1440fb515b0SLoGin let r = ProcessManager::current_pcb() 1450fb515b0SLoGin .fd_table() 1460fb515b0SLoGin .write() 1470fb515b0SLoGin .alloc_fd(file, None) 1480fb515b0SLoGin .map(|fd| fd as usize); 1490fb515b0SLoGin 1500fb515b0SLoGin return r; 1510fb515b0SLoGin } 152*6f189d27Slinfeng 153*6f189d27Slinfeng /// On Linux, futimens() is a library function implemented on top of 154*6f189d27Slinfeng /// the utimensat() system call. To support this, the Linux 155*6f189d27Slinfeng /// utimensat() system call implements a nonstandard feature: if 156*6f189d27Slinfeng /// pathname is NULL, then the call modifies the timestamps of the 157*6f189d27Slinfeng /// file referred to by the file descriptor dirfd (which may refer to 158*6f189d27Slinfeng /// any type of file). 159*6f189d27Slinfeng pub fn do_utimensat( 160*6f189d27Slinfeng dirfd: i32, 161*6f189d27Slinfeng pathname: Option<String>, 162*6f189d27Slinfeng times: Option<[PosixTimeSpec; 2]>, 163*6f189d27Slinfeng flags: UtimensFlags, 164*6f189d27Slinfeng ) -> Result<usize, SystemError> { 165*6f189d27Slinfeng const UTIME_NOW: i64 = (1i64 << 30) - 1i64; 166*6f189d27Slinfeng const UTIME_OMIT: i64 = (1i64 << 30) - 2i64; 167*6f189d27Slinfeng // log::debug!("do_utimensat: dirfd:{}, pathname:{:?}, times:{:?}, flags:{:?}", dirfd, pathname, times, flags); 168*6f189d27Slinfeng let inode = match pathname { 169*6f189d27Slinfeng Some(path) => { 170*6f189d27Slinfeng let (inode_begin, path) = 171*6f189d27Slinfeng user_path_at(&ProcessManager::current_pcb(), dirfd, path.as_str())?; 172*6f189d27Slinfeng let inode = if flags.contains(UtimensFlags::AT_SYMLINK_NOFOLLOW) { 173*6f189d27Slinfeng inode_begin.lookup(path.as_str())? 174*6f189d27Slinfeng } else { 175*6f189d27Slinfeng inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)? 176*6f189d27Slinfeng }; 177*6f189d27Slinfeng inode 178*6f189d27Slinfeng } 179*6f189d27Slinfeng None => { 180*6f189d27Slinfeng let binding = ProcessManager::current_pcb().fd_table(); 181*6f189d27Slinfeng let fd_table_guard = binding.write(); 182*6f189d27Slinfeng let file = fd_table_guard 183*6f189d27Slinfeng .get_file_by_fd(dirfd) 184*6f189d27Slinfeng .ok_or(SystemError::EBADF)?; 185*6f189d27Slinfeng file.inode() 186*6f189d27Slinfeng } 187*6f189d27Slinfeng }; 188*6f189d27Slinfeng let now = PosixTimeSpec::now(); 189*6f189d27Slinfeng let mut meta = inode.metadata()?; 190*6f189d27Slinfeng 191*6f189d27Slinfeng if let Some([atime, mtime]) = times { 192*6f189d27Slinfeng if atime.tv_nsec == UTIME_NOW { 193*6f189d27Slinfeng meta.atime = now; 194*6f189d27Slinfeng } else if atime.tv_nsec != UTIME_OMIT { 195*6f189d27Slinfeng meta.atime = atime; 196*6f189d27Slinfeng } 197*6f189d27Slinfeng if mtime.tv_nsec == UTIME_NOW { 198*6f189d27Slinfeng meta.mtime = now; 199*6f189d27Slinfeng } else if mtime.tv_nsec != UTIME_OMIT { 200*6f189d27Slinfeng meta.mtime = mtime; 201*6f189d27Slinfeng } 202*6f189d27Slinfeng inode.set_metadata(&meta).unwrap(); 203*6f189d27Slinfeng } else { 204*6f189d27Slinfeng meta.atime = now; 205*6f189d27Slinfeng meta.mtime = now; 206*6f189d27Slinfeng inode.set_metadata(&meta).unwrap(); 207*6f189d27Slinfeng } 208*6f189d27Slinfeng return Ok(0); 209*6f189d27Slinfeng } 210*6f189d27Slinfeng 211*6f189d27Slinfeng pub fn do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError> { 212*6f189d27Slinfeng // log::debug!("do_utimes: path:{:?}, times:{:?}", path, times); 213*6f189d27Slinfeng let (inode_begin, path) = user_path_at( 214*6f189d27Slinfeng &ProcessManager::current_pcb(), 215*6f189d27Slinfeng AtFlags::AT_FDCWD.bits(), 216*6f189d27Slinfeng path, 217*6f189d27Slinfeng )?; 218*6f189d27Slinfeng let inode = inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?; 219*6f189d27Slinfeng let mut meta = inode.metadata()?; 220*6f189d27Slinfeng 221*6f189d27Slinfeng if let Some([atime, mtime]) = times { 222*6f189d27Slinfeng meta.atime = PosixTimeSpec::from(atime); 223*6f189d27Slinfeng meta.mtime = PosixTimeSpec::from(mtime); 224*6f189d27Slinfeng inode.set_metadata(&meta)?; 225*6f189d27Slinfeng } else { 226*6f189d27Slinfeng let now = PosixTimeSpec::now(); 227*6f189d27Slinfeng meta.atime = now; 228*6f189d27Slinfeng meta.mtime = now; 229*6f189d27Slinfeng inode.set_metadata(&meta)?; 230*6f189d27Slinfeng } 231*6f189d27Slinfeng return Ok(0); 232*6f189d27Slinfeng } 233