mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-11 09:06:47 +00:00
uevent should be format Enum of smoltcp socket should be optimized. need to add interface for routing subsys actix is still not abled to run. clean some casual added code to other places
235 lines
7.6 KiB
Rust
235 lines
7.6 KiB
Rust
use alloc::sync::Arc;
|
||
use log::{debug, 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::filesystem::vfs::syscall::UtimensFlags;
|
||
use crate::time::{syscall::PosixTimeval, PosixTimeSpec};
|
||
use crate::{
|
||
driver::base::block::SeekFrom, process::ProcessManager,
|
||
syscall::user_access::check_and_clone_cstr,
|
||
};
|
||
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(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);
|
||
}
|