proc: reimplement OpenOptions

This commit is contained in:
Mark Poliakov 2023-07-20 15:40:49 +03:00
parent 0bdc30afdc
commit d3e3d3add8
11 changed files with 63 additions and 165 deletions

View File

@ -8,7 +8,6 @@ edition = "2021"
[dependencies]
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
vfs = { path = "lib/vfs" }
vfs-macros = { path = "lib/vfs/macros" }
aarch64-cpu = "9.3.1"
atomic_enum = "0.2.0"

View File

@ -7,5 +7,4 @@ edition = "2021"
[dependencies]
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
vfs-macros = { path = "macros" }
bitflags = "2.3.3"

View File

@ -1,16 +0,0 @@
[package]
name = "vfs-macros"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
proc-macro = true
[dependencies]
lazy_static = "1.4.0"
proc-macro-crate = "1.3.1"
proc-macro2 = "1.0.66"
quote = "1.0.31"
syn = { version = "2.0.26", features = ["full"] }

View File

@ -1,55 +0,0 @@
use std::collections::HashSet;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use proc_macro_crate::{crate_name, FoundCrate};
use quote::{quote, ToTokens};
use syn::{parse_macro_input, ImplItem, ItemImpl};
mod vnode_impl;
use vnode_impl::IMPLS;
#[proc_macro_attribute]
pub fn auto_vnode_impl(attr: TokenStream, input: TokenStream) -> TokenStream {
let current_crate = crate_name("vfs").unwrap();
let vfs_crate = match current_crate {
FoundCrate::Itself => Ident::new("crate", Span::call_site()),
FoundCrate::Name(name) => Ident::new(&name, Span::call_site()),
};
let vfs_crate = quote! { #vfs_crate };
let mut impl_item = parse_macro_input!(input as ItemImpl);
let behavior = if attr.is_empty() {
"unimplemented".to_string()
} else {
parse_macro_input!(attr as Ident).to_string()
};
let behavior = match behavior.as_str() {
"unimplemented" => quote! { unimplemented!() },
"panic" => quote! { panic!() },
"error" => quote! { Err(yggdrasil_abi::error::Error::NotImplemented) },
_ => panic!("Unknown #[auto_vnode_impl] behavior: {:?}", behavior),
};
let mut missing_impls: HashSet<&str> = HashSet::from_iter(IMPLS.keys().copied());
for item in &impl_item.items {
match item {
ImplItem::Fn(f) => {
let name = &f.sig.ident.to_string();
missing_impls.remove(name.as_str());
}
_ => panic!("Unexpected item in Vnode impl"),
}
}
for &item in &missing_impls {
let f = IMPLS.get(item).unwrap();
let fn_impl = f(&vfs_crate, &behavior);
impl_item.items.push(ImplItem::Verbatim(fn_impl));
}
impl_item.to_token_stream().into()
}

View File

@ -1,60 +0,0 @@
use std::collections::HashMap;
use proc_macro2::TokenStream as TS2;
use quote::quote;
fn impl_open(vfs: &TS2, behavior: &TS2) -> TS2 {
quote! {
fn open(&mut self, _node: &#vfs::VnodeRef, _opts: yggdrasil_abi::io::OpenFlags)
-> Result<u64, yggdrasil_abi::error::Error> {
#behavior
}
}
}
fn impl_close(vfs: &TS2, behavior: &TS2) -> TS2 {
quote! {
fn close(&mut self, _node: &#vfs::VnodeRef) -> Result<(), Error> {
#behavior
}
}
}
fn impl_create(vfs: &TS2, behavior: &TS2) -> TS2 {
quote! {
fn create(&mut self, _at: &#vfs::VnodeRef, _name: &str, _kind: #vfs::VnodeKind)
-> Result<#vfs::VnodeRef, yggdrasil_abi::error::Error> {
#behavior
}
}
}
fn impl_write(vfs: &TS2, behavior: &TS2) -> TS2 {
quote! {
fn write(&mut self, _node: &#vfs::VnodeRef, _pos: u64, _data: &[u8])
-> Result<usize, yggdrasil_abi::error::Error> {
#behavior
}
}
}
fn impl_read(vfs: &TS2, behavior: &TS2) -> TS2 {
quote! {
fn read(&mut self, _node: &#vfs::VnodeRef, _pos: u64, _data: &mut [u8])
-> Result<usize, yggdrasil_abi::error::Error> {
#behavior
}
}
}
lazy_static::lazy_static! {
pub static ref IMPLS: HashMap<&'static str, fn(&TS2, &TS2) -> TS2> = {
let mut m = HashMap::new();
m.insert("open".into(), impl_open as _);
m.insert("close".into(), impl_close as _);
m.insert("create".into(), impl_create as _);
m.insert("write".into(), impl_write as _);
m.insert("read".into(), impl_read as _);
m
};
}

View File

@ -1,5 +1,7 @@
use vfs_macros::auto_vnode_impl;
use yggdrasil_abi::{error::Error, io::OpenFlags};
use yggdrasil_abi::{
error::Error,
io::{FileMode, OpenOptions},
};
use crate::{node::VnodeImpl, VnodeRef};
@ -18,9 +20,13 @@ impl CharDeviceWrapper {
}
}
#[auto_vnode_impl(error)]
impl VnodeImpl for CharDeviceWrapper {
fn open(&mut self, _node: &VnodeRef, _opts: OpenFlags) -> Result<u64, Error> {
fn open(
&mut self,
_node: &VnodeRef,
_opts: OpenOptions,
_mode: FileMode,
) -> Result<u64, Error> {
Ok(0)
}

View File

@ -1,4 +1,8 @@
use yggdrasil_abi::{error::Error, io::OpenFlags, path};
use yggdrasil_abi::{
error::Error,
io::{FileMode, OpenOptions},
path,
};
use crate::{file::FileRef, node::VnodeRef};
@ -107,7 +111,8 @@ impl IoContext {
&self,
at: Option<VnodeRef>,
path: &str,
opts: OpenFlags,
opts: OpenOptions,
mode: FileMode,
) -> Result<FileRef, Error> {
let node = match self.find(at.clone(), path, true, true) {
Err(Error::DoesNotExist) => {
@ -117,7 +122,7 @@ impl IoContext {
o => o,
}?;
node.open(opts)
node.open(opts, mode)
}
pub fn root(&self) -> &VnodeRef {

View File

@ -9,7 +9,10 @@ use alloc::{
string::String,
vec::Vec,
};
use yggdrasil_abi::{error::Error, io::OpenFlags};
use yggdrasil_abi::{
error::Error,
io::{FileMode, OpenOptions},
};
use crate::{
file::{File, FileFlags, FileRef},
@ -46,16 +49,33 @@ pub struct Vnode {
}
pub trait VnodeImpl {
fn create(&mut self, at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error>;
fn create(&mut self, _at: &VnodeRef, _name: &str, _kind: VnodeKind) -> Result<VnodeRef, Error> {
Err(Error::NotImplemented)
}
fn open(&mut self, node: &VnodeRef, opts: OpenFlags) -> Result<u64, Error>;
fn close(&mut self, node: &VnodeRef) -> Result<(), Error>;
fn open(
&mut self,
_node: &VnodeRef,
_opts: OpenOptions,
_mode: FileMode,
) -> Result<u64, Error> {
Err(Error::NotImplemented)
}
fn read(&mut self, node: &VnodeRef, pos: u64, data: &mut [u8]) -> Result<usize, Error>;
fn write(&mut self, node: &VnodeRef, pos: u64, data: &[u8]) -> Result<usize, Error>;
fn close(&mut self, _node: &VnodeRef) -> Result<(), Error> {
Err(Error::NotImplemented)
}
fn read(&mut self, _node: &VnodeRef, _pos: u64, _data: &mut [u8]) -> Result<usize, Error> {
Err(Error::NotImplemented)
}
fn write(&mut self, _node: &VnodeRef, _pos: u64, _data: &[u8]) -> Result<usize, Error> {
Err(Error::NotImplemented)
}
fn size(&mut self, _node: &VnodeRef) -> Result<u64, Error> {
unimplemented!()
Err(Error::NotImplemented)
}
}
@ -205,13 +225,13 @@ impl Vnode {
}
// Node operations
pub fn open(self: &VnodeRef, flags: OpenFlags) -> Result<FileRef, Error> {
pub fn open(self: &VnodeRef, flags: OpenOptions, mode: FileMode) -> Result<FileRef, Error> {
let mut open_flags = FileFlags::empty();
if flags.is_read() {
if flags.contains(OpenOptions::READ) {
open_flags |= FileFlags::READ;
}
if flags.is_write() {
if flags.contains(OpenOptions::WRITE) {
open_flags |= FileFlags::WRITE;
}
@ -220,7 +240,7 @@ impl Vnode {
}
if let Some(ref mut data) = *self.data() {
let pos = data.open(self, flags)?;
let pos = data.open(self, flags, mode)?;
Ok(File::normal(self.clone(), pos, open_flags))
} else {
todo!()

View File

@ -1,8 +1,7 @@
use abi::error::Error;
use abi::{error::Error, io::FileMode};
use alloc::{boxed::Box, rc::Rc};
use vfs::{Filesystem, Vnode, VnodeImpl, VnodeKind, VnodeRef};
use vfs_macros::auto_vnode_impl;
use yggdrasil_abi::io::OpenFlags;
use yggdrasil_abi::io::OpenOptions;
use crate::util::OneTimeInit;
@ -163,7 +162,6 @@ struct RegularInode {
data: &'static [u8],
}
#[auto_vnode_impl]
impl VnodeImpl for DirInode {
fn create(&mut self, _at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error> {
let child = Vnode::new(name, kind);
@ -176,10 +174,9 @@ impl VnodeImpl for DirInode {
}
}
#[auto_vnode_impl]
impl VnodeImpl for RegularInode {
fn open(&mut self, node: &VnodeRef, opts: OpenFlags) -> Result<u64, Error> {
if opts.is_write() {
fn open(&mut self, node: &VnodeRef, opts: OpenOptions, _mode: FileMode) -> Result<u64, Error> {
if opts.contains(OpenOptions::WRITE) {
panic!("TODO: tarfs write");
}

View File

@ -17,11 +17,11 @@ extern crate yggdrasil_abi as abi;
use abi::{
error::Error,
io::{OpenFlags, RawFd},
io::{FileMode, OpenOptions, RawFd},
};
use fs::{devfs, tar::TarFilesystem, INITRD_DATA};
use task::process::Process;
use vfs::{Filesystem, IoContext, Read, VnodeRef};
use vfs::{Filesystem, IoContext, VnodeRef};
extern crate alloc;
@ -66,13 +66,15 @@ pub fn kernel_main() {
let ioctx = IoContext::new(root);
let node = ioctx.find(None, "/init", true, true).unwrap();
let file = node.open(OpenFlags::new().read()).unwrap();
let file = node.open(OpenOptions::READ, FileMode::empty()).unwrap();
{
let user_init = proc::exec::load_elf(file, &["/init"]).unwrap();
let mut io = user_init.io.lock();
io.set_ioctx(ioctx);
let stdout = tty_node.open(OpenFlags::new().write()).unwrap();
let stdout = tty_node
.open(OpenOptions::WRITE, FileMode::empty())
.unwrap();
let stderr = stdout.clone();
io.set_file(RawFd::STDOUT, stdout).unwrap();

View File

@ -3,7 +3,7 @@ use core::time::Duration;
use abi::{
error::Error,
io::{OpenFlags, RawFd},
io::{FileMode, OpenOptions, RawFd},
syscall::SyscallFunction,
};
use vfs::{Read, Write};
@ -103,12 +103,13 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
}
SyscallFunction::Open => {
let path = arg_user_str(args[0] as usize, args[1] as usize)?;
let opts = OpenFlags(args[2] as u32);
let opts = OpenOptions::from(args[2] as u32);
let mode = FileMode::from(args[3] as u32);
let proc = Process::current();
let mut io = proc.io.lock();
let file = io.ioctx().open(None, path, opts)?;
let file = io.ioctx().open(None, path, opts, mode)?;
let fd = io.place_file(file)?;
Ok(fd.0 as usize)