fs: implement Seek syscall

This commit is contained in:
Mark Poliakov 2023-07-22 18:27:40 +03:00
parent ba3819ee8e
commit 461bfb2791
5 changed files with 125 additions and 102 deletions

View File

@ -198,8 +198,8 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
#[cfg(test)]
mod tests {
use std::rc::Rc;
use vfs::{Filesystem, IoContext, Read, Seek, SeekFrom, VnodeKind, Write};
use yggdrasil_abi::io::{FileMode, OpenOptions};
use vfs::{Filesystem, IoContext, Read, Seek, VnodeKind, Write};
use yggdrasil_abi::io::{FileMode, OpenOptions, SeekFrom};
use crate::MemoryFilesystem;

View File

@ -73,6 +73,13 @@ impl File {
flags: FileFlags::READ,
}))
}
pub fn node(&self) -> Result<VnodeRef, Error> {
match &self.inner {
FileInner::Normal(inner) => Ok(inner.vnode.clone()),
FileInner::Directory(inner) => Ok(inner.vnode.clone()),
}
}
}
impl Write for File {

View File

@ -3,7 +3,7 @@
use core::mem::MaybeUninit;
use yggdrasil_abi::error::Error;
use yggdrasil_abi::io::DirectoryEntry;
use yggdrasil_abi::io::{DirectoryEntry, SeekFrom};
extern crate alloc;
@ -29,13 +29,6 @@ pub use node::{Vnode, VnodeDump, VnodeImpl, VnodeKind, VnodeRef, VnodeWeak};
pub const DIR_POSITION_FROM_CACHE: u64 = u64::MAX;
#[derive(Debug)]
pub enum SeekFrom {
Start(u64),
End(i64),
Current(i64),
}
pub trait Write {
fn write(&mut self, data: &[u8]) -> Result<usize, Error>;
}

View File

@ -4,8 +4,8 @@ use elf::{
endian::AnyEndian,
ElfStream, ParseError,
};
use vfs::{FileRef, Read, Seek, SeekFrom};
use yggdrasil_abi::error::Error;
use vfs::{FileRef, Read, Seek};
use yggdrasil_abi::{error::Error, io::SeekFrom};
use crate::mem::{
phys::{self, PageUsage},

View File

@ -3,11 +3,11 @@ use core::{mem::MaybeUninit, time::Duration};
use abi::{
error::Error,
io::{DirectoryEntry, FileAttr, FileMode, OpenOptions, RawFd},
io::{DirectoryEntry, FileAttr, FileMode, OpenOptions, RawFd, SeekFrom},
syscall::SyscallFunction,
};
use alloc::rc::Rc;
use vfs::{Read, ReadDirectory, VnodeKind, Write};
use vfs::{Read, ReadDirectory, Seek, VnodeKind, VnodeRef, Write};
use yggdrasil_abi::{
error::SyscallResult,
io::{MountOptions, UnmountOptions},
@ -16,13 +16,37 @@ use yggdrasil_abi::{
use crate::{
fs,
mem::table::{PageAttributes, VirtualMemoryManager},
proc::wait,
proc::{io::ProcessIo, wait},
sync::IrqSafeSpinlockGuard,
task::process::Process,
};
mod arg;
use arg::*;
fn run_with_io<T, F: FnOnce(IrqSafeSpinlockGuard<ProcessIo>) -> T>(f: F) -> T {
let proc = Process::current();
let io = proc.io.lock();
f(io)
}
fn run_with_io_at<
T,
F: FnOnce(Option<VnodeRef>, IrqSafeSpinlockGuard<ProcessIo>) -> Result<T, Error>,
>(
at: Option<RawFd>,
f: F,
) -> Result<T, Error> {
let proc = Process::current();
let io = proc.io.lock();
let at = at
.map(|fd| io.file(fd).and_then(|f| f.borrow().node()))
.transpose()?;
f(at, io)
}
fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error> {
match func {
SyscallFunction::DebugTrace => {
@ -84,92 +108,87 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
let fd = RawFd(args[0] as u32);
let data = arg_buffer_ref(args[1] as _, args[2] as _)?;
let proc = Process::current();
let io = proc.io.lock();
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
run_with_io(|io| {
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
file_borrow.write(data)
file_borrow.write(data)
})
}
SyscallFunction::Read => {
let fd = RawFd(args[0] as u32);
let data = arg_buffer_mut(args[1] as _, args[2] as _)?;
let proc = Process::current();
let io = proc.io.lock();
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
run_with_io(|io| {
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
file_borrow.read(data)
file_borrow.read(data)
})
}
SyscallFunction::Open => {
let path = arg_user_str(args[0] as usize, args[1] as usize)?;
let opts = OpenOptions::from(args[2] as u32);
let mode = FileMode::from(args[3] as u32);
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let opts = OpenOptions::from(args[3] as u32);
let mode = FileMode::from(args[4] as u32);
let proc = Process::current();
let mut io = proc.io.lock();
run_with_io_at(at, |at, mut io| {
debugln!("run_with_io_at {:?}", at);
let file = io.ioctx().open(at, path, opts, mode)?;
let fd = io.place_file(file)?;
let file = io.ioctx().open(None, path, opts, mode)?;
let fd = io.place_file(file)?;
Ok(fd.0 as usize)
Ok(fd.0 as usize)
})
}
SyscallFunction::Close => {
let fd = RawFd(args[0] as u32);
let proc = Process::current();
let mut io = proc.io.lock();
io.close_file(fd)?;
Ok(0)
run_with_io(|mut io| {
io.close_file(fd)?;
Ok(0)
})
}
SyscallFunction::Mount => {
let options = arg_user_ref::<MountOptions>(args[0] as usize)?;
let proc = Process::current();
let mut io = proc.io.lock();
run_with_io(|mut io| {
let target_node = io.ioctx().find(None, options.target, true, false)?;
if !target_node.is_directory() {
return Err(Error::NotADirectory);
}
let target_node = io.ioctx().find(None, options.target, true, false)?;
if !target_node.is_directory() {
return Err(Error::NotADirectory);
}
let fs_root = fs::create_filesystem(options)?;
let fs_root = fs::create_filesystem(options)?;
target_node.mount(fs_root)?;
target_node.mount(fs_root)?;
debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
Ok(0)
Ok(0)
})
}
SyscallFunction::Unmount => {
let options = arg_user_ref::<UnmountOptions>(args[0] as usize)?;
let proc = Process::current();
let mut io = proc.io.lock();
run_with_io(|mut io| {
let mountpoint = io.ioctx().find(None, options.mountpoint, true, false)?;
mountpoint.unmount_target()?;
let mountpoint = io.ioctx().find(None, options.mountpoint, true, false)?;
mountpoint.unmount_target()?;
debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
Ok(0)
Ok(0)
})
}
SyscallFunction::OpenDirectory => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let proc = Process::current();
let mut io = proc.io.lock();
run_with_io_at(at, |at, mut io| {
let node = io.ioctx().find(at, path, true, true)?;
let file = node.open_directory()?;
let fd = io.place_file(file)?;
// TODO handle at
assert!(at.is_none());
let node = io.ioctx().find(None, path, true, true)?;
let file = node.open_directory()?;
let fd = io.place_file(file)?;
Ok(fd.0 as usize)
Ok(fd.0 as usize)
})
}
SyscallFunction::ReadDirectory => {
let fd = RawFd(args[0] as u32);
@ -178,53 +197,45 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
args[2] as usize,
)?;
let proc = Process::current();
let io = proc.io.lock();
run_with_io(|io| {
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
file_borrow.read_dir_entries(buffer)
file_borrow.read_dir_entries(buffer)
})
}
SyscallFunction::CreateDirectory => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let mode = FileMode::from(args[3] as u32);
let proc = Process::current();
let mut io = proc.io.lock();
run_with_io_at(at, |at, mut io| {
let (parent, name) = abi::path::split_right(path);
let parent_node = io.ioctx().find(at, parent, true, true)?;
parent_node.create(name, VnodeKind::Directory)?;
// TODO handle at
assert!(at.is_none());
let (parent, name) = abi::path::split_right(path);
let parent_node = io.ioctx().find(None, parent, true, true)?;
parent_node.create(name, VnodeKind::Directory)?;
Ok(0)
Ok(0)
})
}
SyscallFunction::Remove => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let recurse = args[3] != 0;
let proc = Process::current();
let mut io = proc.io.lock();
run_with_io_at(at, |at, mut io| {
let node = io.ioctx().find(at, path, false, false)?;
assert!(at.is_none());
if node.is_root() || Rc::ptr_eq(io.ioctx().root(), &node) {
todo!();
}
let node = io.ioctx().find(None, path, false, false)?;
let (_, filename) = abi::path::split_right(path);
let parent = node.parent();
if node.is_root() || Rc::ptr_eq(io.ioctx().root(), &node) {
todo!();
}
parent.remove(node, recurse)?;
let (_, filename) = abi::path::split_right(path);
let parent = node.parent();
parent.remove(node, recurse)?;
Ok(0)
Ok(0)
})
}
SyscallFunction::GetMetadata => {
let at = arg_option_fd(args[0] as u32);
@ -232,17 +243,29 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
let buffer = arg_user_mut::<MaybeUninit<FileAttr>>(args[3] as usize)?;
let follow = args[4] != 0;
let proc = Process::current();
let mut io = proc.io.lock();
run_with_io_at(at, |at, mut io| {
let node = if path.is_empty() {
at.ok_or(Error::InvalidArgument)?
} else {
io.ioctx().find(None, path, follow, true)?
};
assert!(at.is_none());
let metadata = node.metadata()?;
buffer.write(metadata);
let node = io.ioctx().find(None, path, follow, true)?;
Ok(0)
})
}
SyscallFunction::Seek => {
let fd = RawFd(args[0] as u32);
let pos = SeekFrom::from(args[1]);
let metadata = node.metadata()?;
buffer.write(metadata);
run_with_io(|io| {
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
Ok(0)
file_borrow.seek(pos).map(|v| v as usize)
})
}
}
}