Add support for symlink and readlink syscall
This commit is contained in:
parent
4e3dfe93da
commit
df82142c9d
|
|
@ -64,6 +64,9 @@ impl Dentry {
|
|||
}
|
||||
|
||||
pub fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<Self>> {
|
||||
if self.vnode.inode().metadata().type_ != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
let mut inner = self.inner.write();
|
||||
if inner.children.get(name).is_some() {
|
||||
return_errno!(Errno::EEXIST);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ use crate::syscall::poll::sys_poll;
|
|||
use crate::syscall::prctl::sys_prctl;
|
||||
use crate::syscall::prlimit64::sys_prlimit64;
|
||||
use crate::syscall::read::sys_read;
|
||||
use crate::syscall::readlink::sys_readlink;
|
||||
use crate::syscall::readlink::{sys_readlink, sys_readlinkat};
|
||||
use crate::syscall::rmdir::sys_rmdir;
|
||||
use crate::syscall::rt_sigaction::sys_rt_sigaction;
|
||||
use crate::syscall::rt_sigprocmask::sys_rt_sigprocmask;
|
||||
|
|
@ -46,6 +46,7 @@ use crate::syscall::set_robust_list::sys_set_robust_list;
|
|||
use crate::syscall::set_tid_address::sys_set_tid_address;
|
||||
use crate::syscall::setpgid::sys_setpgid;
|
||||
use crate::syscall::stat::{sys_fstat, sys_fstatat, sys_lstat, sys_stat};
|
||||
use crate::syscall::symlink::{sys_symlink, sys_symlinkat};
|
||||
use crate::syscall::tgkill::sys_tgkill;
|
||||
use crate::syscall::uname::sys_uname;
|
||||
use crate::syscall::unlink::{sys_unlink, sys_unlinkat};
|
||||
|
|
@ -101,6 +102,7 @@ mod set_robust_list;
|
|||
mod set_tid_address;
|
||||
mod setpgid;
|
||||
mod stat;
|
||||
mod symlink;
|
||||
mod tgkill;
|
||||
mod uname;
|
||||
mod unlink;
|
||||
|
|
@ -175,6 +177,7 @@ define_syscall_nums!(
|
|||
SYS_RMDIR = 84,
|
||||
SYS_LINK = 86,
|
||||
SYS_UNLINK = 87,
|
||||
SYS_SYMLINK = 88,
|
||||
SYS_READLINK = 89,
|
||||
SYS_GETUID = 102,
|
||||
SYS_GETGID = 104,
|
||||
|
|
@ -197,6 +200,8 @@ define_syscall_nums!(
|
|||
SYS_FSTATAT = 262,
|
||||
SYS_UNLINKAT = 263,
|
||||
SYS_LINKAT = 265,
|
||||
SYS_SYMLINKAT = 266,
|
||||
SYS_READLINKAT = 267,
|
||||
SYS_SET_ROBUST_LIST = 273,
|
||||
SYS_PRLIMIT64 = 302
|
||||
);
|
||||
|
|
@ -292,6 +297,7 @@ pub fn syscall_dispatch(
|
|||
SYS_RMDIR => syscall_handler!(1, sys_rmdir, args),
|
||||
SYS_LINK => syscall_handler!(2, sys_link, args),
|
||||
SYS_UNLINK => syscall_handler!(1, sys_unlink, args),
|
||||
SYS_SYMLINK => syscall_handler!(2, sys_symlink, args),
|
||||
SYS_READLINK => syscall_handler!(3, sys_readlink, args),
|
||||
SYS_GETUID => syscall_handler!(0, sys_getuid),
|
||||
SYS_GETGID => syscall_handler!(0, sys_getgid),
|
||||
|
|
@ -314,6 +320,8 @@ pub fn syscall_dispatch(
|
|||
SYS_FSTATAT => syscall_handler!(4, sys_fstatat, args),
|
||||
SYS_UNLINKAT => syscall_handler!(3, sys_unlinkat, args),
|
||||
SYS_LINKAT => syscall_handler!(5, sys_linkat, args),
|
||||
SYS_SYMLINKAT => syscall_handler!(3, sys_symlinkat, args),
|
||||
SYS_READLINKAT => syscall_handler!(4, sys_readlinkat, args),
|
||||
SYS_SET_ROBUST_LIST => syscall_handler!(2, sys_set_robust_list, args),
|
||||
SYS_PRLIMIT64 => syscall_handler!(4, sys_prlimit64, args),
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -1,54 +1,60 @@
|
|||
use crate::{log_syscall_entry, prelude::*};
|
||||
|
||||
use crate::syscall::SYS_READLINK;
|
||||
use crate::util::{read_bytes_from_user, write_bytes_to_user};
|
||||
use crate::fs::{
|
||||
file_table::FileDescripter,
|
||||
fs_resolver::{FsPath, AT_FDCWD},
|
||||
};
|
||||
use crate::log_syscall_entry;
|
||||
use crate::prelude::*;
|
||||
use crate::syscall::constants::MAX_FILENAME_LEN;
|
||||
use crate::util::{read_cstring_from_user, write_bytes_to_user};
|
||||
|
||||
use super::SyscallReturn;
|
||||
use super::SYS_READLINKAT;
|
||||
|
||||
const MAX_FILENAME_LEN: usize = 128;
|
||||
|
||||
pub fn sys_readlink(
|
||||
filename_ptr: u64,
|
||||
user_buf_ptr: u64,
|
||||
user_buf_len: u64,
|
||||
pub fn sys_readlinkat(
|
||||
dirfd: FileDescripter,
|
||||
pathname_addr: Vaddr,
|
||||
usr_buf_addr: Vaddr,
|
||||
usr_buf_len: usize,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_READLINK);
|
||||
let res = do_sys_readlink(
|
||||
filename_ptr as Vaddr,
|
||||
user_buf_ptr as Vaddr,
|
||||
user_buf_len as usize,
|
||||
)?;
|
||||
Ok(SyscallReturn::Return(res as _))
|
||||
}
|
||||
|
||||
/// do sys readlink
|
||||
/// write the content to user buffer, returns the actual write len
|
||||
pub fn do_sys_readlink(
|
||||
filename_ptr: Vaddr,
|
||||
user_buf_ptr: Vaddr,
|
||||
user_buf_len: usize,
|
||||
) -> Result<usize> {
|
||||
log_syscall_entry!(SYS_READLINKAT);
|
||||
let pathname = read_cstring_from_user(pathname_addr, MAX_FILENAME_LEN)?;
|
||||
debug!(
|
||||
"filename ptr = 0x{:x}, user_buf_ptr = 0x{:x}, user_buf_len = 0x{:x}",
|
||||
filename_ptr, user_buf_ptr, user_buf_len
|
||||
"dirfd = {}, pathname = {:?}, usr_buf_addr = 0x{:x}, usr_buf_len = 0x{:x}",
|
||||
dirfd, pathname, usr_buf_addr, usr_buf_len
|
||||
);
|
||||
|
||||
let mut filename_buffer = [0u8; MAX_FILENAME_LEN];
|
||||
let current = current!();
|
||||
read_bytes_from_user(filename_ptr, &mut filename_buffer)?;
|
||||
let filename = CStr::from_bytes_until_nul(&filename_buffer).expect("Invalid filename");
|
||||
debug!("filename = {:?}", filename);
|
||||
if filename == CString::new("/proc/self/exe").unwrap().as_c_str() {
|
||||
if pathname == CString::new("/proc/self/exe")? {
|
||||
// "proc/self/exe" is used to read the filename of current executable
|
||||
let process_file_name = current.filename().unwrap();
|
||||
debug!("process exec filename= {:?}", process_file_name);
|
||||
let bytes = process_file_name.as_bytes_with_nul();
|
||||
let bytes_len = bytes.len();
|
||||
let write_len = bytes_len.min(user_buf_len);
|
||||
|
||||
write_bytes_to_user(user_buf_ptr, &bytes[..write_len])?;
|
||||
return Ok(write_len);
|
||||
// readlink does not append a terminating null byte to buf
|
||||
let bytes = process_file_name.as_bytes();
|
||||
let write_len = bytes.len().min(usr_buf_len);
|
||||
write_bytes_to_user(usr_buf_addr, &bytes[..write_len])?;
|
||||
return Ok(SyscallReturn::Return(write_len as _));
|
||||
}
|
||||
|
||||
panic!("does not support linkname other than /proc/self/exe")
|
||||
// The common path
|
||||
let dentry = {
|
||||
let pathname = pathname.to_string_lossy();
|
||||
if pathname.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||
}
|
||||
let fs_path = FsPath::new(dirfd, pathname.as_ref())?;
|
||||
current.fs().read().lookup_no_follow(&fs_path)?
|
||||
};
|
||||
let linkpath = dentry.vnode().inode().read_link()?;
|
||||
let bytes = linkpath.as_bytes();
|
||||
let write_len = bytes.len().min(usr_buf_len);
|
||||
write_bytes_to_user(usr_buf_addr, &bytes[..write_len])?;
|
||||
Ok(SyscallReturn::Return(write_len as _))
|
||||
}
|
||||
|
||||
pub fn sys_readlink(
|
||||
pathname_addr: Vaddr,
|
||||
usr_buf_addr: Vaddr,
|
||||
usr_buf_len: usize,
|
||||
) -> Result<SyscallReturn> {
|
||||
self::sys_readlinkat(AT_FDCWD, pathname_addr, usr_buf_addr, usr_buf_len)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
use crate::fs::{
|
||||
file_table::FileDescripter,
|
||||
fs_resolver::{FsPath, AT_FDCWD},
|
||||
utils::{InodeMode, InodeType},
|
||||
};
|
||||
use crate::log_syscall_entry;
|
||||
use crate::prelude::*;
|
||||
use crate::syscall::constants::MAX_FILENAME_LEN;
|
||||
use crate::util::read_cstring_from_user;
|
||||
|
||||
use super::SyscallReturn;
|
||||
use super::SYS_SYMLINKAT;
|
||||
|
||||
pub fn sys_symlinkat(
|
||||
target_addr: Vaddr,
|
||||
dirfd: FileDescripter,
|
||||
linkpath_addr: Vaddr,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_SYMLINKAT);
|
||||
let target = read_cstring_from_user(target_addr, MAX_FILENAME_LEN)?;
|
||||
let linkpath = read_cstring_from_user(linkpath_addr, MAX_FILENAME_LEN)?;
|
||||
debug!(
|
||||
"target = {:?}, dirfd = {}, linkpath = {:?}",
|
||||
target, dirfd, linkpath
|
||||
);
|
||||
|
||||
let current = current!();
|
||||
let target = target.to_string_lossy();
|
||||
if target.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "target is empty");
|
||||
}
|
||||
let (dir_dentry, link_name) = {
|
||||
let linkpath = linkpath.to_string_lossy();
|
||||
if linkpath.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "linkpath is empty");
|
||||
}
|
||||
if linkpath.ends_with("/") {
|
||||
return_errno_with_message!(Errno::EISDIR, "linkpath is dir");
|
||||
}
|
||||
let fs_path = FsPath::new(dirfd, linkpath.as_ref())?;
|
||||
current.fs().read().lookup_dir_and_base_name(&fs_path)?
|
||||
};
|
||||
|
||||
let new_dentry = dir_dentry.create(
|
||||
&link_name,
|
||||
InodeType::SymLink,
|
||||
InodeMode::from_bits_truncate(0o777),
|
||||
)?;
|
||||
new_dentry.vnode().inode().write_link(&target)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
pub fn sys_symlink(target_addr: Vaddr, linkpath_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
self::sys_symlinkat(target_addr, AT_FDCWD, linkpath_addr)
|
||||
}
|
||||
Loading…
Reference in New Issue