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