123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- use alloc::sync::Arc;
- use log::warn;
- use system_error::SystemError;
- use super::{
- fcntl::AtFlags,
- file::{File, FileMode},
- syscall::{ModeType, OpenHow, OpenHowResolve},
- utils::{rsplit_path, user_path_at},
- FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
- };
- use crate::{
- driver::base::block::SeekFrom, process::ProcessManager,
- syscall::user_access::check_and_clone_cstr,
- };
- use crate::{filesystem::vfs::syscall::UtimensFlags, process::cred::Kgid};
- use crate::{
- process::cred::GroupInfo,
- time::{syscall::PosixTimeval, PosixTimeSpec},
- };
- use alloc::string::String;
- pub(super) fn do_faccessat(
- dirfd: i32,
- path: *const u8,
- mode: ModeType,
- flags: u32,
- ) -> Result<usize, SystemError> {
- if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 {
- return Err(SystemError::EINVAL);
- }
- if (flags
- & (!((AtFlags::AT_EACCESS | AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH).bits()
- as u32)))
- != 0
- {
- return Err(SystemError::EINVAL);
- }
- // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0;
- let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
- let path = path.to_str().map_err(|_| SystemError::EINVAL)?;
- let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
- // 如果找不到文件,则返回错误码ENOENT
- let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
- // todo: 接着完善(可以借鉴linux 6.1.9的do_faccessat)
- return Ok(0);
- }
- pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize, SystemError> {
- let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
- let path = path.to_str().map_err(|_| SystemError::EINVAL)?;
- let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
- // 如果找不到文件,则返回错误码ENOENT
- let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
- warn!("do_fchmodat: not implemented yet\n");
- // todo: 真正去改变文件的权限
- return Ok(0);
- }
- pub fn do_fchownat(
- dirfd: i32,
- path: &str,
- uid: usize,
- gid: usize,
- flag: AtFlags,
- ) -> Result<usize, SystemError> {
- // 检查flag是否合法
- if flag.contains(!(AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH)) {
- return Err(SystemError::EINVAL);
- }
- let follow_symlink = flag.contains(!AtFlags::AT_SYMLINK_NOFOLLOW);
- let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
- // 如果找不到文件,则返回错误码ENOENT
- let inode = if follow_symlink {
- inode.lookup_follow_symlink2(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES, false)
- } else {
- inode.lookup(path.as_str())
- };
- if inode.is_err() {
- let errno = inode.clone().unwrap_err();
- // 文件不存在
- if errno == SystemError::ENOENT {
- return Err(SystemError::ENOENT);
- }
- }
- let inode = inode.unwrap();
- return chown_common(inode, uid, gid);
- }
- fn chown_common(inode: Arc<dyn IndexNode>, uid: usize, gid: usize) -> Result<usize, SystemError> {
- let mut meta = inode.metadata()?;
- let cred = ProcessManager::current_pcb().cred();
- let current_uid = cred.uid.data();
- let current_gid = cred.gid.data();
- let mut group_info = GroupInfo::default();
- if let Some(info) = cred.group_info.as_ref() {
- group_info = info.clone();
- }
- // 检查权限
- match current_uid {
- 0 => {
- meta.uid = uid;
- meta.gid = gid;
- }
- _ => {
- // 非文件所有者不能更改信息,且不能更改uid
- if current_uid != meta.uid || uid != meta.uid {
- return Err(SystemError::EPERM);
- }
- if gid != current_gid && !group_info.gids.contains(&Kgid::from(gid)) {
- return Err(SystemError::EPERM);
- }
- meta.gid = gid;
- }
- }
- meta.mode.remove(ModeType::S_ISUID | ModeType::S_ISGID);
- inode.set_metadata(&meta)?;
- return Ok(0);
- }
- pub fn ksys_fchown(fd: i32, uid: usize, gid: usize) -> Result<usize, SystemError> {
- let fd_table = &ProcessManager::current_pcb().fd_table();
- let fd_table = fd_table.read();
- let inode = fd_table.get_file_by_fd(fd).unwrap().inode();
- let result = chown_common(inode, uid, gid);
- drop(fd_table);
- return result;
- }
- pub(super) fn do_sys_open(
- dfd: i32,
- path: &str,
- o_flags: FileMode,
- mode: ModeType,
- follow_symlink: bool,
- ) -> Result<usize, SystemError> {
- let how = OpenHow::new(o_flags, mode, OpenHowResolve::empty());
- return do_sys_openat2(dfd, path, how, follow_symlink);
- }
- fn do_sys_openat2(
- dirfd: i32,
- path: &str,
- how: OpenHow,
- follow_symlink: bool,
- ) -> Result<usize, SystemError> {
- // debug!("open path: {}, how: {:?}", path, how);
- let path = path.trim();
- let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
- let inode: Result<Arc<dyn IndexNode>, SystemError> = inode_begin.lookup_follow_symlink(
- &path,
- if follow_symlink {
- VFS_MAX_FOLLOW_SYMLINK_TIMES
- } else {
- 0
- },
- );
- let inode: Arc<dyn IndexNode> = match inode {
- Ok(inode) => inode,
- Err(errno) => {
- // 文件不存在,且需要创建
- if how.o_flags.contains(FileMode::O_CREAT)
- && !how.o_flags.contains(FileMode::O_DIRECTORY)
- && errno == SystemError::ENOENT
- {
- let (filename, parent_path) = rsplit_path(&path);
- // 查找父目录
- let parent_inode: Arc<dyn IndexNode> =
- ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
- // 创建文件
- let inode: Arc<dyn IndexNode> = parent_inode.create(
- filename,
- FileType::File,
- ModeType::from_bits_truncate(0o755),
- )?;
- inode
- } else {
- // 不需要创建文件,因此返回错误码
- return Err(errno);
- }
- }
- };
- let file_type: FileType = inode.metadata()?.file_type;
- // 如果要打开的是文件夹,而目标不是文件夹
- if how.o_flags.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir {
- return Err(SystemError::ENOTDIR);
- }
- // 创建文件对象
- let file: File = File::new(inode, how.o_flags)?;
- // 打开模式为“追加”
- if how.o_flags.contains(FileMode::O_APPEND) {
- file.lseek(SeekFrom::SeekEnd(0))?;
- }
- // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件
- if how.o_flags.contains(FileMode::O_TRUNC)
- && (how.o_flags.contains(FileMode::O_RDWR) || how.o_flags.contains(FileMode::O_WRONLY))
- && file_type == FileType::File
- {
- file.ftruncate(0)?;
- }
- // 把文件对象存入pcb
- let r = ProcessManager::current_pcb()
- .fd_table()
- .write()
- .alloc_fd(file, None)
- .map(|fd| fd as usize);
- return r;
- }
- /// On Linux, futimens() is a library function implemented on top of
- /// the utimensat() system call. To support this, the Linux
- /// utimensat() system call implements a nonstandard feature: if
- /// pathname is NULL, then the call modifies the timestamps of the
- /// file referred to by the file descriptor dirfd (which may refer to
- /// any type of file).
- pub fn do_utimensat(
- dirfd: i32,
- pathname: Option<String>,
- times: Option<[PosixTimeSpec; 2]>,
- flags: UtimensFlags,
- ) -> Result<usize, SystemError> {
- const UTIME_NOW: i64 = (1i64 << 30) - 1i64;
- const UTIME_OMIT: i64 = (1i64 << 30) - 2i64;
- // log::debug!("do_utimensat: dirfd:{}, pathname:{:?}, times:{:?}, flags:{:?}", dirfd, pathname, times, flags);
- let inode = match pathname {
- Some(path) => {
- let (inode_begin, path) =
- user_path_at(&ProcessManager::current_pcb(), dirfd, path.as_str())?;
- let inode = if flags.contains(UtimensFlags::AT_SYMLINK_NOFOLLOW) {
- inode_begin.lookup(path.as_str())?
- } else {
- inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?
- };
- inode
- }
- None => {
- let binding = ProcessManager::current_pcb().fd_table();
- let fd_table_guard = binding.write();
- let file = fd_table_guard
- .get_file_by_fd(dirfd)
- .ok_or(SystemError::EBADF)?;
- file.inode()
- }
- };
- let now = PosixTimeSpec::now();
- let mut meta = inode.metadata()?;
- if let Some([atime, mtime]) = times {
- if atime.tv_nsec == UTIME_NOW {
- meta.atime = now;
- } else if atime.tv_nsec != UTIME_OMIT {
- meta.atime = atime;
- }
- if mtime.tv_nsec == UTIME_NOW {
- meta.mtime = now;
- } else if mtime.tv_nsec != UTIME_OMIT {
- meta.mtime = mtime;
- }
- inode.set_metadata(&meta).unwrap();
- } else {
- meta.atime = now;
- meta.mtime = now;
- inode.set_metadata(&meta).unwrap();
- }
- return Ok(0);
- }
- pub fn do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError> {
- // log::debug!("do_utimes: path:{:?}, times:{:?}", path, times);
- let (inode_begin, path) = user_path_at(
- &ProcessManager::current_pcb(),
- AtFlags::AT_FDCWD.bits(),
- path,
- )?;
- let inode = inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
- let mut meta = inode.metadata()?;
- if let Some([atime, mtime]) = times {
- meta.atime = PosixTimeSpec::from(atime);
- meta.mtime = PosixTimeSpec::from(mtime);
- inode.set_metadata(&meta)?;
- } else {
- let now = PosixTimeSpec::now();
- meta.atime = now;
- meta.mtime = now;
- inode.set_metadata(&meta)?;
- }
- return Ok(0);
- }
|