mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-18 08:06:32 +00:00
feat:添加chown系统调用 (#962)
* 添加chown系统调用 --------- Co-authored-by: sparkzky <sparkhhhhhhhhh@outlook.com> Co-authored-by: longjin <longjin@DragonOS.org>
This commit is contained in:
@ -598,17 +598,43 @@ impl dyn IndexNode {
|
||||
return self.lookup_follow_symlink(path, 0);
|
||||
}
|
||||
|
||||
/// @brief 查找文件(考虑符号链接)
|
||||
///
|
||||
/// @param path 文件路径
|
||||
/// @param max_follow_times 最大经过的符号链接的大小
|
||||
///
|
||||
/// @return Ok(Arc<dyn IndexNode>) 要寻找的目录项的inode
|
||||
/// @return Err(SystemError) 错误码
|
||||
pub fn lookup_follow_symlink(
|
||||
&self,
|
||||
path: &str,
|
||||
max_follow_times: usize,
|
||||
) -> Result<Arc<dyn IndexNode>, SystemError> {
|
||||
return self.do_lookup_follow_symlink(path, max_follow_times, true);
|
||||
}
|
||||
|
||||
pub fn lookup_follow_symlink2(
|
||||
&self,
|
||||
path: &str,
|
||||
max_follow_times: usize,
|
||||
follow_final_symlink: bool,
|
||||
) -> Result<Arc<dyn IndexNode>, SystemError> {
|
||||
return self.do_lookup_follow_symlink(path, max_follow_times, follow_final_symlink);
|
||||
}
|
||||
|
||||
/// # 查找文件
|
||||
/// 查找指定路径的文件,考虑符号链接的存在,并可选择是否返回最终路径的符号链接文件本身。
|
||||
///
|
||||
/// ## 参数
|
||||
/// - `path`: 文件路径
|
||||
/// - `max_follow_times`: 最大经过的符号链接的数量
|
||||
/// - `follow_final_symlink`: 是否跟随最后的符号链接
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - `Ok(Arc<dyn IndexNode>)`: 要寻找的目录项的inode
|
||||
/// - `Err(SystemError)`: 错误码,表示查找过程中遇到的错误
|
||||
///
|
||||
/// ## Safety
|
||||
/// 此函数在处理符号链接时可能会遇到循环引用的情况,`max_follow_times` 参数用于限制符号链接的跟随次数以避免无限循环。
|
||||
#[inline(never)]
|
||||
pub fn do_lookup_follow_symlink(
|
||||
&self,
|
||||
path: &str,
|
||||
max_follow_times: usize,
|
||||
follow_final_symlink: bool,
|
||||
) -> Result<Arc<dyn IndexNode>, SystemError> {
|
||||
if self.metadata()?.file_type != FileType::Dir {
|
||||
return Err(SystemError::ENOTDIR);
|
||||
@ -632,13 +658,10 @@ impl dyn IndexNode {
|
||||
}
|
||||
|
||||
let name;
|
||||
|
||||
// 寻找“/”
|
||||
match rest_path.find('/') {
|
||||
Some(pos) => {
|
||||
// 找到了,设置下一个要查找的名字
|
||||
name = String::from(&rest_path[0..pos]);
|
||||
// 剩余的路径字符串
|
||||
rest_path = String::from(&rest_path[pos + 1..]);
|
||||
}
|
||||
None => {
|
||||
@ -653,11 +676,18 @@ impl dyn IndexNode {
|
||||
}
|
||||
|
||||
let inode = result.find(&name)?;
|
||||
let file_type = inode.metadata()?.file_type;
|
||||
// 如果已经是路径的最后一个部分,并且不希望跟随最后的符号链接
|
||||
if rest_path.is_empty() && !follow_final_symlink && file_type == FileType::SymLink {
|
||||
// 返回符号链接本身
|
||||
return Ok(inode);
|
||||
}
|
||||
|
||||
// 处理符号链接的问题
|
||||
if inode.metadata()?.file_type == FileType::SymLink && max_follow_times > 0 {
|
||||
// 跟随符号链接跳转
|
||||
if file_type == FileType::SymLink && max_follow_times > 0 {
|
||||
let mut content = [0u8; 256];
|
||||
// 读取符号链接
|
||||
|
||||
let len = inode.read_at(
|
||||
0,
|
||||
256,
|
||||
@ -667,12 +697,16 @@ impl dyn IndexNode {
|
||||
|
||||
// 将读到的数据转换为utf8字符串(先转为str,再转为String)
|
||||
let link_path = String::from(
|
||||
::core::str::from_utf8(&content[..len]).map_err(|_| SystemError::ENOTDIR)?,
|
||||
::core::str::from_utf8(&content[..len]).map_err(|_| SystemError::EINVAL)?,
|
||||
);
|
||||
|
||||
let new_path = link_path + "/" + &rest_path;
|
||||
|
||||
// 继续查找符号链接
|
||||
return result.lookup_follow_symlink(&new_path, max_follow_times - 1);
|
||||
return result.lookup_follow_symlink2(
|
||||
&new_path,
|
||||
max_follow_times - 1,
|
||||
follow_final_symlink,
|
||||
);
|
||||
} else {
|
||||
result = inode;
|
||||
}
|
||||
|
@ -9,12 +9,15 @@ use super::{
|
||||
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 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(
|
||||
@ -64,6 +67,88 @@ pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize
|
||||
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,
|
||||
|
@ -25,7 +25,9 @@ use super::{
|
||||
core::{do_mkdir_at, do_remove_dir, do_unlink_at},
|
||||
fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
|
||||
file::{File, FileMode},
|
||||
open::{do_faccessat, do_fchmodat, do_sys_open, do_utimensat, do_utimes},
|
||||
open::{
|
||||
do_faccessat, do_fchmodat, do_fchownat, do_sys_open, do_utimensat, do_utimes, ksys_fchown,
|
||||
},
|
||||
utils::{rsplit_path, user_path_at},
|
||||
Dirent, FileType, IndexNode, SuperBlock, FSMAKER, MAX_PATHLEN, ROOT_INODE,
|
||||
VFS_MAX_FOLLOW_SYMLINK_TIMES,
|
||||
@ -1638,6 +1640,52 @@ impl Syscall {
|
||||
warn!("fchmod not fully implemented");
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
pub fn chown(pathname: *const u8, uid: usize, gid: usize) -> Result<usize, SystemError> {
|
||||
let pathname = user_access::check_and_clone_cstr(pathname, Some(MAX_PATHLEN))?
|
||||
.into_string()
|
||||
.map_err(|_| SystemError::EINVAL)?;
|
||||
return do_fchownat(
|
||||
AtFlags::AT_FDCWD.bits(),
|
||||
&pathname,
|
||||
uid,
|
||||
gid,
|
||||
AtFlags::AT_STATX_SYNC_AS_STAT,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn lchown(pathname: *const u8, uid: usize, gid: usize) -> Result<usize, SystemError> {
|
||||
let pathname = user_access::check_and_clone_cstr(pathname, Some(MAX_PATHLEN))?
|
||||
.into_string()
|
||||
.map_err(|_| SystemError::EINVAL)?;
|
||||
return do_fchownat(
|
||||
AtFlags::AT_FDCWD.bits(),
|
||||
&pathname,
|
||||
uid,
|
||||
gid,
|
||||
AtFlags::AT_SYMLINK_NOFOLLOW,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn fchownat(
|
||||
dirfd: i32,
|
||||
pathname: *const u8,
|
||||
uid: usize,
|
||||
gid: usize,
|
||||
flags: i32,
|
||||
) -> Result<usize, SystemError> {
|
||||
let pathname = user_access::check_and_clone_cstr(pathname, Some(MAX_PATHLEN))?
|
||||
.into_string()
|
||||
.map_err(|_| SystemError::EINVAL)?;
|
||||
let pathname = pathname.as_str().trim();
|
||||
let flags = AtFlags::from_bits_truncate(flags);
|
||||
return do_fchownat(dirfd, pathname, uid, gid, flags);
|
||||
}
|
||||
|
||||
pub fn fchown(fd: i32, uid: usize, gid: usize) -> Result<usize, SystemError> {
|
||||
return ksys_fchown(fd, uid, gid);
|
||||
}
|
||||
|
||||
/// #挂载文件系统
|
||||
///
|
||||
/// 用于挂载文件系统,目前仅支持ramfs挂载
|
||||
|
@ -164,7 +164,7 @@ impl Cred {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct GroupInfo {
|
||||
pub gids: Vec<Kgid>,
|
||||
}
|
||||
|
@ -997,8 +997,32 @@ impl Syscall {
|
||||
}
|
||||
|
||||
SYS_FCHOWN => {
|
||||
warn!("SYS_FCHOWN has not yet been implemented");
|
||||
Ok(0)
|
||||
let dirfd = args[0] as i32;
|
||||
let uid = args[1];
|
||||
let gid = args[2];
|
||||
Self::fchown(dirfd, uid, gid)
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
SYS_CHOWN => {
|
||||
let pathname = args[0] as *const u8;
|
||||
let uid = args[1];
|
||||
let gid = args[2];
|
||||
Self::chown(pathname, uid, gid)
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
SYS_LCHOWN => {
|
||||
let pathname = args[0] as *const u8;
|
||||
let uid = args[1];
|
||||
let gid = args[2];
|
||||
Self::lchown(pathname, uid, gid)
|
||||
}
|
||||
SYS_FCHOWNAT => {
|
||||
let dirfd = args[0] as i32;
|
||||
let pathname = args[1] as *const u8;
|
||||
let uid = args[2];
|
||||
let gid = args[3];
|
||||
let flag = args[4] as i32;
|
||||
Self::fchownat(dirfd, pathname, uid, gid, flag)
|
||||
}
|
||||
|
||||
SYS_FSYNC => {
|
||||
|
Reference in New Issue
Block a user