mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-10 05:46:48 +00:00
Refactor DentryMnt and fix some issues
Signed-off-by: Zhenchen Wang <m202372036@hust.edu.cn>
This commit is contained in:
parent
60fa4d104a
commit
8d18a12385
@ -22,22 +22,15 @@ pub fn init() -> Result<()> {
|
||||
|
||||
let dev = fs.lookup(&FsPath::try_from("/dev")?)?;
|
||||
// Create the "pts" directory and mount devpts on it.
|
||||
let devpts_dentry =
|
||||
dev.dentry()
|
||||
.create("pts", InodeType::Dir, InodeMode::from_bits_truncate(0o755))?;
|
||||
let devpts_mount_node =
|
||||
DentryMnt::new(dev.mount_node().clone(), devpts_dentry.clone()).mount(DevPts::new())?;
|
||||
let devpts = DentryMnt::new(
|
||||
devpts_mount_node.clone(),
|
||||
devpts_mount_node.root_dentry().clone(),
|
||||
);
|
||||
|
||||
devpts.mount(DevPts::new())?;
|
||||
let devpts_dentrymnt =
|
||||
dev.new_fs_child("pts", InodeType::Dir, InodeMode::from_bits_truncate(0o755))?;
|
||||
let devpts_mount_node = devpts_dentrymnt.mount(DevPts::new())?;
|
||||
let devpts = DentryMnt::new_fs_root(devpts_mount_node.clone());
|
||||
|
||||
DEV_PTS.call_once(|| devpts);
|
||||
|
||||
// Create the "ptmx" symlink.
|
||||
let ptmx = dev.dentry().create(
|
||||
let ptmx = dev.new_fs_child(
|
||||
"ptmx",
|
||||
InodeType::SymLink,
|
||||
InodeMode::from_bits_truncate(0o777),
|
||||
|
@ -1,10 +1,10 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::inode_handle::FileIo;
|
||||
use super::{inode_handle::FileIo, utils::DentryMnt};
|
||||
use crate::{
|
||||
fs::{
|
||||
fs_resolver::{FsPath, FsResolver},
|
||||
utils::{Dentry, InodeMode, InodeType},
|
||||
utils::{InodeMode, InodeType},
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
@ -84,15 +84,14 @@ impl From<DeviceId> for u64 {
|
||||
///
|
||||
/// If the parent path is not existing, `mkdir -p` the parent path.
|
||||
/// This function is used in registering device.
|
||||
pub fn add_node(device: Arc<dyn Device>, pathname: &str) -> Result<Arc<Dentry>> {
|
||||
pub fn add_node(device: Arc<dyn Device>, path: &str) -> Result<Arc<DentryMnt>> {
|
||||
let mut dentrymnt = {
|
||||
let fs_resolver = FsResolver::new();
|
||||
fs_resolver.lookup(&FsPath::try_from("/dev").unwrap())?
|
||||
};
|
||||
let mut dentry = dentrymnt.dentry().clone();
|
||||
|
||||
let mut relative_path = {
|
||||
let relative_path = pathname.trim_start_matches('/');
|
||||
let relative_path = path.trim_start_matches('/');
|
||||
if relative_path.is_empty() {
|
||||
return_errno_with_message!(Errno::EINVAL, "invalid device path");
|
||||
}
|
||||
@ -117,14 +116,14 @@ pub fn add_node(device: Arc<dyn Device>, pathname: &str) -> Result<Arc<Dentry>>
|
||||
Err(_) => {
|
||||
if path_remain.is_empty() {
|
||||
// Create the device node
|
||||
dentry = dentrymnt.dentry().mknod(
|
||||
dentrymnt = dentrymnt.mknod(
|
||||
next_name,
|
||||
InodeMode::from_bits_truncate(0o666),
|
||||
device.clone(),
|
||||
)?;
|
||||
} else {
|
||||
// Mkdir parent path
|
||||
dentry = dentrymnt.dentry().create(
|
||||
dentrymnt = dentrymnt.new_fs_child(
|
||||
next_name,
|
||||
InodeType::Dir,
|
||||
InodeMode::from_bits_truncate(0o755),
|
||||
@ -135,15 +134,15 @@ pub fn add_node(device: Arc<dyn Device>, pathname: &str) -> Result<Arc<Dentry>>
|
||||
relative_path = path_remain;
|
||||
}
|
||||
|
||||
Ok(dentry)
|
||||
Ok(dentrymnt)
|
||||
}
|
||||
|
||||
/// Delete the device node from FS for the device.
|
||||
///
|
||||
/// This function is used in unregistering device.
|
||||
pub fn delete_node(pathname: &str) -> Result<()> {
|
||||
pub fn delete_node(path: &str) -> Result<()> {
|
||||
let abs_path = {
|
||||
let device_path = pathname.trim_start_matches('/');
|
||||
let device_path = path.trim_start_matches('/');
|
||||
if device_path.is_empty() {
|
||||
return_errno_with_message!(Errno::EINVAL, "invalid device path");
|
||||
}
|
||||
@ -155,6 +154,6 @@ pub fn delete_node(pathname: &str) -> Result<()> {
|
||||
fs_resolver.lookup_dir_and_base_name(&FsPath::try_from(abs_path.as_str()).unwrap())?
|
||||
};
|
||||
|
||||
parent_dentrymnt.dentry().unlink(&name)?;
|
||||
parent_dentrymnt.unlink(&name)?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ impl Default for FsResolver {
|
||||
impl FsResolver {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
root: DentryMnt::new(root_mount().clone(), root_mount().root_dentry().clone()),
|
||||
cwd: DentryMnt::new(root_mount().clone(), root_mount().root_dentry().clone()),
|
||||
root: DentryMnt::new_fs_root(root_mount().clone()),
|
||||
cwd: DentryMnt::new_fs_root(root_mount().clone()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ impl FsResolver {
|
||||
}
|
||||
|
||||
/// Open or create a file inode handler.
|
||||
pub fn open(&self, pathname: &FsPath, flags: u32, mode: u16) -> Result<InodeHandle> {
|
||||
pub fn open(&self, path: &FsPath, flags: u32, mode: u16) -> Result<InodeHandle> {
|
||||
let creation_flags = CreationFlags::from_bits_truncate(flags);
|
||||
let status_flags = StatusFlags::from_bits_truncate(flags);
|
||||
let access_mode = AccessMode::from_u32(flags)?;
|
||||
@ -72,9 +72,9 @@ impl FsResolver {
|
||||
let follow_tail_link = !(creation_flags.contains(CreationFlags::O_NOFOLLOW)
|
||||
|| creation_flags.contains(CreationFlags::O_CREAT)
|
||||
&& creation_flags.contains(CreationFlags::O_EXCL));
|
||||
let dentrymnt = match self.lookup_inner(pathname, follow_tail_link) {
|
||||
let dentrymnt = match self.lookup_inner(path, follow_tail_link) {
|
||||
Ok(dentrymnt) => {
|
||||
let inode = dentrymnt.dentry().inode();
|
||||
let inode = dentrymnt.inode();
|
||||
if inode.type_() == InodeType::SymLink
|
||||
&& creation_flags.contains(CreationFlags::O_NOFOLLOW)
|
||||
&& !status_flags.contains(StatusFlags::O_PATH)
|
||||
@ -104,18 +104,14 @@ impl FsResolver {
|
||||
return_errno_with_message!(Errno::ENOTDIR, "cannot create directory");
|
||||
}
|
||||
let (dir_dentrymnt, file_name) =
|
||||
self.lookup_dir_and_base_name_inner(pathname, follow_tail_link)?;
|
||||
self.lookup_dir_and_base_name_inner(path, follow_tail_link)?;
|
||||
if file_name.ends_with('/') {
|
||||
return_errno_with_message!(Errno::EISDIR, "path refers to a directory");
|
||||
}
|
||||
if !dir_dentrymnt.dentry().mode()?.is_writable() {
|
||||
if !dir_dentrymnt.mode()?.is_writable() {
|
||||
return_errno_with_message!(Errno::EACCES, "file cannot be created");
|
||||
}
|
||||
let dir_dentry =
|
||||
dir_dentrymnt
|
||||
.dentry()
|
||||
.create(&file_name, InodeType::File, inode_mode)?;
|
||||
DentryMnt::new(dir_dentrymnt.mount_node().clone(), dir_dentry.clone())
|
||||
dir_dentrymnt.new_fs_child(&file_name, InodeType::File, inode_mode)?
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
@ -125,29 +121,27 @@ impl FsResolver {
|
||||
}
|
||||
|
||||
/// Lookup dentrymnt according to FsPath, always follow symlinks
|
||||
pub fn lookup(&self, pathname: &FsPath) -> Result<Arc<DentryMnt>> {
|
||||
self.lookup_inner(pathname, true)
|
||||
pub fn lookup(&self, path: &FsPath) -> Result<Arc<DentryMnt>> {
|
||||
self.lookup_inner(path, true)
|
||||
}
|
||||
|
||||
/// Lookup dentrymnt according to FsPath, do not follow it if last component is a symlink
|
||||
pub fn lookup_no_follow(&self, pathname: &FsPath) -> Result<Arc<DentryMnt>> {
|
||||
self.lookup_inner(pathname, false)
|
||||
pub fn lookup_no_follow(&self, path: &FsPath) -> Result<Arc<DentryMnt>> {
|
||||
self.lookup_inner(path, false)
|
||||
}
|
||||
|
||||
fn lookup_inner(&self, pathname: &FsPath, follow_tail_link: bool) -> Result<Arc<DentryMnt>> {
|
||||
let dentrymnt = match pathname.inner {
|
||||
FsPathInner::Absolute(pathname) => self.lookup_from_parent(
|
||||
&self.root,
|
||||
pathname.trim_start_matches('/'),
|
||||
follow_tail_link,
|
||||
)?,
|
||||
FsPathInner::CwdRelative(pathname) => {
|
||||
self.lookup_from_parent(&self.cwd, pathname, follow_tail_link)?
|
||||
fn lookup_inner(&self, path: &FsPath, follow_tail_link: bool) -> Result<Arc<DentryMnt>> {
|
||||
let dentrymnt = match path.inner {
|
||||
FsPathInner::Absolute(path) => {
|
||||
self.lookup_from_parent(&self.root, path.trim_start_matches('/'), follow_tail_link)?
|
||||
}
|
||||
FsPathInner::CwdRelative(path) => {
|
||||
self.lookup_from_parent(&self.cwd, path, follow_tail_link)?
|
||||
}
|
||||
FsPathInner::Cwd => self.cwd.clone(),
|
||||
FsPathInner::FdRelative(fd, pathname) => {
|
||||
FsPathInner::FdRelative(fd, path) => {
|
||||
let parent = self.lookup_from_fd(fd)?;
|
||||
self.lookup_from_parent(&parent, pathname, follow_tail_link)?
|
||||
self.lookup_from_parent(&parent, path, follow_tail_link)?
|
||||
}
|
||||
FsPathInner::Fd(fd) => self.lookup_from_fd(fd)?,
|
||||
};
|
||||
@ -196,8 +190,7 @@ impl FsResolver {
|
||||
|
||||
// Iterate next dentry
|
||||
let next_dentrymnt = dentrymnt.lookup(next_name)?;
|
||||
let next_dentry = next_dentrymnt.dentry();
|
||||
let next_type = next_dentry.type_();
|
||||
let next_type = next_dentrymnt.type_();
|
||||
let next_is_tail = path_remain.is_empty();
|
||||
|
||||
// If next inode is a symlink, follow symlinks at most `SYMLINKS_MAX` times.
|
||||
@ -206,7 +199,7 @@ impl FsResolver {
|
||||
return_errno_with_message!(Errno::ELOOP, "too many symlinks");
|
||||
}
|
||||
let link_path_remain = {
|
||||
let mut tmp_link_path = next_dentry.inode().read_link()?;
|
||||
let mut tmp_link_path = next_dentrymnt.inode().read_link()?;
|
||||
if tmp_link_path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "empty symlink");
|
||||
}
|
||||
@ -241,7 +234,7 @@ impl FsResolver {
|
||||
}
|
||||
|
||||
/// Lookup dentry from the giving fd
|
||||
pub fn lookup_from_fd(&self, fd: FileDesc) -> Result<Arc<Dentry>> {
|
||||
pub fn lookup_from_fd(&self, fd: FileDesc) -> Result<Arc<DentryMnt>> {
|
||||
let current = current!();
|
||||
let file_table = current.file_table().lock();
|
||||
let inode_handle = file_table
|
||||
@ -251,35 +244,35 @@ impl FsResolver {
|
||||
Ok(inode_handle.dentrymnt().clone())
|
||||
}
|
||||
|
||||
/// Lookup the dir dentrymnt and base file name of the giving pathname.
|
||||
/// Lookup the dir dentrymnt and base file name of the giving path.
|
||||
///
|
||||
/// If the last component is a symlink, do not deference it
|
||||
pub fn lookup_dir_and_base_name(&self, pathname: &FsPath) -> Result<(Arc<DentryMnt>, String)> {
|
||||
self.lookup_dir_and_base_name_inner(pathname, false)
|
||||
pub fn lookup_dir_and_base_name(&self, path: &FsPath) -> Result<(Arc<DentryMnt>, String)> {
|
||||
self.lookup_dir_and_base_name_inner(path, false)
|
||||
}
|
||||
|
||||
fn lookup_dir_and_base_name_inner(
|
||||
&self,
|
||||
pathname: &FsPath,
|
||||
path: &FsPath,
|
||||
follow_tail_link: bool,
|
||||
) -> Result<(Arc<DentryMnt>, String)> {
|
||||
let (mut dir_dentrymnt, mut base_name) = match pathname.inner {
|
||||
FsPathInner::Absolute(pathname) => {
|
||||
let (dir, file_name) = split_path(pathname);
|
||||
let (mut dir_dentrymnt, mut base_name) = match path.inner {
|
||||
FsPathInner::Absolute(path) => {
|
||||
let (dir, file_name) = split_path(path);
|
||||
(
|
||||
self.lookup_from_parent(&self.root, dir.trim_start_matches('/'), true)?,
|
||||
String::from(file_name),
|
||||
)
|
||||
}
|
||||
FsPathInner::CwdRelative(pathname) => {
|
||||
let (dir, file_name) = split_path(pathname);
|
||||
FsPathInner::CwdRelative(path) => {
|
||||
let (dir, file_name) = split_path(path);
|
||||
(
|
||||
self.lookup_from_parent(&self.cwd, dir, true)?,
|
||||
String::from(file_name),
|
||||
)
|
||||
}
|
||||
FsPathInner::FdRelative(fd, pathname) => {
|
||||
let (dir, file_name) = split_path(pathname);
|
||||
FsPathInner::FdRelative(fd, path) => {
|
||||
let (dir, file_name) = split_path(path);
|
||||
let parent = self.lookup_from_fd(fd)?;
|
||||
(
|
||||
self.lookup_from_parent(&parent, dir, true)?,
|
||||
@ -295,9 +288,9 @@ impl FsResolver {
|
||||
// Dereference the tail symlinks if needed
|
||||
loop {
|
||||
match dir_dentrymnt.lookup(base_name.trim_end_matches('/')) {
|
||||
Ok(dentrymnt) if dentrymnt.dentry().type_() == InodeType::SymLink => {
|
||||
Ok(dentrymnt) if dentrymnt.type_() == InodeType::SymLink => {
|
||||
let link = {
|
||||
let mut link = dentrymnt.dentry().inode().read_link()?;
|
||||
let mut link = dentrymnt.inode().read_link()?;
|
||||
if link.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "invalid symlink");
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ impl InodeHandle<Rights> {
|
||||
access_mode: AccessMode,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<Self> {
|
||||
let inode = dentrymnt.dentry().inode();
|
||||
let inode = dentrymnt.inode();
|
||||
if access_mode.is_readable() && !inode.mode()?.is_readable() {
|
||||
return_errno_with_message!(Errno::EACCES, "File is not readable");
|
||||
}
|
||||
@ -116,6 +116,6 @@ impl FileLike for InodeHandle<Rights> {
|
||||
}
|
||||
|
||||
fn as_device(&self) -> Option<Arc<dyn Device>> {
|
||||
self.0.dentrymnt.dentry().inode().as_device()
|
||||
self.0.dentrymnt.inode().as_device()
|
||||
}
|
||||
}
|
||||
|
@ -47,12 +47,9 @@ impl InodeHandle_ {
|
||||
}
|
||||
|
||||
let len = if self.status_flags().contains(StatusFlags::O_DIRECT) {
|
||||
self.dentrymnt
|
||||
.dentry()
|
||||
.inode()
|
||||
.read_direct_at(*offset, buf)?
|
||||
self.dentrymnt.inode().read_direct_at(*offset, buf)?
|
||||
} else {
|
||||
self.dentrymnt.dentry().inode().read_at(*offset, buf)?
|
||||
self.dentrymnt.inode().read_at(*offset, buf)?
|
||||
};
|
||||
|
||||
*offset += len;
|
||||
@ -67,15 +64,12 @@ impl InodeHandle_ {
|
||||
}
|
||||
|
||||
if self.status_flags().contains(StatusFlags::O_APPEND) {
|
||||
*offset = self.dentrymnt.dentry().size();
|
||||
*offset = self.dentrymnt.size();
|
||||
}
|
||||
let len = if self.status_flags().contains(StatusFlags::O_DIRECT) {
|
||||
self.dentrymnt
|
||||
.dentry()
|
||||
.inode()
|
||||
.write_direct_at(*offset, buf)?
|
||||
self.dentrymnt.inode().write_direct_at(*offset, buf)?
|
||||
} else {
|
||||
self.dentrymnt.dentry().inode().write_at(*offset, buf)?
|
||||
self.dentrymnt.inode().write_at(*offset, buf)?
|
||||
};
|
||||
|
||||
*offset += len;
|
||||
@ -88,9 +82,9 @@ impl InodeHandle_ {
|
||||
}
|
||||
|
||||
let len = if self.status_flags().contains(StatusFlags::O_DIRECT) {
|
||||
self.dentrymnt.dentry().inode().read_direct_all(buf)?
|
||||
self.dentrymnt.inode().read_direct_all(buf)?
|
||||
} else {
|
||||
self.dentrymnt.dentry().inode().read_all(buf)?
|
||||
self.dentrymnt.inode().read_all(buf)?
|
||||
};
|
||||
Ok(len)
|
||||
}
|
||||
@ -105,7 +99,7 @@ impl InodeHandle_ {
|
||||
off as isize
|
||||
}
|
||||
SeekFrom::End(off /* as isize */) => {
|
||||
let file_size = self.dentrymnt.dentry().size() as isize;
|
||||
let file_size = self.dentrymnt.size() as isize;
|
||||
assert!(file_size >= 0);
|
||||
file_size
|
||||
.checked_add(off)
|
||||
@ -133,7 +127,7 @@ impl InodeHandle_ {
|
||||
if self.status_flags().contains(StatusFlags::O_APPEND) {
|
||||
return_errno_with_message!(Errno::EPERM, "can not resize append-only file");
|
||||
}
|
||||
self.dentrymnt.dentry().resize(new_size)
|
||||
self.dentrymnt.resize(new_size)
|
||||
}
|
||||
|
||||
pub fn access_mode(&self) -> AccessMode {
|
||||
@ -152,11 +146,7 @@ impl InodeHandle_ {
|
||||
|
||||
pub fn readdir(&self, visitor: &mut dyn DirentVisitor) -> Result<usize> {
|
||||
let mut offset = self.offset.lock();
|
||||
let read_cnt = self
|
||||
.dentrymnt
|
||||
.dentry()
|
||||
.inode()
|
||||
.readdir_at(*offset, visitor)?;
|
||||
let read_cnt = self.dentrymnt.inode().readdir_at(*offset, visitor)?;
|
||||
*offset += read_cnt;
|
||||
Ok(read_cnt)
|
||||
}
|
||||
@ -166,7 +156,7 @@ impl InodeHandle_ {
|
||||
return file_io.poll(mask, poller);
|
||||
}
|
||||
|
||||
self.dentrymnt.dentry().inode().poll(mask, poller)
|
||||
self.dentrymnt.inode().poll(mask, poller)
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
@ -174,11 +164,11 @@ impl InodeHandle_ {
|
||||
return file_io.ioctl(cmd, arg);
|
||||
}
|
||||
|
||||
self.dentrymnt.dentry().inode().ioctl(cmd, arg)
|
||||
self.dentrymnt.inode().ioctl(cmd, arg)
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.dentrymnt.dentry()")]
|
||||
#[inherit_methods(from = "self.dentrymnt")]
|
||||
impl InodeHandle_ {
|
||||
pub fn size(&self) -> usize;
|
||||
pub fn metadata(&self) -> Metadata;
|
||||
|
@ -76,12 +76,12 @@ impl FileSymOps {
|
||||
|
||||
impl SymOps for FileSymOps {
|
||||
fn read_link(&self) -> Result<String> {
|
||||
let pathname = if let Some(inode_handle) = self.0.downcast_ref::<InodeHandle>() {
|
||||
let path = if let Some(inode_handle) = self.0.downcast_ref::<InodeHandle>() {
|
||||
inode_handle.dentrymnt().abs_path()
|
||||
} else {
|
||||
// TODO: get the real path for other FileLike object
|
||||
String::from("/dev/tty")
|
||||
};
|
||||
Ok(pathname)
|
||||
Ok(path)
|
||||
}
|
||||
}
|
||||
|
@ -54,20 +54,20 @@ pub fn init(initramfs_buf: &[u8]) -> Result<()> {
|
||||
let mode = InodeMode::from_bits_truncate(metadata.permission_mode());
|
||||
match metadata.file_type() {
|
||||
FileType::File => {
|
||||
let dentry = parent.dentry().create(name, InodeType::File, mode)?;
|
||||
entry.read_all(dentry.inode().writer(0))?;
|
||||
let dentrymnt = parent.new_fs_child(name, InodeType::File, mode)?;
|
||||
entry.read_all(dentrymnt.inode().writer(0))?;
|
||||
}
|
||||
FileType::Dir => {
|
||||
let _ = parent.dentry().create(name, InodeType::Dir, mode)?;
|
||||
let _ = parent.new_fs_child(name, InodeType::Dir, mode)?;
|
||||
}
|
||||
FileType::Link => {
|
||||
let dentry = parent.dentry().create(name, InodeType::SymLink, mode)?;
|
||||
let dentrymnt = parent.new_fs_child(name, InodeType::SymLink, mode)?;
|
||||
let link_content = {
|
||||
let mut link_data: Vec<u8> = Vec::new();
|
||||
entry.read_all(&mut link_data)?;
|
||||
core::str::from_utf8(&link_data)?.to_string()
|
||||
};
|
||||
dentry.inode().write_link(&link_content)?;
|
||||
dentrymnt.inode().write_link(&link_content)?;
|
||||
}
|
||||
type_ => {
|
||||
panic!("unsupported file type = {:?} in initramfs", type_);
|
||||
|
@ -9,7 +9,10 @@ use inherit_methods_macro::inherit_methods;
|
||||
|
||||
use super::{FileSystem, Inode, InodeMode, InodeType, Metadata};
|
||||
use crate::{
|
||||
fs::device::Device,
|
||||
fs::{
|
||||
device::Device,
|
||||
utils::{MountNode, NAME_MAX},
|
||||
},
|
||||
prelude::*,
|
||||
process::{Gid, Uid},
|
||||
};
|
||||
@ -28,24 +31,16 @@ pub struct Dentry {
|
||||
}
|
||||
|
||||
impl Dentry {
|
||||
/// Create a new root dentry with the giving inode and mount node.
|
||||
/// Create a new root dentry with the giving inode.
|
||||
///
|
||||
/// It is been created during the construction of MountNode struct. The MountNode
|
||||
/// struct holds an arc reference to this root dentry, while this dentry holds a
|
||||
/// weak reference to the MountNode struct.
|
||||
/// struct holds an arc reference to this root dentry.
|
||||
pub(super) fn new_root(inode: Arc<dyn Inode>) -> Arc<Self> {
|
||||
let root = Self::new(inode, DentryOptions::Root);
|
||||
DCACHE.lock().insert(root.key(), root.clone());
|
||||
root
|
||||
}
|
||||
|
||||
pub fn new_child(&self, inode: Arc<dyn Inode>, name: &str) -> Arc<Self> {
|
||||
Dentry::new(
|
||||
inode,
|
||||
DentryOptions::Leaf((String::from(name), self.this())),
|
||||
)
|
||||
}
|
||||
|
||||
/// Internal constructor.
|
||||
fn new(inode: Arc<dyn Inode>, options: DentryOptions) -> Arc<Self> {
|
||||
Arc::new_cyclic(|weak_self| Self {
|
||||
@ -63,7 +58,7 @@ impl Dentry {
|
||||
/// Get the name of dentry.
|
||||
///
|
||||
/// Returns "/" if it is a root dentry.
|
||||
pub fn name(&self) -> String {
|
||||
fn name(&self) -> String {
|
||||
match self.name_and_parent.read().as_ref() {
|
||||
Some(name_and_parent) => name_and_parent.0.clone(),
|
||||
None => String::from("/"),
|
||||
@ -73,7 +68,7 @@ impl Dentry {
|
||||
/// Get the parent.
|
||||
///
|
||||
/// Returns None if it is root dentry.
|
||||
pub fn parent(&self) -> Option<Arc<Self>> {
|
||||
fn parent(&self) -> Option<Arc<Self>> {
|
||||
self.name_and_parent
|
||||
.read()
|
||||
.as_ref()
|
||||
@ -91,7 +86,7 @@ impl Dentry {
|
||||
}
|
||||
|
||||
/// Get the DentryKey.
|
||||
pub fn key(&self) -> DentryKey {
|
||||
fn key(&self) -> DentryKey {
|
||||
DentryKey::new(self)
|
||||
}
|
||||
|
||||
@ -106,27 +101,27 @@ impl Dentry {
|
||||
DentryFlags::from_bits(flags).unwrap()
|
||||
}
|
||||
|
||||
pub fn is_mountpoint(&self) -> bool {
|
||||
fn is_mountpoint(&self) -> bool {
|
||||
self.flags().contains(DentryFlags::MOUNTED)
|
||||
}
|
||||
|
||||
pub fn set_mountpoint(&self) {
|
||||
fn set_mountpoint(&self) {
|
||||
self.flags
|
||||
.fetch_or(DentryFlags::MOUNTED.bits(), Ordering::Release);
|
||||
}
|
||||
|
||||
pub fn clear_mountpoint(&self) {
|
||||
fn clear_mountpoint(&self) {
|
||||
self.flags
|
||||
.fetch_and(!(DentryFlags::MOUNTED.bits()), Ordering::Release);
|
||||
}
|
||||
|
||||
/// Currently, the root dentry of a fs is the root of a mount.
|
||||
pub fn is_root_of_mount(&self) -> bool {
|
||||
fn is_root_of_mount(&self) -> bool {
|
||||
self.name_and_parent.read().as_ref().is_none()
|
||||
}
|
||||
|
||||
/// Create a dentry by making inode.
|
||||
pub fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<Self>> {
|
||||
fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<Self>> {
|
||||
if self.inode.type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
@ -148,13 +143,13 @@ impl Dentry {
|
||||
}
|
||||
|
||||
/// Lookup a dentry from DCACHE.
|
||||
pub fn lookup_fast(&self, name: &str) -> Option<Arc<Dentry>> {
|
||||
fn lookup_via_cache(&self, name: &str) -> Option<Arc<Dentry>> {
|
||||
let mut children = self.children.lock();
|
||||
children.find_dentry(name)
|
||||
}
|
||||
|
||||
/// Lookup a dentry from filesystem.
|
||||
pub fn lookup_slow(&self, name: &str) -> Result<Arc<Dentry>> {
|
||||
fn lookuop_via_fs(&self, name: &str) -> Result<Arc<Dentry>> {
|
||||
let mut children = self.children.lock();
|
||||
let inode = self.inode.lookup(name)?;
|
||||
let dentry = Self::new(
|
||||
@ -165,13 +160,13 @@ impl Dentry {
|
||||
Ok(dentry)
|
||||
}
|
||||
|
||||
pub fn insert_dentry(&self, child_dentry: &Arc<Dentry>) {
|
||||
fn insert_dentry(&self, child_dentry: &Arc<Dentry>) {
|
||||
let mut children = self.children.lock();
|
||||
children.insert_dentry(child_dentry);
|
||||
}
|
||||
|
||||
/// Create a dentry by making a device inode.
|
||||
pub fn mknod(&self, name: &str, mode: InodeMode, device: Arc<dyn Device>) -> Result<Arc<Self>> {
|
||||
fn mknod(&self, name: &str, mode: InodeMode, device: Arc<dyn Device>) -> Result<Arc<Self>> {
|
||||
if self.inode.type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
@ -192,8 +187,27 @@ impl Dentry {
|
||||
Ok(child)
|
||||
}
|
||||
|
||||
/// Link a new name for the dentry by linking inode.
|
||||
fn link(&self, old: &Arc<Self>, name: &str) -> Result<()> {
|
||||
if self.inode.type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
let mut children = self.children.lock();
|
||||
if children.find_dentry(name).is_some() {
|
||||
return_errno!(Errno::EEXIST);
|
||||
}
|
||||
let old_inode = old.inode();
|
||||
self.inode.link(old_inode, name)?;
|
||||
let dentry = Self::new(
|
||||
old_inode.clone(),
|
||||
DentryOptions::Leaf((String::from(name), self.this())),
|
||||
);
|
||||
children.insert_dentry(&dentry);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Delete a dentry by unlinking inode.
|
||||
pub fn unlink(&self, name: &str) -> Result<()> {
|
||||
fn unlink(&self, name: &str) -> Result<()> {
|
||||
if self.inode.type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
@ -205,7 +219,7 @@ impl Dentry {
|
||||
}
|
||||
|
||||
/// Delete a directory dentry by rmdiring inode.
|
||||
pub fn rmdir(&self, name: &str) -> Result<()> {
|
||||
fn rmdir(&self, name: &str) -> Result<()> {
|
||||
if self.inode.type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
@ -217,7 +231,7 @@ impl Dentry {
|
||||
}
|
||||
|
||||
/// Rename a dentry to the new dentry by renaming inode.
|
||||
pub fn rename(&self, old_name: &str, new_dir: &Arc<Self>, new_name: &str) -> Result<()> {
|
||||
fn rename(&self, old_name: &str, new_dir: &Arc<Self>, new_name: &str) -> Result<()> {
|
||||
if old_name == "." || old_name == ".." || new_name == "." || new_name == ".." {
|
||||
return_errno_with_message!(Errno::EISDIR, "old_name or new_name is a directory");
|
||||
}
|
||||
@ -268,22 +282,22 @@ impl Dentry {
|
||||
|
||||
#[inherit_methods(from = "self.inode")]
|
||||
impl Dentry {
|
||||
pub fn fs(&self) -> Arc<dyn FileSystem>;
|
||||
pub fn sync(&self) -> Result<()>;
|
||||
pub fn metadata(&self) -> Metadata;
|
||||
pub fn type_(&self) -> InodeType;
|
||||
pub fn mode(&self) -> Result<InodeMode>;
|
||||
pub fn set_mode(&self, mode: InodeMode) -> Result<()>;
|
||||
pub fn size(&self) -> usize;
|
||||
pub fn resize(&self, size: usize) -> Result<()>;
|
||||
pub fn owner(&self) -> Result<Uid>;
|
||||
pub fn set_owner(&self, uid: Uid) -> Result<()>;
|
||||
pub fn group(&self) -> Result<Gid>;
|
||||
pub fn set_group(&self, gid: Gid) -> Result<()>;
|
||||
pub fn atime(&self) -> Duration;
|
||||
pub fn set_atime(&self, time: Duration);
|
||||
pub fn mtime(&self) -> Duration;
|
||||
pub fn set_mtime(&self, time: Duration);
|
||||
fn fs(&self) -> Arc<dyn FileSystem>;
|
||||
fn sync(&self) -> Result<()>;
|
||||
fn metadata(&self) -> Metadata;
|
||||
fn type_(&self) -> InodeType;
|
||||
fn mode(&self) -> Result<InodeMode>;
|
||||
fn set_mode(&self, mode: InodeMode) -> Result<()>;
|
||||
fn size(&self) -> usize;
|
||||
fn resize(&self, size: usize) -> Result<()>;
|
||||
fn owner(&self) -> Result<Uid>;
|
||||
fn set_owner(&self, uid: Uid) -> Result<()>;
|
||||
fn group(&self) -> Result<Gid>;
|
||||
fn set_group(&self, gid: Gid) -> Result<()>;
|
||||
fn atime(&self) -> Duration;
|
||||
fn set_atime(&self, time: Duration);
|
||||
fn mtime(&self) -> Duration;
|
||||
fn set_mtime(&self, time: Duration);
|
||||
}
|
||||
|
||||
impl Debug for Dentry {
|
||||
@ -307,7 +321,7 @@ pub struct DentryKey {
|
||||
|
||||
impl DentryKey {
|
||||
/// Form the DentryKey for the dentry.
|
||||
pub fn new(dentry: &Dentry) -> Self {
|
||||
fn new(dentry: &Dentry) -> Self {
|
||||
let (name, parent) = match dentry.name_and_parent.read().as_ref() {
|
||||
Some(name_and_parent) => name_and_parent.clone(),
|
||||
None => (String::from("/"), dentry.this()),
|
||||
@ -335,13 +349,13 @@ struct Children {
|
||||
}
|
||||
|
||||
impl Children {
|
||||
pub fn new() -> Self {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
inner: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_dentry(&mut self, dentry: &Arc<Dentry>) {
|
||||
fn insert_dentry(&mut self, dentry: &Arc<Dentry>) {
|
||||
// Do not cache it in DCACHE and children if is not cacheable.
|
||||
// When we look up it from the parent, it will always be newly created.
|
||||
if !dentry.inode().is_dentry_cacheable() {
|
||||
@ -352,14 +366,14 @@ impl Children {
|
||||
self.inner.insert(dentry.name(), Arc::downgrade(dentry));
|
||||
}
|
||||
|
||||
pub fn delete_dentry(&mut self, name: &str) -> Option<Arc<Dentry>> {
|
||||
fn delete_dentry(&mut self, name: &str) -> Option<Arc<Dentry>> {
|
||||
self.inner
|
||||
.remove(name)
|
||||
.and_then(|d| d.upgrade())
|
||||
.and_then(|d| DCACHE.lock().remove(&d.key()))
|
||||
}
|
||||
|
||||
pub fn find_dentry(&mut self, name: &str) -> Option<Arc<Dentry>> {
|
||||
fn find_dentry(&mut self, name: &str) -> Option<Arc<Dentry>> {
|
||||
if let Some(dentry) = self.inner.get(name) {
|
||||
dentry.upgrade().or_else(|| {
|
||||
self.inner.remove(name);
|
||||
@ -370,10 +384,7 @@ impl Children {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_dentry_with_checking_mountpoint(
|
||||
&mut self,
|
||||
name: &str,
|
||||
) -> Result<Option<Arc<Dentry>>> {
|
||||
fn find_dentry_with_checking_mountpoint(&mut self, name: &str) -> Result<Option<Arc<Dentry>>> {
|
||||
let dentry = self.find_dentry(name);
|
||||
if let Some(dentry) = dentry.as_ref() {
|
||||
if dentry.is_mountpoint() {
|
||||
@ -400,3 +411,256 @@ fn write_lock_children_on_two_dentries<'a>(
|
||||
(this, other)
|
||||
}
|
||||
}
|
||||
|
||||
/// The DentryMnt can represent a location in the mount tree.
|
||||
#[derive(Debug)]
|
||||
pub struct DentryMnt {
|
||||
mount_node: Arc<MountNode>,
|
||||
dentry: Arc<Dentry>,
|
||||
this: Weak<DentryMnt>,
|
||||
}
|
||||
|
||||
impl DentryMnt {
|
||||
/// Create a new DentryMnt to represent the root directory of a file system.
|
||||
pub fn new_fs_root(mount_node: Arc<MountNode>) -> Arc<Self> {
|
||||
Self::new(mount_node.clone(), mount_node.root_dentry().clone())
|
||||
}
|
||||
|
||||
/// Crete a new DentryMnt to represent the child directory of a file system.
|
||||
pub fn new_fs_child(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<Self>> {
|
||||
let new_child_dentry = self.dentry.create(name, type_, mode)?;
|
||||
Ok(Self::new(self.mount_node.clone(), new_child_dentry.clone()))
|
||||
}
|
||||
|
||||
/// Internal constructor.
|
||||
fn new(mount_node: Arc<MountNode>, dentry: Arc<Dentry>) -> Arc<Self> {
|
||||
Arc::new_cyclic(|weak_self| Self {
|
||||
mount_node,
|
||||
dentry,
|
||||
this: weak_self.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Lookup a dentrymnt.
|
||||
pub fn lookup(&self, name: &str) -> Result<Arc<Self>> {
|
||||
if self.dentry.inode().type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
if !self.dentry.inode().mode()?.is_executable() {
|
||||
return_errno!(Errno::EACCES);
|
||||
}
|
||||
if name.len() > NAME_MAX {
|
||||
return_errno!(Errno::ENAMETOOLONG);
|
||||
}
|
||||
|
||||
let dentrymnt = match name {
|
||||
"." => self.this(),
|
||||
".." => self.effective_parent().unwrap_or_else(|| self.this()),
|
||||
name => {
|
||||
let children_dentry = self.dentry.lookup_via_cache(name);
|
||||
match children_dentry {
|
||||
Some(dentry) => Self::new(self.mount_node().clone(), dentry.clone()),
|
||||
None => {
|
||||
let slow_dentry = self.dentry.lookuop_via_fs(name)?;
|
||||
Self::new(self.mount_node().clone(), slow_dentry.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let dentrymnt = dentrymnt.get_top_dentrymnt();
|
||||
Ok(dentrymnt)
|
||||
}
|
||||
|
||||
/// Get the absolute path.
|
||||
///
|
||||
/// It will resolve the mountpoint automatically.
|
||||
pub fn abs_path(&self) -> String {
|
||||
let mut path = self.effective_name();
|
||||
let mut dir_dentrymnt = self.this();
|
||||
|
||||
while let Some(parent_dir_dentrymnt) = dir_dentrymnt.effective_parent() {
|
||||
path = {
|
||||
let parent_name = parent_dir_dentrymnt.effective_name();
|
||||
if parent_name != "/" {
|
||||
parent_name + "/" + &path
|
||||
} else {
|
||||
parent_name + &path
|
||||
}
|
||||
};
|
||||
dir_dentrymnt = parent_dir_dentrymnt;
|
||||
}
|
||||
debug_assert!(path.starts_with('/'));
|
||||
path
|
||||
}
|
||||
|
||||
/// Get the effective name of dentrymnt.
|
||||
///
|
||||
/// If it is the root of mount, it will go up to the mountpoint to get the name
|
||||
/// of the mountpoint recursively.
|
||||
fn effective_name(&self) -> String {
|
||||
if !self.dentry.is_root_of_mount() {
|
||||
return self.dentry.name();
|
||||
}
|
||||
|
||||
let Some(parent) = self.mount_node.parent() else {
|
||||
return self.dentry.name();
|
||||
};
|
||||
let Some(mountpoint) = self.mount_node.mountpoint_dentry() else {
|
||||
return self.dentry.name();
|
||||
};
|
||||
|
||||
let parent_dentrymnt = Self::new(
|
||||
self.mount_node.parent().unwrap().upgrade().unwrap().clone(),
|
||||
self.mount_node.mountpoint_dentry().unwrap().clone(),
|
||||
);
|
||||
parent_dentrymnt.effective_name()
|
||||
}
|
||||
|
||||
/// Get the effective parent of dentrymnt.
|
||||
///
|
||||
/// If it is the root of mount, it will go up to the mountpoint to get the parent
|
||||
/// of the mountpoint recursively.
|
||||
fn effective_parent(&self) -> Option<Arc<Self>> {
|
||||
if !self.dentry.is_root_of_mount() {
|
||||
return Some(Self::new(
|
||||
self.mount_node.clone(),
|
||||
self.dentry.parent().unwrap().clone(),
|
||||
));
|
||||
}
|
||||
|
||||
let parent = self.mount_node.parent()?;
|
||||
let mountpoint = self.mount_node.mountpoint_dentry()?;
|
||||
|
||||
let parent_dentrymnt = Self::new(parent.upgrade().unwrap(), mountpoint.clone());
|
||||
parent_dentrymnt.effective_parent()
|
||||
}
|
||||
|
||||
/// Get the top DentryMnt of self.
|
||||
///
|
||||
/// When different file systems are mounted on the same mount point.
|
||||
/// For example, first `mount /dev/sda1 /mnt` and then `mount /dev/sda2 /mnt`.
|
||||
/// After the second mount is completed, the content of the first mount will be overridden.
|
||||
/// We need to recursively obtain the top DentryMnt.
|
||||
fn get_top_dentrymnt(&self) -> Arc<Self> {
|
||||
if !self.dentry.is_mountpoint() {
|
||||
return self.this();
|
||||
}
|
||||
match self.mount_node.get(self) {
|
||||
Some(child_mount) => Self::new(child_mount.clone(), child_mount.root_dentry().clone())
|
||||
.get_top_dentrymnt(),
|
||||
None => self.this(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Make this DentryMnt's dentry to be a mountpoint,
|
||||
/// and set the mountpoint of the child mount to this DentryMnt's dentry.
|
||||
fn set_mountpoint(&self, child_mount: Arc<MountNode>) {
|
||||
child_mount.set_mountpoint_dentry(self.dentry.clone());
|
||||
self.dentry.set_mountpoint();
|
||||
}
|
||||
|
||||
/// Mount the fs on this DentryMnt. It will make this DentryMnt's dentry to be a mountpoint.
|
||||
///
|
||||
/// If the given mountpoint has already been mounted, then its mounted child mount
|
||||
/// will be updated.
|
||||
/// The root dentry cannot be mounted.
|
||||
///
|
||||
/// Return the mounted child mount.
|
||||
pub fn mount(&self, fs: Arc<dyn FileSystem>) -> Result<Arc<MountNode>> {
|
||||
if self.dentry.inode().type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
if self.effective_parent().is_none() {
|
||||
return_errno_with_message!(Errno::EINVAL, "can not mount on root");
|
||||
}
|
||||
let child_mount = self.mount_node().mount(fs, &self.this())?;
|
||||
self.set_mountpoint(child_mount.clone());
|
||||
Ok(child_mount)
|
||||
}
|
||||
|
||||
/// Unmount and return the mounted child mount.
|
||||
///
|
||||
/// Note that the root mount cannot be unmounted.
|
||||
pub fn umount(&self) -> Result<Arc<MountNode>> {
|
||||
if !self.dentry.is_root_of_mount() {
|
||||
return_errno_with_message!(Errno::EINVAL, "not mounted");
|
||||
}
|
||||
|
||||
let mount_node = self.mount_node.clone();
|
||||
let Some(mountpoint_dentry) = mount_node.mountpoint_dentry() else {
|
||||
return_errno_with_message!(Errno::EINVAL, "cannot umount root mount");
|
||||
};
|
||||
|
||||
let mountpoint_mount_node = mount_node.parent().unwrap().upgrade().unwrap();
|
||||
let mountpoint_dentrymnt =
|
||||
Self::new(mountpoint_mount_node.clone(), mountpoint_dentry.clone());
|
||||
|
||||
let child_mount = mountpoint_mount_node.umount(&mountpoint_dentrymnt)?;
|
||||
mountpoint_dentry.clear_mountpoint();
|
||||
Ok(child_mount)
|
||||
}
|
||||
|
||||
/// Create a DentryMnt by making a device inode.
|
||||
pub fn mknod(&self, name: &str, mode: InodeMode, device: Arc<dyn Device>) -> Result<Arc<Self>> {
|
||||
let dentry = self.dentry.mknod(name, mode, device)?;
|
||||
Ok(Self::new(self.mount_node.clone(), dentry.clone()))
|
||||
}
|
||||
|
||||
/// Link a new name for the DentryMnt by linking inode.
|
||||
pub fn link(&self, old: &Arc<Self>, name: &str) -> Result<()> {
|
||||
if !Arc::ptr_eq(&old.mount_node, &self.mount_node) {
|
||||
return_errno_with_message!(Errno::EXDEV, "cannot cross mount");
|
||||
}
|
||||
self.dentry.link(&old.dentry, name)
|
||||
}
|
||||
|
||||
/// Delete a DentryMnt by unlinking inode.
|
||||
pub fn unlink(&self, name: &str) -> Result<()> {
|
||||
self.dentry.unlink(name)
|
||||
}
|
||||
|
||||
/// Delete a directory dentry by rmdiring inode.
|
||||
pub fn rmdir(&self, name: &str) -> Result<()> {
|
||||
self.dentry.rmdir(name)
|
||||
}
|
||||
|
||||
/// Rename a dentry to the new dentry by renaming inode.
|
||||
pub fn rename(&self, old_name: &str, new_dir: &Arc<Self>, new_name: &str) -> Result<()> {
|
||||
if !Arc::ptr_eq(&self.mount_node, &new_dir.mount_node) {
|
||||
return_errno_with_message!(Errno::EXDEV, "cannot cross mount");
|
||||
}
|
||||
self.dentry.rename(old_name, &new_dir.dentry, new_name)
|
||||
}
|
||||
|
||||
/// Get the arc reference to self.
|
||||
fn this(&self) -> Arc<Self> {
|
||||
self.this.upgrade().unwrap()
|
||||
}
|
||||
|
||||
/// Get the mount node of this dentrymnt.
|
||||
pub fn mount_node(&self) -> &Arc<MountNode> {
|
||||
&self.mount_node
|
||||
}
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.dentry")]
|
||||
impl DentryMnt {
|
||||
pub fn fs(&self) -> Arc<dyn FileSystem>;
|
||||
pub fn sync(&self) -> Result<()>;
|
||||
pub fn metadata(&self) -> Metadata;
|
||||
pub fn type_(&self) -> InodeType;
|
||||
pub fn mode(&self) -> Result<InodeMode>;
|
||||
pub fn set_mode(&self, mode: InodeMode) -> Result<()>;
|
||||
pub fn size(&self) -> usize;
|
||||
pub fn resize(&self, size: usize) -> Result<()>;
|
||||
pub fn owner(&self) -> Result<Uid>;
|
||||
pub fn set_owner(&self, uid: Uid) -> Result<()>;
|
||||
pub fn group(&self) -> Result<Gid>;
|
||||
pub fn set_group(&self, gid: Gid) -> Result<()>;
|
||||
pub fn atime(&self) -> Duration;
|
||||
pub fn set_atime(&self, time: Duration);
|
||||
pub fn mtime(&self) -> Duration;
|
||||
pub fn set_mtime(&self, time: Duration);
|
||||
pub fn key(&self) -> DentryKey;
|
||||
pub fn inode(&self) -> &Arc<dyn Inode>;
|
||||
}
|
||||
|
@ -1,210 +0,0 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::{Dentry, FileSystem, InodeType, MountNode, NAME_MAX};
|
||||
use crate::prelude::*;
|
||||
|
||||
/// The DentryMnt can represent a location in the mount tree.
|
||||
#[derive(Debug)]
|
||||
pub struct DentryMnt {
|
||||
mount_node: Arc<MountNode>,
|
||||
dentry: Arc<Dentry>,
|
||||
this: Weak<DentryMnt>,
|
||||
}
|
||||
|
||||
impl DentryMnt {
|
||||
pub fn new(mount_node: Arc<MountNode>, dentry: Arc<Dentry>) -> Arc<Self> {
|
||||
Arc::new_cyclic(|weak_self| Self {
|
||||
mount_node,
|
||||
dentry,
|
||||
this: weak_self.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Lookup a dentrymnt.
|
||||
pub fn lookup(&self, name: &str) -> Result<Arc<Self>> {
|
||||
if self.dentry.inode().type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
if !self.dentry.inode().mode()?.is_executable() {
|
||||
return_errno!(Errno::EACCES);
|
||||
}
|
||||
if name.len() > NAME_MAX {
|
||||
return_errno!(Errno::ENAMETOOLONG);
|
||||
}
|
||||
|
||||
let dentrymnt = match name {
|
||||
"." => self.this(),
|
||||
".." => self.effective_parent().unwrap_or(self.this()),
|
||||
name => {
|
||||
let children_dentry = self.dentry.lookup_fast(name);
|
||||
match children_dentry {
|
||||
Some(dentry) => Self::new(self.mount_node().clone(), dentry.clone()),
|
||||
None => {
|
||||
let slow_dentry = self.dentry.lookup_slow(name)?;
|
||||
Self::new(self.mount_node().clone(), slow_dentry.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let dentrymnt = dentrymnt.overlaid_dentrymnt();
|
||||
Ok(dentrymnt)
|
||||
}
|
||||
|
||||
// Get the absolute path.
|
||||
//
|
||||
// It will resolve the mountpoint automatically.
|
||||
pub fn abs_path(&self) -> String {
|
||||
let mut path = self.effective_name();
|
||||
let mut dir_dentrymnt = self.this();
|
||||
|
||||
loop {
|
||||
match dir_dentrymnt.effective_parent() {
|
||||
None => break,
|
||||
Some(parent_dir_dentrymnt) => {
|
||||
path = {
|
||||
let parent_name = parent_dir_dentrymnt.effective_name();
|
||||
if parent_name != "/" {
|
||||
parent_name + "/" + &path
|
||||
} else {
|
||||
parent_name + &path
|
||||
}
|
||||
};
|
||||
dir_dentrymnt = parent_dir_dentrymnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug_assert!(path.starts_with('/'));
|
||||
path
|
||||
}
|
||||
|
||||
/// Get the effective name of dentrymnt.
|
||||
///
|
||||
/// If it is the root of mount, it will go up to the mountpoint to get the name
|
||||
/// of the mountpoint recursively.
|
||||
fn effective_name(&self) -> String {
|
||||
if !self.dentry.is_root_of_mount() {
|
||||
return self.dentry.name();
|
||||
}
|
||||
|
||||
if self.mount_node.parent().is_some() & self.mount_node.mountpoint_dentry().is_some() {
|
||||
let parent_dentrymnt = Self::new(
|
||||
self.mount_node.parent().unwrap().upgrade().unwrap().clone(),
|
||||
self.mount_node.mountpoint_dentry().unwrap().clone(),
|
||||
);
|
||||
parent_dentrymnt.effective_name()
|
||||
} else {
|
||||
self.dentry.name()
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the effective parent of dentrymnt.
|
||||
///
|
||||
/// If it is the root of mount, it will go up to the mountpoint to get the parent
|
||||
/// of the mountpoint recursively.
|
||||
fn effective_parent(&self) -> Option<Arc<Self>> {
|
||||
if !self.dentry.is_root_of_mount() {
|
||||
return Some(Self::new(
|
||||
self.mount_node.clone(),
|
||||
self.dentry.parent().unwrap().clone(),
|
||||
));
|
||||
}
|
||||
if self.mount_node.parent().is_some() & self.mount_node.mountpoint_dentry().is_some() {
|
||||
let parent_dentrymnt = Self::new(
|
||||
self.mount_node.parent().unwrap().upgrade().unwrap().clone(),
|
||||
self.mount_node.mountpoint_dentry().unwrap().clone(),
|
||||
);
|
||||
parent_dentrymnt.effective_parent()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the overlaid dentrymnt of self.
|
||||
///
|
||||
/// It will jump into the child mount if it is a mountpoint.
|
||||
fn overlaid_dentrymnt(&self) -> Arc<Self> {
|
||||
if !self.dentry.is_mountpoint() {
|
||||
return self.this();
|
||||
}
|
||||
match self.mount_node.get(self) {
|
||||
Some(child_mount) => Self::new(child_mount.clone(), child_mount.root_dentry().clone())
|
||||
.overlaid_dentrymnt(),
|
||||
None => self.this(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Mount the fs on this dentrymnt. It will make this dentrymnt's dentry to be a mountpoint.
|
||||
///
|
||||
/// If the given mountpoint has already been mounted, then its mounted child mount
|
||||
/// will be updated.
|
||||
/// The root dentry cannot be mounted.
|
||||
///
|
||||
/// Return the mounted child mount.
|
||||
pub fn mount(&self, fs: Arc<dyn FileSystem>) -> Result<Arc<MountNode>> {
|
||||
if self.dentry.inode().type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
if self.effective_parent().is_none() {
|
||||
return_errno_with_message!(Errno::EINVAL, "can not mount on root");
|
||||
}
|
||||
let child_mount = self.mount_node().mount(fs, &self.this())?;
|
||||
self.dentry().set_mountpoint();
|
||||
Ok(child_mount)
|
||||
}
|
||||
|
||||
/// Unmount and return the mounted child mount.
|
||||
///
|
||||
/// Note that the root mount cannot be unmounted.
|
||||
pub fn umount(&self) -> Result<Arc<MountNode>> {
|
||||
if !self.dentry.is_root_of_mount() {
|
||||
return_errno_with_message!(Errno::EINVAL, "not mounted");
|
||||
}
|
||||
|
||||
let mount_node = self.mount_node.clone();
|
||||
let Some(mountpoint_dentry) = mount_node.mountpoint_dentry() else {
|
||||
return_errno_with_message!(Errno::EINVAL, "cannot umount root mount");
|
||||
};
|
||||
|
||||
let mountpoint_mount_node = mount_node.parent().unwrap().upgrade().unwrap();
|
||||
let mountpoint_dentrymnt =
|
||||
Self::new(mountpoint_mount_node.clone(), mountpoint_dentry.clone());
|
||||
|
||||
let child_mount = mountpoint_mount_node.umount(&mountpoint_dentrymnt)?;
|
||||
mountpoint_dentry.clear_mountpoint();
|
||||
Ok(child_mount)
|
||||
}
|
||||
|
||||
/// Link a new name for the dentrymnt's dentry by linking inode.
|
||||
pub fn link(&self, old: &Arc<Self>, name: &str) -> Result<()> {
|
||||
if self.dentry.inode().type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
let children = self.dentry.lookup_fast(name);
|
||||
if children.is_some() {
|
||||
return_errno!(Errno::EEXIST);
|
||||
}
|
||||
if !Arc::ptr_eq(old.mount_node(), self.mount_node()) {
|
||||
return_errno_with_message!(Errno::EXDEV, "cannot cross mount");
|
||||
}
|
||||
let old_inode = old.dentry.inode();
|
||||
self.dentry.inode().link(old_inode, name)?;
|
||||
let dentry = self.dentry.new_child(old_inode.clone(), name);
|
||||
self.dentry.insert_dentry(&dentry);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the arc reference to self.
|
||||
fn this(&self) -> Arc<Self> {
|
||||
self.this.upgrade().unwrap()
|
||||
}
|
||||
|
||||
/// Get the mount node of this dentrymnt.
|
||||
pub fn mount_node(&self) -> &Arc<MountNode> {
|
||||
&self.mount_node
|
||||
}
|
||||
|
||||
/// Get the dentry of this dentrymnt.
|
||||
pub fn dentry(&self) -> &Arc<Dentry> {
|
||||
&self.dentry
|
||||
}
|
||||
}
|
@ -5,8 +5,7 @@
|
||||
pub use access_mode::AccessMode;
|
||||
pub use channel::{Channel, Consumer, Producer};
|
||||
pub use creation_flags::CreationFlags;
|
||||
pub use dentry::{Dentry, DentryKey};
|
||||
pub use dentrymnt::DentryMnt;
|
||||
pub use dentry::{Dentry, DentryKey, DentryMnt};
|
||||
pub use dirent_visitor::DirentVisitor;
|
||||
pub use direntry_vec::DirEntryVecExt;
|
||||
pub use file_creation_mask::FileCreationMask;
|
||||
@ -22,7 +21,6 @@ mod access_mode;
|
||||
mod channel;
|
||||
mod creation_flags;
|
||||
mod dentry;
|
||||
mod dentrymnt;
|
||||
mod dirent_visitor;
|
||||
mod direntry_vec;
|
||||
mod file_creation_mask;
|
||||
|
@ -9,7 +9,7 @@ pub struct MountNode {
|
||||
root_dentry: Arc<Dentry>,
|
||||
/// Mountpoint dentry. A mount node can be mounted on one dentry of another mount node,
|
||||
/// which makes the mount being the child of the mount node.
|
||||
mountpoint_dentry: Option<Arc<Dentry>>,
|
||||
mountpoint_dentry: RwLock<Option<Arc<Dentry>>>,
|
||||
/// The associated FS.
|
||||
fs: Arc<dyn FileSystem>,
|
||||
/// The parent mount node.
|
||||
@ -29,20 +29,21 @@ impl MountNode {
|
||||
/// It is allowed to create a mount node even if the fs has been provided to another
|
||||
/// mount node. It is the fs's responsibility to ensure the data consistency.
|
||||
pub fn new_root(fs: Arc<dyn FileSystem>) -> Arc<Self> {
|
||||
Self::new(fs, None, None)
|
||||
Self::new(fs, None)
|
||||
}
|
||||
|
||||
/// The internal constructor.
|
||||
///
|
||||
/// Root mount node has no mountpoint which other mount nodes must have mountpoint.
|
||||
fn new(
|
||||
fs: Arc<dyn FileSystem>,
|
||||
mountpoint: Option<Arc<Dentry>>,
|
||||
parent_mount: Option<Weak<MountNode>>,
|
||||
) -> Arc<Self> {
|
||||
///
|
||||
/// Here, a MountNode is instantiated without an initial mountpoint,
|
||||
/// avoiding fixed mountpoint limitations. This allows the root mount node to
|
||||
/// exist without a mountpoint, ensuring uniformity and security, while all other
|
||||
/// mount nodes must be explicitly assigned a mountpoint to maintain structural integrity.
|
||||
fn new(fs: Arc<dyn FileSystem>, parent_mount: Option<Weak<MountNode>>) -> Arc<Self> {
|
||||
Arc::new_cyclic(|weak_self| Self {
|
||||
root_dentry: Dentry::new_root(fs.root_inode()),
|
||||
mountpoint_dentry: mountpoint,
|
||||
mountpoint_dentry: RwLock::new(None),
|
||||
parent: RwLock::new(parent_mount),
|
||||
children: Mutex::new(BTreeMap::new()),
|
||||
fs,
|
||||
@ -65,16 +66,12 @@ impl MountNode {
|
||||
if !Arc::ptr_eq(mountpoint.mount_node(), &self.this()) {
|
||||
return_errno_with_message!(Errno::EINVAL, "mountpoint not belongs to this");
|
||||
}
|
||||
if mountpoint.dentry().type_() != InodeType::Dir {
|
||||
if mountpoint.type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
|
||||
let key = mountpoint.dentry().key();
|
||||
let child_mount = Self::new(
|
||||
fs,
|
||||
Some(mountpoint.dentry().clone()),
|
||||
Some(Arc::downgrade(mountpoint.mount_node())),
|
||||
);
|
||||
let key = mountpoint.key();
|
||||
let child_mount = Self::new(fs, Some(Arc::downgrade(mountpoint.mount_node())));
|
||||
self.children.lock().insert(key, child_mount.clone());
|
||||
Ok(child_mount)
|
||||
}
|
||||
@ -90,7 +87,7 @@ impl MountNode {
|
||||
let child_mount = self
|
||||
.children
|
||||
.lock()
|
||||
.remove(&mountpoint.dentry().key())
|
||||
.remove(&mountpoint.key())
|
||||
.ok_or_else(|| Error::with_message(Errno::ENOENT, "can not find child mount"))?;
|
||||
Ok(child_mount)
|
||||
}
|
||||
@ -100,10 +97,7 @@ impl MountNode {
|
||||
if !Arc::ptr_eq(mountpoint.mount_node(), &self.this()) {
|
||||
return None;
|
||||
}
|
||||
self.children
|
||||
.lock()
|
||||
.get(&mountpoint.dentry().key())
|
||||
.cloned()
|
||||
self.children.lock().get(&mountpoint.key()).cloned()
|
||||
}
|
||||
|
||||
/// Get the root dentry of this mount node.
|
||||
@ -112,8 +106,17 @@ impl MountNode {
|
||||
}
|
||||
|
||||
/// Try to get the mountpoint dentry of this mount node.
|
||||
pub fn mountpoint_dentry(&self) -> Option<&Arc<Dentry>> {
|
||||
self.mountpoint_dentry.as_ref()
|
||||
pub fn mountpoint_dentry(&self) -> Option<Arc<Dentry>> {
|
||||
self.mountpoint_dentry.read().clone()
|
||||
}
|
||||
|
||||
/// Set the mountpoint.
|
||||
///
|
||||
/// In some cases we may need to reset the mountpoint of
|
||||
/// the created MountNode, such as move mount.
|
||||
pub fn set_mountpoint_dentry(&self, dentry: Arc<Dentry>) {
|
||||
let mut mountpoint_dentry = self.mountpoint_dentry.write();
|
||||
*mountpoint_dentry = Some(dentry);
|
||||
}
|
||||
|
||||
/// Flushes all pending filesystem metadata and cached file data to the device.
|
||||
@ -133,6 +136,10 @@ impl MountNode {
|
||||
self.parent.read().as_ref().cloned()
|
||||
}
|
||||
|
||||
/// Set the parent.
|
||||
///
|
||||
/// In some cases we may need to reset the parent of
|
||||
/// the created MountNode, such as move mount.
|
||||
pub fn set_parent(&self, mount_node: Arc<MountNode>) {
|
||||
let mut parent = self.parent.write();
|
||||
*parent = Some(Arc::downgrade(&mount_node));
|
||||
|
@ -18,9 +18,7 @@ impl PartialEq for UnixSocketAddrBound {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Abstract(l0), Self::Abstract(r0)) => l0 == r0,
|
||||
(Self::Path(l0), Self::Path(r0)) => {
|
||||
Arc::ptr_eq(l0.dentry().inode(), r0.dentry().inode())
|
||||
}
|
||||
(Self::Path(l0), Self::Path(r0)) => Arc::ptr_eq(l0.inode(), r0.inode()),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ impl Init {
|
||||
|
||||
let bound_addr = match addr_to_bind {
|
||||
UnixSocketAddr::Abstract(_) => todo!(),
|
||||
UnixSocketAddr::Path(pathname) => {
|
||||
let dentrymnt = create_socket_file(pathname)?;
|
||||
UnixSocketAddr::Path(path) => {
|
||||
let dentrymnt = create_socket_file(path)?;
|
||||
UnixSocketAddrBound::Path(dentrymnt)
|
||||
}
|
||||
};
|
||||
@ -87,19 +87,18 @@ impl Init {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_socket_file(pathname: &str) -> Result<Arc<DentryMnt>> {
|
||||
let (parent_pathname, file_name) = split_path(pathname);
|
||||
fn create_socket_file(path: &str) -> Result<Arc<DentryMnt>> {
|
||||
let (parent_pathname, file_name) = split_path(path);
|
||||
let parent = {
|
||||
let current = current!();
|
||||
let fs = current.fs().read();
|
||||
let parent_path = FsPath::try_from(parent_pathname)?;
|
||||
fs.lookup(&parent_path)?
|
||||
};
|
||||
let dentry = parent.dentry().create(
|
||||
let dentrymnt = parent.new_fs_child(
|
||||
file_name,
|
||||
InodeType::Socket,
|
||||
InodeMode::S_IRUSR | InodeMode::S_IWUSR,
|
||||
)?;
|
||||
let dentrymnt = DentryMnt::new(parent.mount_node().clone(), dentry.clone());
|
||||
Ok(dentrymnt)
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ impl Backlog {
|
||||
}
|
||||
|
||||
fn create_keyable_inode(dentrymnt: &Arc<DentryMnt>) -> KeyableWeak<dyn Inode> {
|
||||
let weak_inode = Arc::downgrade(dentrymnt.dentry().inode());
|
||||
let weak_inode = Arc::downgrade(dentrymnt.inode());
|
||||
KeyableWeak::from(weak_inode)
|
||||
}
|
||||
|
||||
|
@ -161,8 +161,8 @@ impl Socket for UnixStreamSocket {
|
||||
UnixSocketAddr::Abstract(abstract_name) => {
|
||||
UnixSocketAddrBound::Abstract(abstract_name)
|
||||
}
|
||||
UnixSocketAddr::Path(pathname) => {
|
||||
let dentrymnt = lookup_socket_file(&pathname)?;
|
||||
UnixSocketAddr::Path(path) => {
|
||||
let dentrymnt = lookup_socket_file(&path)?;
|
||||
UnixSocketAddrBound::Path(dentrymnt)
|
||||
}
|
||||
}
|
||||
@ -287,19 +287,19 @@ impl Drop for UnixStreamSocket {
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_socket_file(pathname: &str) -> Result<Arc<DentryMnt>> {
|
||||
fn lookup_socket_file(path: &str) -> Result<Arc<DentryMnt>> {
|
||||
let dentrymnt = {
|
||||
let current = current!();
|
||||
let fs = current.fs().read();
|
||||
let fs_path = FsPath::try_from(pathname)?;
|
||||
let fs_path = FsPath::try_from(path)?;
|
||||
fs.lookup(&fs_path)?
|
||||
};
|
||||
|
||||
if dentrymnt.dentry().type_() != InodeType::Socket {
|
||||
if dentrymnt.type_() != InodeType::Socket {
|
||||
return_errno_with_message!(Errno::ENOTSOCK, "not a socket file")
|
||||
}
|
||||
|
||||
if !dentrymnt.dentry().mode()?.is_readable() || !dentrymnt.dentry().mode()?.is_writable() {
|
||||
if !dentrymnt.mode()?.is_readable() || !dentrymnt.mode()?.is_writable() {
|
||||
return_errno_with_message!(Errno::EACCES, "the socket cannot be read or written")
|
||||
}
|
||||
Ok(dentrymnt)
|
||||
|
@ -12,7 +12,7 @@ use super::elf_file::Elf;
|
||||
use crate::{
|
||||
fs::{
|
||||
fs_resolver::{FsPath, FsResolver, AT_FDCWD},
|
||||
utils::{Dentry, DentryMnt},
|
||||
utils::DentryMnt,
|
||||
},
|
||||
prelude::*,
|
||||
process::{
|
||||
@ -93,7 +93,7 @@ fn lookup_and_parse_ldso(
|
||||
elf: &Elf,
|
||||
file_header: &[u8],
|
||||
fs_resolver: &FsResolver,
|
||||
) -> Result<(Arc<Dentry>, Elf)> {
|
||||
) -> Result<(Arc<DentryMnt>, Elf)> {
|
||||
let ldso_file = {
|
||||
let ldso_path = elf.ldso_path(file_header)?;
|
||||
let fs_path = FsPath::new(AT_FDCWD, &ldso_path)?;
|
||||
@ -101,14 +101,18 @@ fn lookup_and_parse_ldso(
|
||||
};
|
||||
let ldso_elf = {
|
||||
let mut buf = Box::new([0u8; PAGE_SIZE]);
|
||||
let inode = ldso_file.dentry().inode();
|
||||
let inode = ldso_file.inode();
|
||||
inode.read_at(0, &mut *buf)?;
|
||||
Elf::parse_elf(&*buf)?
|
||||
};
|
||||
Ok((ldso_file.dentry().clone(), ldso_elf))
|
||||
Ok((ldso_file.clone(), ldso_elf))
|
||||
}
|
||||
|
||||
fn load_ldso(root_vmar: &Vmar<Full>, ldso_file: &Dentry, ldso_elf: &Elf) -> Result<LdsoLoadInfo> {
|
||||
fn load_ldso(
|
||||
root_vmar: &Vmar<Full>,
|
||||
ldso_file: &DentryMnt,
|
||||
ldso_elf: &Elf,
|
||||
) -> Result<LdsoLoadInfo> {
|
||||
let map_addr = map_segment_vmos(ldso_elf, root_vmar, ldso_file)?;
|
||||
Ok(LdsoLoadInfo::new(
|
||||
ldso_elf.entry_point() + map_addr,
|
||||
@ -118,9 +122,9 @@ fn load_ldso(root_vmar: &Vmar<Full>, ldso_file: &Dentry, ldso_elf: &Elf) -> Resu
|
||||
|
||||
fn init_and_map_vmos(
|
||||
process_vm: &ProcessVm,
|
||||
ldso: Option<(Arc<Dentry>, Elf)>,
|
||||
ldso: Option<(Arc<DentryMnt>, Elf)>,
|
||||
parsed_elf: &Elf,
|
||||
elf_file: &Dentry,
|
||||
elf_file: &DentryMnt,
|
||||
) -> Result<(Vaddr, AuxVec)> {
|
||||
let root_vmar = process_vm.root_vmar();
|
||||
|
||||
@ -199,7 +203,7 @@ impl ElfLoadInfo {
|
||||
}
|
||||
|
||||
/// init vmo for each segment and then map segment to root vmar
|
||||
pub fn map_segment_vmos(elf: &Elf, root_vmar: &Vmar<Full>, elf_file: &Dentry) -> Result<Vaddr> {
|
||||
pub fn map_segment_vmos(elf: &Elf, root_vmar: &Vmar<Full>, elf_file: &DentryMnt) -> Result<Vaddr> {
|
||||
// all segments of the shared object must be mapped to a continuous vm range
|
||||
// to ensure the relative offset of each segment not changed.
|
||||
let base_addr = if elf.is_shared_object() {
|
||||
@ -288,7 +292,10 @@ fn map_segment_vmo(
|
||||
|
||||
/// Create VMO for each segment. Return the segment VMO and the size of
|
||||
/// additional anonymous mapping it needs.
|
||||
fn init_segment_vmo(program_header: &ProgramHeader64, elf_file: &Dentry) -> Result<(Vmo, usize)> {
|
||||
fn init_segment_vmo(
|
||||
program_header: &ProgramHeader64,
|
||||
elf_file: &DentryMnt,
|
||||
) -> Result<(Vmo, usize)> {
|
||||
trace!(
|
||||
"mem range = 0x{:x} - 0x{:x}, mem_size = 0x{:x}",
|
||||
program_header.virtual_addr,
|
||||
|
@ -11,7 +11,7 @@ use super::process_vm::ProcessVm;
|
||||
use crate::{
|
||||
fs::{
|
||||
fs_resolver::{FsPath, FsResolver, AT_FDCWD},
|
||||
utils::{Dentry, DentryMnt},
|
||||
utils::DentryMnt,
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
@ -32,7 +32,7 @@ pub fn load_program_to_vm(
|
||||
recursion_limit: usize,
|
||||
) -> Result<(String, ElfLoadInfo)> {
|
||||
let abs_path = elf_file.abs_path();
|
||||
let inode = elf_file.dentry().inode();
|
||||
let inode = elf_file.inode();
|
||||
let file_header = {
|
||||
// read the first page of file header
|
||||
let mut file_header_buffer = Box::new([0u8; PAGE_SIZE]);
|
||||
@ -49,7 +49,7 @@ pub fn load_program_to_vm(
|
||||
let fs_path = FsPath::new(AT_FDCWD, &filename)?;
|
||||
fs_resolver.lookup(&fs_path)?
|
||||
};
|
||||
check_executable_file(interpreter.dentry())?;
|
||||
check_executable_file(&interpreter)?;
|
||||
return load_program_to_vm(
|
||||
process_vm,
|
||||
interpreter,
|
||||
@ -68,16 +68,16 @@ pub fn load_program_to_vm(
|
||||
Ok((abs_path, elf_load_info))
|
||||
}
|
||||
|
||||
pub fn check_executable_file(dentry: &Arc<Dentry>) -> Result<()> {
|
||||
if dentry.type_().is_directory() {
|
||||
pub fn check_executable_file(dentrymnt: &Arc<DentryMnt>) -> Result<()> {
|
||||
if dentrymnt.type_().is_directory() {
|
||||
return_errno_with_message!(Errno::EISDIR, "the file is a directory");
|
||||
}
|
||||
|
||||
if !dentry.type_().is_reguler_file() {
|
||||
if !dentrymnt.type_().is_reguler_file() {
|
||||
return_errno_with_message!(Errno::EACCES, "the dentry is not a regular file");
|
||||
}
|
||||
|
||||
if !dentry.mode()?.is_executable() {
|
||||
if !dentrymnt.mode()?.is_executable() {
|
||||
return_errno_with_message!(Errno::EACCES, "the dentry is not executable");
|
||||
}
|
||||
|
||||
|
@ -9,22 +9,22 @@ use crate::{
|
||||
util::read_cstring_from_user,
|
||||
};
|
||||
|
||||
pub fn sys_chdir(pathname_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
pub fn sys_chdir(path_ptr: Vaddr) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_CHDIR);
|
||||
let pathname = read_cstring_from_user(pathname_addr, MAX_FILENAME_LEN)?;
|
||||
debug!("pathname = {:?}", pathname);
|
||||
let path = read_cstring_from_user(path_ptr, MAX_FILENAME_LEN)?;
|
||||
debug!("path = {:?}", path);
|
||||
|
||||
let current = current!();
|
||||
let mut fs = current.fs().write();
|
||||
let dentrymnt = {
|
||||
let pathname = pathname.to_string_lossy();
|
||||
if pathname.is_empty() {
|
||||
let path = path.to_string_lossy();
|
||||
if path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||
}
|
||||
let fs_path = FsPath::try_from(pathname.as_ref())?;
|
||||
let fs_path = FsPath::try_from(path.as_ref())?;
|
||||
fs.lookup(&fs_path)?
|
||||
};
|
||||
if dentrymnt.dentry().type_() != InodeType::Dir {
|
||||
if dentrymnt.type_() != InodeType::Dir {
|
||||
return_errno_with_message!(Errno::ENOTDIR, "must be directory");
|
||||
}
|
||||
fs.set_cwd(dentrymnt);
|
||||
@ -44,7 +44,7 @@ pub fn sys_fchdir(fd: FileDesc) -> Result<SyscallReturn> {
|
||||
.ok_or(Error::with_message(Errno::EBADF, "not inode"))?;
|
||||
inode_handle.dentrymnt().clone()
|
||||
};
|
||||
if dentrymnt.dentry().type_() != InodeType::Dir {
|
||||
if dentrymnt.type_() != InodeType::Dir {
|
||||
return_errno_with_message!(Errno::ENOTDIR, "must be directory");
|
||||
}
|
||||
current.fs().write().set_cwd(dentrymnt);
|
||||
|
@ -47,8 +47,6 @@ pub fn sys_fchmodat(
|
||||
let fs_path = FsPath::new(dirfd, path.as_ref())?;
|
||||
current.fs().read().lookup(&fs_path)?
|
||||
};
|
||||
dentrymnt
|
||||
.dentry()
|
||||
.set_mode(InodeMode::from_bits_truncate(mode))?;
|
||||
dentrymnt.set_mode(InodeMode::from_bits_truncate(mode))?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -90,10 +90,10 @@ pub fn sys_fchownat(
|
||||
}
|
||||
};
|
||||
if let Some(uid) = uid {
|
||||
dentrymnt.dentry().set_owner(uid)?;
|
||||
dentrymnt.set_owner(uid)?;
|
||||
}
|
||||
if let Some(gid) = gid {
|
||||
dentrymnt.dentry().set_group(gid)?;
|
||||
dentrymnt.set_group(gid)?;
|
||||
}
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -9,22 +9,22 @@ use crate::{
|
||||
util::read_cstring_from_user,
|
||||
};
|
||||
|
||||
pub fn sys_chroot(pathname_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
pub fn sys_chroot(path_ptr: Vaddr) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_CHROOT);
|
||||
let pathname = read_cstring_from_user(pathname_addr, MAX_FILENAME_LEN)?;
|
||||
debug!("pathname = {:?}", pathname);
|
||||
let path = read_cstring_from_user(path_ptr, MAX_FILENAME_LEN)?;
|
||||
debug!("path = {:?}", path);
|
||||
|
||||
let current = current!();
|
||||
let mut fs = current.fs().write();
|
||||
let dentrymnt = {
|
||||
let pathname = pathname.to_string_lossy();
|
||||
if pathname.is_empty() {
|
||||
let path = path.to_string_lossy();
|
||||
if path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||
}
|
||||
let fs_path = FsPath::try_from(pathname.as_ref())?;
|
||||
let fs_path = FsPath::try_from(path.as_ref())?;
|
||||
fs.lookup(&fs_path)?
|
||||
};
|
||||
if dentrymnt.dentry().type_() != InodeType::Dir {
|
||||
if dentrymnt.type_() != InodeType::Dir {
|
||||
return_errno_with_message!(Errno::ENOTDIR, "must be directory");
|
||||
}
|
||||
fs.set_root(dentrymnt);
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
fs::{
|
||||
file_table::FileDesc,
|
||||
fs_resolver::{FsPath, AT_FDCWD},
|
||||
utils::{Dentry, DentryMnt, InodeType},
|
||||
utils::{DentryMnt, InodeType},
|
||||
},
|
||||
log_syscall_entry,
|
||||
prelude::*,
|
||||
@ -70,7 +70,7 @@ fn lookup_executable_file(
|
||||
let fs_path = FsPath::new(dfd, &filename)?;
|
||||
if flags.contains(OpenFlags::AT_SYMLINK_NOFOLLOW) {
|
||||
let dentrymnt = fs_resolver.lookup_no_follow(&fs_path)?;
|
||||
if dentrymnt.dentry().type_() == InodeType::SymLink {
|
||||
if dentrymnt.type_() == InodeType::SymLink {
|
||||
return_errno_with_message!(Errno::ELOOP, "the executable file is a symlink");
|
||||
}
|
||||
Ok(dentrymnt)
|
||||
@ -78,7 +78,7 @@ fn lookup_executable_file(
|
||||
fs_resolver.lookup(&fs_path)
|
||||
}
|
||||
}?;
|
||||
check_executable_file(dentrymnt.dentry())?;
|
||||
check_executable_file(&dentrymnt)?;
|
||||
Ok(dentrymnt)
|
||||
}
|
||||
|
||||
@ -121,8 +121,8 @@ fn do_execve(
|
||||
debug!("load elf in execve succeeds");
|
||||
|
||||
let credentials = credentials_mut();
|
||||
set_uid_from_elf(&credentials, elf_file.dentry())?;
|
||||
set_gid_from_elf(&credentials, elf_file.dentry())?;
|
||||
set_uid_from_elf(&credentials, &elf_file)?;
|
||||
set_gid_from_elf(&credentials, &elf_file)?;
|
||||
|
||||
// set executable path
|
||||
current.set_executable_path(new_executable_path);
|
||||
@ -180,7 +180,7 @@ fn read_cstring_vec(
|
||||
}
|
||||
|
||||
/// Sets uid for credentials as the same of uid of elf file if elf file has `set_uid` bit.
|
||||
fn set_uid_from_elf(credentials: &Credentials<WriteOp>, elf_file: &Arc<Dentry>) -> Result<()> {
|
||||
fn set_uid_from_elf(credentials: &Credentials<WriteOp>, elf_file: &Arc<DentryMnt>) -> Result<()> {
|
||||
if elf_file.mode()?.has_set_uid() {
|
||||
let uid = elf_file.owner()?;
|
||||
credentials.set_euid(uid);
|
||||
@ -192,7 +192,7 @@ fn set_uid_from_elf(credentials: &Credentials<WriteOp>, elf_file: &Arc<Dentry>)
|
||||
}
|
||||
|
||||
/// Sets gid for credentials as the same of gid of elf file if elf file has `set_gid` bit.
|
||||
fn set_gid_from_elf(credentials: &Credentials<WriteOp>, elf_file: &Arc<Dentry>) -> Result<()> {
|
||||
fn set_gid_from_elf(credentials: &Credentials<WriteOp>, elf_file: &Arc<DentryMnt>) -> Result<()> {
|
||||
if elf_file.mode()?.has_set_gid() {
|
||||
let gid = elf_file.group()?;
|
||||
credentials.set_egid(gid);
|
||||
|
@ -11,15 +11,15 @@ pub fn sys_fsync(fd: FileDesc) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_FSYNC);
|
||||
debug!("fd = {}", fd);
|
||||
|
||||
let dentry = {
|
||||
let dentrymnt = {
|
||||
let current = current!();
|
||||
let file_table = current.file_table().lock();
|
||||
let file = file_table.get_file(fd)?;
|
||||
let inode_handle = file
|
||||
.downcast_ref::<InodeHandle>()
|
||||
.ok_or(Error::with_message(Errno::EINVAL, "not inode"))?;
|
||||
inode_handle.dentrymnt().dentry().clone()
|
||||
inode_handle.dentrymnt().clone()
|
||||
};
|
||||
dentry.sync()?;
|
||||
dentrymnt.sync()?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ pub fn sys_getdents64(fd: FileDesc, buf_addr: Vaddr, buf_len: usize) -> Result<S
|
||||
let inode_handle = file
|
||||
.downcast_ref::<InodeHandle>()
|
||||
.ok_or(Error::with_message(Errno::EBADF, "not inode"))?;
|
||||
if inode_handle.dentrymnt().dentry().type_() != InodeType::Dir {
|
||||
if inode_handle.dentrymnt().type_() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
let mut buffer = vec![0u8; buf_len];
|
||||
|
@ -14,37 +14,37 @@ use crate::{
|
||||
|
||||
pub fn sys_linkat(
|
||||
old_dirfd: FileDesc,
|
||||
old_pathname_addr: Vaddr,
|
||||
old_path_addr: Vaddr,
|
||||
new_dirfd: FileDesc,
|
||||
new_pathname_addr: Vaddr,
|
||||
new_path_addr: Vaddr,
|
||||
flags: u32,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_LINKAT);
|
||||
let old_pathname = read_cstring_from_user(old_pathname_addr, MAX_FILENAME_LEN)?;
|
||||
let new_pathname = read_cstring_from_user(new_pathname_addr, MAX_FILENAME_LEN)?;
|
||||
let old_path = read_cstring_from_user(old_path_addr, MAX_FILENAME_LEN)?;
|
||||
let new_path = read_cstring_from_user(new_path_addr, MAX_FILENAME_LEN)?;
|
||||
let flags =
|
||||
LinkFlags::from_bits(flags).ok_or(Error::with_message(Errno::EINVAL, "invalid flags"))?;
|
||||
debug!(
|
||||
"old_dirfd = {}, old_pathname = {:?}, new_dirfd = {}, new_pathname = {:?}, flags = {:?}",
|
||||
old_dirfd, old_pathname, new_dirfd, new_pathname, flags
|
||||
"old_dirfd = {}, old_path = {:?}, new_dirfd = {}, new_path = {:?}, flags = {:?}",
|
||||
old_dirfd, old_path, new_dirfd, new_path, flags
|
||||
);
|
||||
|
||||
let current = current!();
|
||||
let (old_dentrymnt, new_dir_dentrymnt, new_name) = {
|
||||
let old_pathname = old_pathname.to_string_lossy();
|
||||
if old_pathname.ends_with('/') {
|
||||
let old_path = old_path.to_string_lossy();
|
||||
if old_path.ends_with('/') {
|
||||
return_errno_with_message!(Errno::EPERM, "oldpath is dir");
|
||||
}
|
||||
if old_pathname.is_empty() && !flags.contains(LinkFlags::AT_EMPTY_PATH) {
|
||||
if old_path.is_empty() && !flags.contains(LinkFlags::AT_EMPTY_PATH) {
|
||||
return_errno_with_message!(Errno::ENOENT, "oldpath is empty");
|
||||
}
|
||||
let new_pathname = new_pathname.to_string_lossy();
|
||||
if new_pathname.ends_with('/') || new_pathname.is_empty() {
|
||||
let new_path = new_path.to_string_lossy();
|
||||
if new_path.ends_with('/') || new_path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "newpath is dir or is empty");
|
||||
}
|
||||
|
||||
let old_fs_path = FsPath::new(old_dirfd, old_pathname.as_ref())?;
|
||||
let new_fs_path = FsPath::new(new_dirfd, new_pathname.as_ref())?;
|
||||
let old_fs_path = FsPath::new(old_dirfd, old_path.as_ref())?;
|
||||
let new_fs_path = FsPath::new(new_dirfd, new_path.as_ref())?;
|
||||
let fs = current.fs().read();
|
||||
let old_dentrymnt = if flags.contains(LinkFlags::AT_SYMLINK_FOLLOW) {
|
||||
fs.lookup(&old_fs_path)?
|
||||
@ -54,12 +54,13 @@ pub fn sys_linkat(
|
||||
let (new_dir_dentrymnt, new_name) = fs.lookup_dir_and_base_name(&new_fs_path)?;
|
||||
(old_dentrymnt, new_dir_dentrymnt, new_name)
|
||||
};
|
||||
|
||||
new_dir_dentrymnt.link(&old_dentrymnt, &new_name)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
pub fn sys_link(old_pathname_addr: Vaddr, new_pathname_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
self::sys_linkat(AT_FDCWD, old_pathname_addr, AT_FDCWD, new_pathname_addr, 0)
|
||||
pub fn sys_link(old_path_addr: Vaddr, new_path_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
self::sys_linkat(AT_FDCWD, old_path_addr, AT_FDCWD, new_path_addr, 0)
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
|
@ -13,21 +13,18 @@ use crate::{
|
||||
util::read_cstring_from_user,
|
||||
};
|
||||
|
||||
pub fn sys_mkdirat(dirfd: FileDesc, pathname_addr: Vaddr, mode: u16) -> Result<SyscallReturn> {
|
||||
pub fn sys_mkdirat(dirfd: FileDesc, path_addr: Vaddr, mode: u16) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_MKDIRAT);
|
||||
let pathname = read_cstring_from_user(pathname_addr, MAX_FILENAME_LEN)?;
|
||||
debug!(
|
||||
"dirfd = {}, pathname = {:?}, mode = {}",
|
||||
dirfd, pathname, mode
|
||||
);
|
||||
let path = read_cstring_from_user(path_addr, MAX_FILENAME_LEN)?;
|
||||
debug!("dirfd = {}, path = {:?}, mode = {}", dirfd, path, mode);
|
||||
|
||||
let current = current!();
|
||||
let (dir_dentrymnt, name) = {
|
||||
let pathname = pathname.to_string_lossy();
|
||||
if pathname.is_empty() {
|
||||
let path = path.to_string_lossy();
|
||||
if path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||
}
|
||||
let fs_path = FsPath::new(dirfd, pathname.as_ref())?;
|
||||
let fs_path = FsPath::new(dirfd, path.as_ref())?;
|
||||
current.fs().read().lookup_dir_and_base_name(&fs_path)?
|
||||
};
|
||||
|
||||
@ -35,13 +32,10 @@ pub fn sys_mkdirat(dirfd: FileDesc, pathname_addr: Vaddr, mode: u16) -> Result<S
|
||||
let mask_mode = mode & !current.umask().read().get();
|
||||
InodeMode::from_bits_truncate(mask_mode)
|
||||
};
|
||||
let _ =
|
||||
dir_dentrymnt
|
||||
.dentry()
|
||||
.create(name.trim_end_matches('/'), InodeType::Dir, inode_mode)?;
|
||||
let _ = dir_dentrymnt.new_fs_child(name.trim_end_matches('/'), InodeType::Dir, inode_mode)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
pub fn sys_mkdir(pathname_addr: Vaddr, mode: u16) -> Result<SyscallReturn> {
|
||||
self::sys_mkdirat(AT_FDCWD, pathname_addr, mode)
|
||||
pub fn sys_mkdir(path_addr: Vaddr, mode: u16) -> Result<SyscallReturn> {
|
||||
self::sys_mkdirat(AT_FDCWD, path_addr, mode)
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ fn alloc_filebacked_vmo(
|
||||
let page_cache_vmo = {
|
||||
let fs_resolver = current.fs().read();
|
||||
let dentrymnt = fs_resolver.lookup_from_fd(fd)?;
|
||||
let inode = dentrymnt.dentry().inode();
|
||||
let inode = dentrymnt.inode();
|
||||
inode
|
||||
.page_cache()
|
||||
.ok_or(Error::with_message(
|
||||
|
@ -16,21 +16,21 @@ use crate::{
|
||||
|
||||
pub fn sys_openat(
|
||||
dirfd: FileDesc,
|
||||
pathname_addr: Vaddr,
|
||||
path_addr: Vaddr,
|
||||
flags: u32,
|
||||
mode: u16,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_OPENAT);
|
||||
let pathname = read_cstring_from_user(pathname_addr, MAX_FILENAME_LEN)?;
|
||||
let path = read_cstring_from_user(path_addr, MAX_FILENAME_LEN)?;
|
||||
debug!(
|
||||
"dirfd = {}, pathname = {:?}, flags = {}, mode = {}",
|
||||
dirfd, pathname, flags, mode
|
||||
"dirfd = {}, path = {:?}, flags = {}, mode = {}",
|
||||
dirfd, path, flags, mode
|
||||
);
|
||||
|
||||
let current = current!();
|
||||
let file_handle = {
|
||||
let pathname = pathname.to_string_lossy();
|
||||
let fs_path = FsPath::new(dirfd, pathname.as_ref())?;
|
||||
let path = path.to_string_lossy();
|
||||
let fs_path = FsPath::new(dirfd, path.as_ref())?;
|
||||
let mask_mode = mode & !current.umask().read().get();
|
||||
let inode_handle = current.fs().read().open(&fs_path, flags, mask_mode)?;
|
||||
Arc::new(inode_handle)
|
||||
@ -48,8 +48,8 @@ pub fn sys_openat(
|
||||
Ok(SyscallReturn::Return(fd as _))
|
||||
}
|
||||
|
||||
pub fn sys_open(pathname_addr: Vaddr, flags: u32, mode: u16) -> Result<SyscallReturn> {
|
||||
self::sys_openat(AT_FDCWD, pathname_addr, flags, mode)
|
||||
pub fn sys_open(path_addr: Vaddr, flags: u32, mode: u16) -> Result<SyscallReturn> {
|
||||
self::sys_openat(AT_FDCWD, path_addr, flags, mode)
|
||||
}
|
||||
|
||||
/// File for output busybox ash log.
|
||||
|
@ -14,27 +14,27 @@ use crate::{
|
||||
|
||||
pub fn sys_readlinkat(
|
||||
dirfd: FileDesc,
|
||||
pathname_addr: Vaddr,
|
||||
path_addr: Vaddr,
|
||||
usr_buf_addr: Vaddr,
|
||||
usr_buf_len: usize,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_READLINKAT);
|
||||
let pathname = read_cstring_from_user(pathname_addr, MAX_FILENAME_LEN)?;
|
||||
let path = read_cstring_from_user(path_addr, MAX_FILENAME_LEN)?;
|
||||
debug!(
|
||||
"dirfd = {}, pathname = {:?}, usr_buf_addr = 0x{:x}, usr_buf_len = 0x{:x}",
|
||||
dirfd, pathname, usr_buf_addr, usr_buf_len
|
||||
"dirfd = {}, path = {:?}, usr_buf_addr = 0x{:x}, usr_buf_len = 0x{:x}",
|
||||
dirfd, path, usr_buf_addr, usr_buf_len
|
||||
);
|
||||
|
||||
let current = current!();
|
||||
let dentrymnt = {
|
||||
let pathname = pathname.to_string_lossy();
|
||||
if pathname.is_empty() {
|
||||
let path = path.to_string_lossy();
|
||||
if path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||
}
|
||||
let fs_path = FsPath::new(dirfd, pathname.as_ref())?;
|
||||
let fs_path = FsPath::new(dirfd, path.as_ref())?;
|
||||
current.fs().read().lookup_no_follow(&fs_path)?
|
||||
};
|
||||
let linkpath = dentrymnt.dentry().inode().read_link()?;
|
||||
let linkpath = dentrymnt.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])?;
|
||||
@ -42,9 +42,9 @@ pub fn sys_readlinkat(
|
||||
}
|
||||
|
||||
pub fn sys_readlink(
|
||||
pathname_addr: Vaddr,
|
||||
path_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)
|
||||
self::sys_readlinkat(AT_FDCWD, path_addr, usr_buf_addr, usr_buf_len)
|
||||
}
|
||||
|
@ -15,40 +15,40 @@ use crate::{
|
||||
|
||||
pub fn sys_renameat(
|
||||
old_dirfd: FileDesc,
|
||||
old_pathname_addr: Vaddr,
|
||||
old_path_addr: Vaddr,
|
||||
new_dirfd: FileDesc,
|
||||
new_pathname_addr: Vaddr,
|
||||
new_path_addr: Vaddr,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_RENAMEAT);
|
||||
let old_pathname = read_cstring_from_user(old_pathname_addr, MAX_FILENAME_LEN)?;
|
||||
let new_pathname = read_cstring_from_user(new_pathname_addr, MAX_FILENAME_LEN)?;
|
||||
let old_path = read_cstring_from_user(old_path_addr, MAX_FILENAME_LEN)?;
|
||||
let new_path = read_cstring_from_user(new_path_addr, MAX_FILENAME_LEN)?;
|
||||
debug!(
|
||||
"old_dirfd = {}, old_pathname = {:?}, new_dirfd = {}, new_pathname = {:?}",
|
||||
old_dirfd, old_pathname, new_dirfd, new_pathname
|
||||
"old_dirfd = {}, old_path = {:?}, new_dirfd = {}, new_path = {:?}",
|
||||
old_dirfd, old_path, new_dirfd, new_path
|
||||
);
|
||||
|
||||
let current = current!();
|
||||
let fs = current.fs().read();
|
||||
|
||||
let (old_dir_dentrymnt, old_name) = {
|
||||
let old_pathname = old_pathname.to_string_lossy();
|
||||
if old_pathname.is_empty() {
|
||||
let old_path = old_path.to_string_lossy();
|
||||
if old_path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "oldpath is empty");
|
||||
}
|
||||
let old_fs_path = FsPath::new(old_dirfd, old_pathname.as_ref())?;
|
||||
let old_fs_path = FsPath::new(old_dirfd, old_path.as_ref())?;
|
||||
fs.lookup_dir_and_base_name(&old_fs_path)?
|
||||
};
|
||||
let old_dentrymnt = old_dir_dentrymnt.lookup(&old_name)?;
|
||||
|
||||
let (new_dir_dentrymnt, new_name) = {
|
||||
let new_pathname = new_pathname.to_string_lossy();
|
||||
if new_pathname.is_empty() {
|
||||
let new_path = new_path.to_string_lossy();
|
||||
if new_path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "newpath is empty");
|
||||
}
|
||||
if new_pathname.ends_with('/') && old_dentrymnt.dentry().type_() != InodeType::Dir {
|
||||
if new_path.ends_with('/') && old_dentrymnt.type_() != InodeType::Dir {
|
||||
return_errno_with_message!(Errno::ENOTDIR, "oldpath is not dir");
|
||||
}
|
||||
let new_fs_path = FsPath::new(new_dirfd, new_pathname.as_ref().trim_end_matches('/'))?;
|
||||
let new_fs_path = FsPath::new(new_dirfd, new_path.as_ref().trim_end_matches('/'))?;
|
||||
fs.lookup_dir_and_base_name(&new_fs_path)?
|
||||
};
|
||||
|
||||
@ -66,20 +66,11 @@ pub fn sys_renameat(
|
||||
}
|
||||
}
|
||||
|
||||
if !Arc::ptr_eq(
|
||||
old_dir_dentrymnt.mount_node(),
|
||||
new_dir_dentrymnt.mount_node(),
|
||||
) {
|
||||
return_errno_with_message!(Errno::EXDEV, "cannot cross mount");
|
||||
}
|
||||
|
||||
old_dir_dentrymnt
|
||||
.dentry()
|
||||
.rename(&old_name, new_dir_dentrymnt.dentry(), &new_name)?;
|
||||
old_dir_dentrymnt.rename(&old_name, &new_dir_dentrymnt, &new_name)?;
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
pub fn sys_rename(old_pathname_addr: Vaddr, new_pathname_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
self::sys_renameat(AT_FDCWD, old_pathname_addr, AT_FDCWD, new_pathname_addr)
|
||||
pub fn sys_rename(old_path_addr: Vaddr, new_path_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
self::sys_renameat(AT_FDCWD, old_path_addr, AT_FDCWD, new_path_addr)
|
||||
}
|
||||
|
@ -12,24 +12,24 @@ use crate::{
|
||||
util::read_cstring_from_user,
|
||||
};
|
||||
|
||||
pub fn sys_rmdir(pathname_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
self::sys_rmdirat(AT_FDCWD, pathname_addr)
|
||||
pub fn sys_rmdir(path_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
self::sys_rmdirat(AT_FDCWD, path_addr)
|
||||
}
|
||||
|
||||
pub(super) fn sys_rmdirat(dirfd: FileDesc, pathname_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
pub(super) fn sys_rmdirat(dirfd: FileDesc, path_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_RMDIR);
|
||||
let pathname = read_cstring_from_user(pathname_addr, MAX_FILENAME_LEN)?;
|
||||
debug!("dirfd = {}, pathname = {:?}", dirfd, pathname);
|
||||
let path_addr = read_cstring_from_user(path_addr, MAX_FILENAME_LEN)?;
|
||||
debug!("dirfd = {}, path_addr = {:?}", dirfd, path_addr);
|
||||
|
||||
let current = current!();
|
||||
let (dir_dentrymnt, name) = {
|
||||
let pathname = pathname.to_string_lossy();
|
||||
if pathname == "/" {
|
||||
let path_addr = path_addr.to_string_lossy();
|
||||
if path_addr == "/" {
|
||||
return_errno_with_message!(Errno::EBUSY, "is root directory");
|
||||
}
|
||||
let fs_path = FsPath::new(dirfd, pathname.as_ref())?;
|
||||
let fs_path = FsPath::new(dirfd, path_addr.as_ref())?;
|
||||
current.fs().read().lookup_dir_and_base_name(&fs_path)?
|
||||
};
|
||||
dir_dentrymnt.dentry().rmdir(name.trim_end_matches('/'))?;
|
||||
dir_dentrymnt.rmdir(name.trim_end_matches('/'))?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ pub fn sys_fstatat(
|
||||
fs.lookup(&fs_path)?
|
||||
}
|
||||
};
|
||||
let stat = Stat::from(dentrymnt.dentry().metadata());
|
||||
let stat = Stat::from(dentrymnt.metadata());
|
||||
write_val_to_user(stat_buf_ptr, &stat)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -15,19 +15,16 @@ use crate::{
|
||||
|
||||
pub fn sys_statfs(path_ptr: Vaddr, statfs_buf_ptr: Vaddr) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_STATFS);
|
||||
let pathname = read_cstring_from_user(path_ptr, PATH_MAX)?;
|
||||
debug!(
|
||||
"pathname = {:?}, statfs_buf_ptr = 0x{:x}",
|
||||
pathname, statfs_buf_ptr,
|
||||
);
|
||||
let path = read_cstring_from_user(path_ptr, PATH_MAX)?;
|
||||
debug!("path = {:?}, statfs_buf_ptr = 0x{:x}", path, statfs_buf_ptr,);
|
||||
|
||||
let current = current!();
|
||||
let path = {
|
||||
let pathname = pathname.to_string_lossy();
|
||||
let fs_path = FsPath::try_from(pathname.as_ref())?;
|
||||
let dentrymnt = {
|
||||
let path = path.to_string_lossy();
|
||||
let fs_path = FsPath::try_from(path.as_ref())?;
|
||||
current.fs().read().lookup(&fs_path)?
|
||||
};
|
||||
let statfs = Statfs::from(path.dentry().fs().sb());
|
||||
let statfs = Statfs::from(dentrymnt.fs().sb());
|
||||
write_val_to_user(statfs_buf_ptr, &statfs)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
@ -42,8 +39,8 @@ pub fn sys_fstatfs(fd: FileDesc, statfs_buf_ptr: Vaddr) -> Result<SyscallReturn>
|
||||
let inode_handle = file
|
||||
.downcast_ref::<InodeHandle>()
|
||||
.ok_or(Error::with_message(Errno::EBADF, "not inode"))?;
|
||||
let dentry = inode_handle.dentrymnt().dentry();
|
||||
let statfs = Statfs::from(dentry.fs().sb());
|
||||
let dentrymnt = inode_handle.dentrymnt();
|
||||
let statfs = Statfs::from(dentrymnt.fs().sb());
|
||||
write_val_to_user(statfs_buf_ptr, &statfs)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ pub fn sys_symlinkat(
|
||||
current.fs().read().lookup_dir_and_base_name(&fs_path)?
|
||||
};
|
||||
|
||||
let new_dentry = dir_dentrymnt.dentry().create(
|
||||
let new_dentry = dir_dentrymnt.new_fs_child(
|
||||
&link_name,
|
||||
InodeType::SymLink,
|
||||
InodeMode::from_bits_truncate(0o777),
|
||||
|
@ -28,21 +28,21 @@ pub fn sys_ftruncate(fd: FileDesc, len: isize) -> Result<SyscallReturn> {
|
||||
|
||||
pub fn sys_truncate(path_ptr: Vaddr, len: isize) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_TRUNCATE);
|
||||
let pathname = read_cstring_from_user(path_ptr, PATH_MAX)?;
|
||||
debug!("pathname = {:?}, length = {}", pathname, len);
|
||||
let path = read_cstring_from_user(path_ptr, PATH_MAX)?;
|
||||
debug!("path = {:?}, length = {}", path, len);
|
||||
|
||||
check_length(len)?;
|
||||
|
||||
let current = current!();
|
||||
let dir_dentrymnt = {
|
||||
let pathname = pathname.to_string_lossy();
|
||||
if pathname.is_empty() {
|
||||
let path = path.to_string_lossy();
|
||||
if path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||
}
|
||||
let fs_path = FsPath::new(AT_FDCWD, pathname.as_ref())?;
|
||||
let fs_path = FsPath::new(AT_FDCWD, path.as_ref())?;
|
||||
current.fs().read().lookup(&fs_path)?
|
||||
};
|
||||
dir_dentrymnt.dentry().resize(len as usize)?;
|
||||
dir_dentrymnt.resize(len as usize)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
|
@ -12,35 +12,35 @@ use crate::{
|
||||
util::read_cstring_from_user,
|
||||
};
|
||||
|
||||
pub fn sys_unlinkat(dirfd: FileDesc, pathname_addr: Vaddr, flags: u32) -> Result<SyscallReturn> {
|
||||
pub fn sys_unlinkat(dirfd: FileDesc, path_addr: Vaddr, flags: u32) -> Result<SyscallReturn> {
|
||||
let flags =
|
||||
UnlinkFlags::from_bits(flags).ok_or(Error::with_message(Errno::EINVAL, "invalid flags"))?;
|
||||
if flags.contains(UnlinkFlags::AT_REMOVEDIR) {
|
||||
return super::rmdir::sys_rmdirat(dirfd, pathname_addr);
|
||||
return super::rmdir::sys_rmdirat(dirfd, path_addr);
|
||||
}
|
||||
|
||||
log_syscall_entry!(SYS_UNLINKAT);
|
||||
let pathname = read_cstring_from_user(pathname_addr, MAX_FILENAME_LEN)?;
|
||||
debug!("dirfd = {}, pathname = {:?}", dirfd, pathname);
|
||||
let path = read_cstring_from_user(path_addr, MAX_FILENAME_LEN)?;
|
||||
debug!("dirfd = {}, path = {:?}", dirfd, path);
|
||||
|
||||
let current = current!();
|
||||
let (dir_dentrymnt, name) = {
|
||||
let pathname = pathname.to_string_lossy();
|
||||
if pathname.is_empty() {
|
||||
let path = path.to_string_lossy();
|
||||
if path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||
}
|
||||
if pathname.ends_with('/') {
|
||||
if path.ends_with('/') {
|
||||
return_errno_with_message!(Errno::EISDIR, "unlink on directory");
|
||||
}
|
||||
let fs_path = FsPath::new(dirfd, pathname.as_ref())?;
|
||||
let fs_path = FsPath::new(dirfd, path.as_ref())?;
|
||||
current.fs().read().lookup_dir_and_base_name(&fs_path)?
|
||||
};
|
||||
dir_dentrymnt.dentry().unlink(&name)?;
|
||||
dir_dentrymnt.unlink(&name)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
pub fn sys_unlink(pathname_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
self::sys_unlinkat(AT_FDCWD, pathname_addr, 0)
|
||||
pub fn sys_unlink(path_addr: Vaddr) -> Result<SyscallReturn> {
|
||||
self::sys_unlinkat(AT_FDCWD, path_addr, 0)
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
|
@ -14,12 +14,12 @@ use crate::{
|
||||
|
||||
pub fn sys_utimensat(
|
||||
dirfd: FileDesc,
|
||||
pathname_ptr: Vaddr,
|
||||
path_addr: Vaddr,
|
||||
timespecs_ptr: Vaddr,
|
||||
flags: u32,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_UTIMENSAT);
|
||||
let pathname = read_cstring_from_user(pathname_ptr, MAX_FILENAME_LEN)?;
|
||||
let path = read_cstring_from_user(path_addr, MAX_FILENAME_LEN)?;
|
||||
let (atime, mtime) = {
|
||||
let (autime, mutime) = if timespecs_ptr == 0 {
|
||||
(timespec_t::utime_now(), timespec_t::utime_now())
|
||||
@ -53,8 +53,8 @@ pub fn sys_utimensat(
|
||||
let flags = UtimensFlags::from_bits(flags)
|
||||
.ok_or(Error::with_message(Errno::EINVAL, "invalid flags"))?;
|
||||
debug!(
|
||||
"dirfd = {}, pathname = {:?}, atime = {:?}, mtime = {:?}, flags = {:?}",
|
||||
dirfd, pathname, atime, mtime, flags
|
||||
"dirfd = {}, path = {:?}, atime = {:?}, mtime = {:?}, flags = {:?}",
|
||||
dirfd, path, atime, mtime, flags
|
||||
);
|
||||
|
||||
if atime.is_none() && mtime.is_none() {
|
||||
@ -62,11 +62,11 @@ pub fn sys_utimensat(
|
||||
}
|
||||
let current = current!();
|
||||
let dentrymnt = {
|
||||
let pathname = pathname.to_string_lossy();
|
||||
if pathname.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "pathname is empty");
|
||||
let path = path.to_string_lossy();
|
||||
if path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "path is empty");
|
||||
}
|
||||
let fs_path = FsPath::new(dirfd, pathname.as_ref())?;
|
||||
let fs_path = FsPath::new(dirfd, path.as_ref())?;
|
||||
let fs = current.fs().read();
|
||||
if flags.contains(UtimensFlags::AT_SYMLINK_NOFOLLOW) {
|
||||
fs.lookup_no_follow(&fs_path)?
|
||||
@ -75,10 +75,10 @@ pub fn sys_utimensat(
|
||||
}
|
||||
};
|
||||
if let Some(time) = atime {
|
||||
dentrymnt.dentry().set_atime(Duration::from(time));
|
||||
dentrymnt.set_atime(Duration::from(time));
|
||||
}
|
||||
if let Some(time) = mtime {
|
||||
dentrymnt.dentry().set_mtime(Duration::from(time));
|
||||
dentrymnt.set_mtime(Duration::from(time));
|
||||
}
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ impl Vdso {
|
||||
let vdso_path = FsPath::new(AT_FDCWD, "/lib/x86_64-linux-gnu/vdso64.so").unwrap();
|
||||
let fs_resolver = FsResolver::new();
|
||||
let vdso_lib = fs_resolver.lookup(&vdso_path).unwrap();
|
||||
vdso_lib.dentry().inode().page_cache().unwrap()
|
||||
vdso_lib.inode().page_cache().unwrap()
|
||||
};
|
||||
let mut vdso_text = Box::new([0u8; PAGE_SIZE]);
|
||||
vdso_lib_vmo.read_bytes(0, &mut *vdso_text).unwrap();
|
||||
|
Loading…
x
Reference in New Issue
Block a user