mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 08:53:29 +00:00
Enhance the vnode
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
9606119028
commit
ece1a545ce
@ -9,14 +9,14 @@ impl InodeHandle<Rights> {
|
||||
access_mode: AccessMode,
|
||||
status_flags: StatusFlags,
|
||||
) -> Result<Self> {
|
||||
let inode_info = dentry.vnode().inode().metadata();
|
||||
if access_mode.is_readable() && !inode_info.mode.is_readable() {
|
||||
let vnode = dentry.vnode();
|
||||
if access_mode.is_readable() && !vnode.inode_mode().is_readable() {
|
||||
return_errno_with_message!(Errno::EACCES, "File is not readable");
|
||||
}
|
||||
if access_mode.is_writable() && !inode_info.mode.is_writable() {
|
||||
if access_mode.is_writable() && !vnode.inode_mode().is_writable() {
|
||||
return_errno_with_message!(Errno::EACCES, "File is not writable");
|
||||
}
|
||||
if access_mode.is_writable() && inode_info.type_ == InodeType::Dir {
|
||||
if access_mode.is_writable() && vnode.inode_type() == InodeType::Dir {
|
||||
return_errno_with_message!(Errno::EISDIR, "Directory cannot open to write");
|
||||
}
|
||||
let inner = Arc::new(InodeHandle_ {
|
||||
@ -43,6 +43,13 @@ impl InodeHandle<Rights> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
if !self.1.contains(Rights::READ) {
|
||||
return_errno_with_message!(Errno::EBADF, "File is not readable");
|
||||
}
|
||||
self.0.read_to_end(buf)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||
if !self.1.contains(Rights::WRITE) {
|
||||
return_errno_with_message!(Errno::EBADF, "File is not writable");
|
||||
|
@ -8,8 +8,6 @@ use crate::fs::utils::{
|
||||
};
|
||||
use crate::prelude::*;
|
||||
use crate::rights::Rights;
|
||||
use alloc::sync::Arc;
|
||||
use jinux_frame::vm::VmIo;
|
||||
|
||||
pub struct InodeHandle<R = Rights>(Arc<InodeHandle_>, R);
|
||||
|
||||
@ -23,20 +21,10 @@ struct InodeHandle_ {
|
||||
impl InodeHandle_ {
|
||||
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
let mut offset = self.offset.lock();
|
||||
let file_size = self.dentry.vnode().inode().metadata().size;
|
||||
let start = file_size.min(*offset);
|
||||
let end = file_size.min(*offset + buf.len());
|
||||
let len = if self.status_flags.lock().contains(StatusFlags::O_DIRECT) {
|
||||
self.dentry
|
||||
.vnode()
|
||||
.inode()
|
||||
.read_at(start, &mut buf[0..end - start])?
|
||||
self.dentry.vnode().read_direct_at(*offset, buf)?
|
||||
} else {
|
||||
self.dentry
|
||||
.vnode()
|
||||
.pages()
|
||||
.read_bytes(start, &mut buf[0..end - start])?;
|
||||
end - start
|
||||
self.dentry.vnode().read_at(*offset, buf)?
|
||||
};
|
||||
|
||||
*offset += len;
|
||||
@ -45,29 +33,28 @@ impl InodeHandle_ {
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||
let mut offset = self.offset.lock();
|
||||
let file_size = self.dentry.vnode().inode().metadata().size;
|
||||
if self.status_flags.lock().contains(StatusFlags::O_APPEND) {
|
||||
*offset = file_size;
|
||||
*offset = self.dentry.vnode().len();
|
||||
}
|
||||
let len = if self.status_flags.lock().contains(StatusFlags::O_DIRECT) {
|
||||
self.dentry.vnode().inode().write_at(*offset, buf)?
|
||||
self.dentry.vnode().write_direct_at(*offset, buf)?
|
||||
} else {
|
||||
let pages = self.dentry.vnode().pages();
|
||||
let should_expand_size = *offset + buf.len() > file_size;
|
||||
if should_expand_size {
|
||||
pages.resize(*offset + buf.len())?;
|
||||
}
|
||||
pages.write_bytes(*offset, buf)?;
|
||||
if should_expand_size {
|
||||
self.dentry.vnode().inode().resize(*offset + buf.len())?;
|
||||
}
|
||||
buf.len()
|
||||
self.dentry.vnode().write_at(*offset, buf)?
|
||||
};
|
||||
|
||||
*offset += len;
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
let len = if self.status_flags.lock().contains(StatusFlags::O_DIRECT) {
|
||||
self.dentry.vnode().read_direct_to_end(buf)?
|
||||
} else {
|
||||
self.dentry.vnode().read_to_end(buf)?
|
||||
};
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
pub fn seek(&self, pos: SeekFrom) -> Result<usize> {
|
||||
let mut offset = self.offset.lock();
|
||||
let new_offset: isize = match pos {
|
||||
@ -78,7 +65,7 @@ impl InodeHandle_ {
|
||||
off as isize
|
||||
}
|
||||
SeekFrom::End(off /* as isize */) => {
|
||||
let file_size = self.dentry.vnode().inode().metadata().size as isize;
|
||||
let file_size = self.dentry.vnode().len() as isize;
|
||||
assert!(file_size >= 0);
|
||||
file_size
|
||||
.checked_add(off)
|
||||
@ -125,7 +112,7 @@ impl InodeHandle_ {
|
||||
pub fn readdir(&self, writer: &mut dyn DirentWriter) -> Result<usize> {
|
||||
let mut offset = self.offset.lock();
|
||||
let mut dir_writer_ctx = DirentWriterContext::new(*offset, writer);
|
||||
let written_size = self.dentry.vnode().inode().readdir(&mut dir_writer_ctx)?;
|
||||
let written_size = self.dentry.vnode().readdir(&mut dir_writer_ctx)?;
|
||||
*offset = dir_writer_ctx.pos();
|
||||
Ok(written_size)
|
||||
}
|
||||
|
@ -10,6 +10,11 @@ impl<R: TRights> InodeHandle<R> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
#[require(R > Read)]
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
self.0.read_to_end(buf)
|
||||
}
|
||||
|
||||
#[require(R > Write)]
|
||||
pub fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||
self.0.write(buf)
|
||||
|
@ -70,7 +70,7 @@ impl FileHandle {
|
||||
pub fn metadata(&self) -> Metadata {
|
||||
match &self.inner {
|
||||
Inner::File(file) => file.metadata(),
|
||||
Inner::Inode(inode_handle) => inode_handle.dentry().vnode().inode().metadata(),
|
||||
Inner::Inode(inode_handle) => inode_handle.dentry().vnode().metadata(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,14 @@ use super::utils::{
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
static ref ROOT_FS: Arc<dyn FileSystem> = RamFS::new();
|
||||
static ref RAM_FS: Arc<dyn FileSystem> = RamFS::new();
|
||||
static ref ROOT_DENTRY: Arc<Dentry> = {
|
||||
fn init() -> Result<Arc<Dentry>> {
|
||||
let root_vnode = Vnode::new(RAM_FS.root_inode())?;
|
||||
Ok(Dentry::new_root(root_vnode))
|
||||
}
|
||||
init().unwrap()
|
||||
};
|
||||
}
|
||||
|
||||
pub struct FsResolver {
|
||||
@ -29,15 +36,11 @@ impl Clone for FsResolver {
|
||||
}
|
||||
|
||||
impl FsResolver {
|
||||
pub fn new() -> Result<Self> {
|
||||
let root = {
|
||||
let root_vnode = Vnode::new(ROOT_FS.root_inode())?;
|
||||
Dentry::new_root(root_vnode)
|
||||
};
|
||||
Ok(Self {
|
||||
root: root.clone(),
|
||||
cwd: root,
|
||||
})
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
root: ROOT_DENTRY.clone(),
|
||||
cwd: ROOT_DENTRY.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the root directory
|
||||
@ -65,8 +68,8 @@ impl FsResolver {
|
||||
let follow_tail_link = !creation_flags.contains(CreationFlags::O_NOFOLLOW);
|
||||
let dentry = match self.lookup_inner(path, follow_tail_link) {
|
||||
Ok(dentry) => {
|
||||
let inode = dentry.vnode().inode();
|
||||
if inode.metadata().type_ == InodeType::SymLink
|
||||
let vnode = dentry.vnode();
|
||||
if vnode.inode_type() == InodeType::SymLink
|
||||
&& !status_flags.contains(StatusFlags::O_PATH)
|
||||
{
|
||||
return_errno_with_message!(Errno::ELOOP, "file is a symlink");
|
||||
@ -77,7 +80,7 @@ impl FsResolver {
|
||||
return_errno_with_message!(Errno::EEXIST, "file exists");
|
||||
}
|
||||
if creation_flags.contains(CreationFlags::O_DIRECTORY)
|
||||
&& inode.metadata().type_ != InodeType::Dir
|
||||
&& vnode.inode_type() != InodeType::Dir
|
||||
{
|
||||
return_errno_with_message!(
|
||||
Errno::ENOTDIR,
|
||||
@ -98,7 +101,7 @@ impl FsResolver {
|
||||
if file_name.ends_with("/") {
|
||||
return_errno_with_message!(Errno::EISDIR, "path refers to a directory");
|
||||
}
|
||||
if !dir_dentry.vnode().inode().metadata().mode.is_writable() {
|
||||
if !dir_dentry.vnode().inode_mode().is_writable() {
|
||||
return_errno_with_message!(Errno::EPERM, "file cannot be created");
|
||||
}
|
||||
let new_dentry = dir_dentry.create(&file_name, InodeType::File, inode_mode)?;
|
||||
@ -181,7 +184,7 @@ impl FsResolver {
|
||||
|
||||
// Iterate next dentry
|
||||
let next_dentry = dentry.lookup(next_name)?;
|
||||
let next_type = next_dentry.vnode().inode().metadata().type_;
|
||||
let next_type = next_dentry.vnode().inode_type();
|
||||
let next_is_tail = path_remain.is_empty();
|
||||
|
||||
// If next inode is a symlink, follow symlinks at most `SYMLINKS_MAX` times.
|
||||
@ -190,7 +193,7 @@ impl FsResolver {
|
||||
return_errno_with_message!(Errno::ELOOP, "too many symlinks");
|
||||
}
|
||||
let link_path_remain = {
|
||||
let mut tmp_link_path = next_dentry.vnode().inode().read_link()?;
|
||||
let mut tmp_link_path = next_dentry.vnode().read_link()?;
|
||||
if tmp_link_path.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "empty symlink");
|
||||
}
|
||||
@ -279,9 +282,9 @@ impl FsResolver {
|
||||
// Dereference the tail symlinks if needed
|
||||
loop {
|
||||
match dir_dentry.lookup(&base_name.trim_end_matches('/')) {
|
||||
Ok(dentry) if dentry.vnode().inode().metadata().type_ == InodeType::SymLink => {
|
||||
Ok(dentry) if dentry.vnode().inode_type() == InodeType::SymLink => {
|
||||
let link = {
|
||||
let mut link = dentry.vnode().inode().read_link()?;
|
||||
let mut link = dentry.vnode().read_link()?;
|
||||
if link.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "invalid symlink");
|
||||
}
|
||||
|
@ -301,12 +301,12 @@ impl Inode for RamInode {
|
||||
return_errno_with_message!(Errno::EOPNOTSUPP, "direct write is not supported");
|
||||
}
|
||||
|
||||
fn resize(&self, new_size: usize) -> Result<()> {
|
||||
if self.0.read().metadata.type_ != InodeType::File {
|
||||
return_errno_with_message!(Errno::EISDIR, "self is not file");
|
||||
}
|
||||
fn len(&self) -> usize {
|
||||
self.0.read().metadata.size
|
||||
}
|
||||
|
||||
fn resize(&self, new_size: usize) {
|
||||
self.0.write().metadata.size = new_size;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mknod(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> {
|
||||
|
@ -2,7 +2,7 @@ use crate::prelude::*;
|
||||
use alloc::string::String;
|
||||
use spin::RwLockWriteGuard;
|
||||
|
||||
use super::{InodeMode, InodeType, Vnode, NAME_MAX};
|
||||
use super::{InodeMode, InodeType, Metadata, Vnode, NAME_MAX};
|
||||
|
||||
pub struct Dentry {
|
||||
inner: RwLock<Dentry_>,
|
||||
@ -68,12 +68,12 @@ impl Dentry {
|
||||
self.inner.write().parent = Some(Arc::downgrade(parent));
|
||||
}
|
||||
|
||||
pub fn vnode(&self) -> &Vnode {
|
||||
pub(in crate::fs) fn vnode(&self) -> &Vnode {
|
||||
&self.vnode
|
||||
}
|
||||
|
||||
pub fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<Self>> {
|
||||
if self.vnode.inode().metadata().type_ != InodeType::Dir {
|
||||
if self.vnode.inode_type() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
let mut inner = self.inner.write();
|
||||
@ -81,7 +81,7 @@ impl Dentry {
|
||||
return_errno!(Errno::EEXIST);
|
||||
}
|
||||
let child = {
|
||||
let vnode = Vnode::new(self.vnode.inode().mknod(name, type_, mode)?)?;
|
||||
let vnode = self.vnode.mknod(name, type_, mode)?;
|
||||
Dentry::new(name, vnode, Some(inner.this.clone()))
|
||||
};
|
||||
inner.children.insert(String::from(name), child.clone());
|
||||
@ -89,7 +89,7 @@ impl Dentry {
|
||||
}
|
||||
|
||||
pub fn lookup(&self, name: &str) -> Result<Arc<Self>> {
|
||||
if self.vnode.inode().metadata().type_ != InodeType::Dir {
|
||||
if self.vnode.inode_type() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
if name.len() > NAME_MAX {
|
||||
@ -104,7 +104,7 @@ impl Dentry {
|
||||
if let Some(dentry) = inner.children.get(name) {
|
||||
dentry.clone()
|
||||
} else {
|
||||
let vnode = Vnode::new(self.vnode.inode().lookup(name)?)?;
|
||||
let vnode = self.vnode.lookup(name)?;
|
||||
let dentry = Dentry::new(name, vnode, Some(inner.this.clone()));
|
||||
inner.children.insert(String::from(name), dentry.clone());
|
||||
dentry
|
||||
@ -115,7 +115,7 @@ impl Dentry {
|
||||
}
|
||||
|
||||
pub fn link(&self, old: &Arc<Self>, name: &str) -> Result<()> {
|
||||
if self.vnode.inode().metadata().type_ != InodeType::Dir {
|
||||
if self.vnode.inode_type() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
let mut inner = self.inner.write();
|
||||
@ -123,38 +123,51 @@ impl Dentry {
|
||||
return_errno!(Errno::EEXIST);
|
||||
}
|
||||
let target_vnode = old.vnode();
|
||||
self.vnode.inode().link(target_vnode.inode(), name)?;
|
||||
self.vnode.link(target_vnode, name)?;
|
||||
let new_dentry = Self::new(name, target_vnode.clone(), Some(inner.this.clone()));
|
||||
inner.children.insert(String::from(name), new_dentry);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unlink(&self, name: &str) -> Result<()> {
|
||||
if self.vnode.inode().metadata().type_ != InodeType::Dir {
|
||||
if self.vnode.inode_type() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
let mut inner = self.inner.write();
|
||||
self.vnode.inode().unlink(name)?;
|
||||
self.vnode.unlink(name)?;
|
||||
inner.children.remove(name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn rmdir(&self, name: &str) -> Result<()> {
|
||||
if self.vnode.inode().metadata().type_ != InodeType::Dir {
|
||||
if self.vnode.inode_type() != InodeType::Dir {
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
let mut inner = self.inner.write();
|
||||
self.vnode.inode().rmdir(name)?;
|
||||
self.vnode.rmdir(name)?;
|
||||
inner.children.remove(name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_link(&self) -> Result<String> {
|
||||
if self.vnode.inode_type() != InodeType::SymLink {
|
||||
return_errno!(Errno::EINVAL);
|
||||
}
|
||||
self.vnode.read_link()
|
||||
}
|
||||
|
||||
pub fn write_link(&self, target: &str) -> Result<()> {
|
||||
if self.vnode.inode_type() != InodeType::SymLink {
|
||||
return_errno!(Errno::EINVAL);
|
||||
}
|
||||
self.vnode.write_link(target)
|
||||
}
|
||||
|
||||
pub 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");
|
||||
}
|
||||
if self.vnode.inode().metadata().type_ != InodeType::Dir
|
||||
|| new_dir.vnode.inode().metadata().type_ != InodeType::Dir
|
||||
if self.vnode.inode_type() != InodeType::Dir || new_dir.vnode.inode_type() != InodeType::Dir
|
||||
{
|
||||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
@ -168,12 +181,10 @@ impl Dentry {
|
||||
let dentry = if let Some(dentry) = inner.children.get(old_name) {
|
||||
dentry.clone()
|
||||
} else {
|
||||
let vnode = Vnode::new(self.vnode.inode().lookup(old_name)?)?;
|
||||
let vnode = self.vnode.lookup(old_name)?;
|
||||
Dentry::new(old_name, vnode, Some(inner.this.clone()))
|
||||
};
|
||||
self.vnode
|
||||
.inode()
|
||||
.rename(old_name, self.vnode.inode(), new_name)?;
|
||||
self.vnode.rename(old_name, &self.vnode, new_name)?;
|
||||
inner.children.remove(old_name);
|
||||
dentry.set_name(new_name);
|
||||
inner.children.insert(String::from(new_name), dentry);
|
||||
@ -183,12 +194,10 @@ impl Dentry {
|
||||
let dentry = if let Some(dentry) = self_inner.children.get(old_name) {
|
||||
dentry.clone()
|
||||
} else {
|
||||
let vnode = Vnode::new(self.vnode.inode().lookup(old_name)?)?;
|
||||
let vnode = self.vnode.lookup(old_name)?;
|
||||
Dentry::new(old_name, vnode, Some(self_inner.this.clone()))
|
||||
};
|
||||
self.vnode
|
||||
.inode()
|
||||
.rename(old_name, new_dir.vnode.inode(), new_name)?;
|
||||
self.vnode.rename(old_name, &new_dir.vnode, new_name)?;
|
||||
self_inner.children.remove(old_name);
|
||||
dentry.set_name(new_name);
|
||||
dentry.set_parent(&new_dir.this());
|
||||
@ -199,6 +208,22 @@ impl Dentry {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn inode_metadata(&self) -> Metadata {
|
||||
self.vnode.metadata()
|
||||
}
|
||||
|
||||
pub fn inode_type(&self) -> InodeType {
|
||||
self.vnode.inode_type()
|
||||
}
|
||||
|
||||
pub fn inode_mode(&self) -> InodeMode {
|
||||
self.vnode.inode_mode()
|
||||
}
|
||||
|
||||
pub fn inode_len(&self) -> usize {
|
||||
self.vnode.len()
|
||||
}
|
||||
|
||||
pub fn abs_path(&self) -> String {
|
||||
let mut path = self.name();
|
||||
let mut dentry = self.this();
|
||||
|
@ -159,7 +159,9 @@ pub struct Timespec {
|
||||
}
|
||||
|
||||
pub trait Inode: Any + Sync + Send {
|
||||
fn resize(&self, new_size: usize) -> Result<()>;
|
||||
fn len(&self) -> usize;
|
||||
|
||||
fn resize(&self, new_size: usize);
|
||||
|
||||
fn metadata(&self) -> Metadata;
|
||||
|
||||
|
@ -1,31 +1,186 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use super::{Inode, PageCacheManager};
|
||||
use super::{DirentWriterContext, Inode, InodeMode, InodeType, Metadata, PageCacheManager};
|
||||
use crate::rights::Rights;
|
||||
use crate::vm::vmo::{Vmo, VmoFlags, VmoOptions};
|
||||
use alloc::string::String;
|
||||
use jinux_frame::vm::VmIo;
|
||||
|
||||
/// VFS-level representation of an inode
|
||||
#[derive(Clone)]
|
||||
pub struct Vnode {
|
||||
// The RwLock is to maintain the correct file length for concurrent read or write.
|
||||
inner: Arc<RwLock<Inner>>,
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
inode: Arc<dyn Inode>,
|
||||
pages: Vmo,
|
||||
page_cache: Vmo,
|
||||
page_cache_manager: Arc<PageCacheManager>,
|
||||
}
|
||||
|
||||
impl Vnode {
|
||||
pub fn new(inode: Arc<dyn Inode>) -> Result<Self> {
|
||||
let page_cache_manager = Arc::new(PageCacheManager::new(&Arc::downgrade(&inode)));
|
||||
let pages = VmoOptions::<Rights>::new(inode.metadata().size)
|
||||
let page_cache = VmoOptions::<Rights>::new(inode.len())
|
||||
.flags(VmoFlags::RESIZABLE)
|
||||
.pager(page_cache_manager)
|
||||
.pager(page_cache_manager.clone())
|
||||
.alloc()?;
|
||||
Ok(Self { inode, pages })
|
||||
Ok(Self {
|
||||
inner: Arc::new(RwLock::new(Inner {
|
||||
inode,
|
||||
page_cache,
|
||||
page_cache_manager,
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pages(&self) -> &Vmo {
|
||||
&self.pages
|
||||
pub fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||
let type_ = self.inode_type();
|
||||
if type_ != InodeType::File && type_ != InodeType::Socket {
|
||||
return_errno!(Errno::EINVAL);
|
||||
}
|
||||
let inner = self.inner.write();
|
||||
let file_len = inner.inode.len();
|
||||
let should_expand_len = offset + buf.len() > file_len;
|
||||
if should_expand_len {
|
||||
inner.page_cache.resize(offset + buf.len())?;
|
||||
}
|
||||
inner.page_cache.write_bytes(offset, buf)?;
|
||||
if should_expand_len {
|
||||
inner.inode.resize(offset + buf.len());
|
||||
}
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
pub fn inode(&self) -> &Arc<dyn Inode> {
|
||||
&self.inode
|
||||
pub fn write_direct_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||
let type_ = self.inode_type();
|
||||
if type_ != InodeType::File && type_ != InodeType::Socket {
|
||||
return_errno!(Errno::EINVAL);
|
||||
}
|
||||
let inner = self.inner.write();
|
||||
let file_len = inner.inode.len();
|
||||
if offset + buf.len() > file_len {
|
||||
inner.page_cache.resize(offset + buf.len())?;
|
||||
}
|
||||
// Flush the dirty pages if necessary.
|
||||
// inner.page_cache_manager.flush(offset..offset + buf.len())?;
|
||||
// TODO: Update the related page state to invalid to reload the content from inode
|
||||
// for upcoming read or write.
|
||||
inner.inode.write_at(offset, buf)
|
||||
}
|
||||
|
||||
pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
let type_ = self.inode_type();
|
||||
if type_ != InodeType::File && type_ != InodeType::Socket {
|
||||
return_errno!(Errno::EISDIR);
|
||||
}
|
||||
let inner = self.inner.read();
|
||||
let (offset, read_len) = {
|
||||
let file_len = inner.inode.len();
|
||||
let start = file_len.min(offset);
|
||||
let end = file_len.min(offset + buf.len());
|
||||
(start, end - start)
|
||||
};
|
||||
inner.page_cache.read_bytes(offset, &mut buf[..read_len])?;
|
||||
Ok(read_len)
|
||||
}
|
||||
|
||||
pub fn read_direct_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
let type_ = self.inode_type();
|
||||
if type_ != InodeType::File && type_ != InodeType::Socket {
|
||||
return_errno!(Errno::EISDIR);
|
||||
}
|
||||
let inner = self.inner.read();
|
||||
// Flush the dirty pages if necessary.
|
||||
// inner.page_cache_manager.flush(offset..offset + buf.len())?;
|
||||
inner.inode.read_at(offset, buf)
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
let type_ = self.inode_type();
|
||||
if type_ != InodeType::File && type_ != InodeType::Socket {
|
||||
return_errno!(Errno::EISDIR);
|
||||
}
|
||||
let inner = self.inner.read();
|
||||
let file_len = inner.inode.len();
|
||||
if buf.len() < file_len {
|
||||
buf.resize(file_len, 0);
|
||||
}
|
||||
inner.page_cache.read_bytes(0, &mut buf[..file_len])?;
|
||||
Ok(file_len)
|
||||
}
|
||||
|
||||
pub fn read_direct_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
let type_ = self.inode_type();
|
||||
if type_ != InodeType::File && type_ != InodeType::Socket {
|
||||
return_errno!(Errno::EISDIR);
|
||||
}
|
||||
let inner = self.inner.read();
|
||||
let file_len = inner.inode.len();
|
||||
if buf.len() < file_len {
|
||||
buf.resize(file_len, 0);
|
||||
}
|
||||
// Flush the dirty pages if necessary.
|
||||
// inner.page_cache_manager.flush(..file_size)?;
|
||||
let len = inner.inode.read_at(0, &mut buf[..file_len])?;
|
||||
Ok(len)
|
||||
}
|
||||
|
||||
pub fn mknod(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Self> {
|
||||
let inode = self.inner.read().inode.mknod(name, type_, mode)?;
|
||||
Self::new(inode)
|
||||
}
|
||||
|
||||
pub fn lookup(&self, name: &str) -> Result<Self> {
|
||||
let inode = self.inner.read().inode.lookup(name)?;
|
||||
Self::new(inode)
|
||||
}
|
||||
|
||||
pub fn link(&self, old: &Vnode, name: &str) -> Result<()> {
|
||||
self.inner.read().inode.link(&old.inner.read().inode, name)
|
||||
}
|
||||
|
||||
pub fn unlink(&self, name: &str) -> Result<()> {
|
||||
self.inner.read().inode.unlink(name)
|
||||
}
|
||||
|
||||
pub fn rmdir(&self, name: &str) -> Result<()> {
|
||||
self.inner.read().inode.rmdir(name)
|
||||
}
|
||||
|
||||
pub fn rename(&self, old_name: &str, target: &Vnode, new_name: &str) -> Result<()> {
|
||||
self.inner
|
||||
.read()
|
||||
.inode
|
||||
.rename(old_name, &target.inner.read().inode, new_name)
|
||||
}
|
||||
|
||||
pub fn read_link(&self) -> Result<String> {
|
||||
self.inner.read().inode.read_link()
|
||||
}
|
||||
|
||||
pub fn write_link(&self, target: &str) -> Result<()> {
|
||||
self.inner.write().inode.write_link(target)
|
||||
}
|
||||
|
||||
pub fn readdir(&self, ctx: &mut DirentWriterContext) -> Result<usize> {
|
||||
self.inner.read().inode.readdir(ctx)
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> Metadata {
|
||||
self.inner.read().inode.metadata()
|
||||
}
|
||||
|
||||
pub fn inode_type(&self) -> InodeType {
|
||||
self.inner.read().inode.metadata().type_
|
||||
}
|
||||
|
||||
pub fn inode_mode(&self) -> InodeMode {
|
||||
self.inner.read().inode.metadata().mode
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.inner.read().inode.len()
|
||||
}
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ impl Process {
|
||||
let pid = thread.tid();
|
||||
let user_vm = UserVm::new();
|
||||
let file_table = FileTable::new_with_stdio();
|
||||
let fs = FsResolver::new().unwrap();
|
||||
let fs = FsResolver::new();
|
||||
let sig_dispositions = SigDispositions::new();
|
||||
|
||||
let process = Process::new(
|
||||
@ -231,7 +231,7 @@ impl Process {
|
||||
let thread = Thread::new_kernel_thread(task_fn, weak_process_ref.clone());
|
||||
let pid = thread.tid();
|
||||
let file_table = FileTable::new();
|
||||
let fs = FsResolver::new().unwrap();
|
||||
let fs = FsResolver::new();
|
||||
let sig_dispositions = SigDispositions::new();
|
||||
// FIXME: kernel process does not need root vmar
|
||||
let root_vmar = Vmar::<Full>::new_root().unwrap();
|
||||
|
@ -44,7 +44,7 @@ pub fn sys_readlinkat(
|
||||
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 linkpath = dentry.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,7 @@ pub fn sys_renameat(
|
||||
if new_pathname.is_empty() {
|
||||
return_errno_with_message!(Errno::ENOENT, "newpath is empty");
|
||||
}
|
||||
if new_pathname.ends_with("/")
|
||||
&& old_dentry.vnode().inode().metadata().type_ != InodeType::Dir
|
||||
{
|
||||
if new_pathname.ends_with("/") && old_dentry.inode_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('/'))?;
|
||||
|
@ -65,7 +65,7 @@ pub fn sys_fstatat(
|
||||
fs.lookup(&fs_path)?
|
||||
}
|
||||
};
|
||||
let stat = Stat::from(dentry.vnode().inode().metadata());
|
||||
let stat = Stat::from(dentry.inode_metadata());
|
||||
write_val_to_user(stat_buf_ptr, &stat)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ pub fn sys_symlinkat(
|
||||
InodeType::SymLink,
|
||||
InodeMode::from_bits_truncate(0o777),
|
||||
)?;
|
||||
new_dentry.vnode().inode().write_link(&target)?;
|
||||
new_dentry.write_link(&target)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user