Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • bjorn3/redox-scheme
  • vadorovsky/redox-scheme
  • redox-os/redox-scheme
  • 4lDO2/redox-scheme
  • rw_van/redox-scheme
5 results
Show changes
Commits on Source (49)
/Cargo.lock
/target /target
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "libc"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "libredox"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "962b650e6b934f95cec493e1464e0f5cba98dd9ba9ef2b1c42cdfdb7864cab5a"
dependencies = [
"bitflags 2.4.1",
"libc",
"redox_syscall",
]
[[package]]
name = "redox-scheme"
version = "0.1.0"
dependencies = [
"libredox",
"redox_syscall",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[package] [package]
name = "redox-scheme" name = "redox-scheme"
authors = ["4lDO2 <4lDO2@protonmail.com>"] authors = ["4lDO2 <4lDO2@protonmail.com>"]
version = "0.1.0" version = "0.5.0"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
exclude = ["target"]
repository = "https://gitlab.redox-os.org/redox-os/redox-scheme"
description = "Library for writing Redox scheme daemons"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
redox_syscall = "0.4.1" redox_syscall = "0.5.10"
libredox = "0.0.3" libredox = { version = "0.1.3", default-features = false, features = ["redox_syscall", "call"] }
#!/usr/bin/env bash
set -e
echo "Generating SchemeMut from Scheme"
sed 's/trait Scheme/trait SchemeMut/' scheme.rs \
| sed 's/\&self/\&mut self/g' \
> scheme_mut.rs
echo "Generating SchemeBlock from Scheme"
sed 's/trait Scheme/trait SchemeBlock/' scheme.rs \
| sed 's/fn handle(\&self, packet: \&mut Packet)/fn handle(\&self, packet: \&Packet) -> Option<usize>/' \
| sed 's/packet.a = Error::mux(res);/res.transpose().map(Error::mux)/' \
| sed 's/\.map(|f| f\.bits())/\.map(|f| f.map(|f| f.bits()))/' \
| sed 's/\.map(|o| o as usize)/.map(|o| o.map(|o| o as usize))/' \
| sed 's/Ok(0)/Ok(Some(0))/g' \
| sed 's/Result<\([^>]\+\)>/Result<Option<\1>>/g' \
| sed 's/convert_to_this_scheme/convert_to_this_scheme_block/g' \
| sed 's/convert_in_scheme_handle/convert_in_scheme_handle_block/g' \
> scheme_block.rs
echo "Generating SchemeBlockMut from SchemeBlock"
sed 's/trait SchemeBlock/trait SchemeBlockMut/' scheme_block.rs \
| sed 's/\&self/\&mut self/g' \
> scheme_block_mut.rs
use core::{slice, str}; #![no_std]
use libredox::flag; extern crate alloc;
use syscall::{Error, Packet, Result, EOPNOTSUPP, ESKMSG, SKMSG_FRETURNFD}; use alloc::format;
pub use self::scheme::Scheme; use core::str;
pub use self::scheme_block::SchemeBlock; use core::task::Poll;
pub use self::scheme_block_mut::SchemeBlockMut;
pub use self::scheme_mut::SchemeMut;
pub use self::seek::*;
unsafe fn str_from_raw_parts(ptr: *const u8, len: usize) -> Option<&'static str> { use libredox::flag;
let slice = slice::from_raw_parts(ptr, len); use syscall::error::{Error, Result, EINTR};
str::from_utf8(slice).ok() use syscall::flag::{FobtainFdFlags, SendFdFlags};
} use syscall::schemev2::{Cqe, CqeOpcode, NewFdFlags, Opcode, Sqe};
mod scheme; pub mod scheme;
mod scheme_block;
mod scheme_block_mut;
mod scheme_mut;
mod seek;
pub struct CallerCtx { pub struct CallerCtx {
pub pid: usize, pub pid: usize,
...@@ -27,107 +20,158 @@ pub struct CallerCtx { ...@@ -27,107 +20,158 @@ pub struct CallerCtx {
} }
pub enum OpenResult { pub enum OpenResult {
ThisScheme { number: usize }, ThisScheme { number: usize, flags: NewFdFlags },
OtherScheme { fd: usize }, OtherScheme { fd: usize },
} }
// TODO: Find a better solution than generate.sh use core::mem::size_of;
pub(crate) fn convert_to_this_scheme(r: Result<usize>) -> Result<OpenResult> {
r.map(|number| OpenResult::ThisScheme { number }) use self::scheme::IntoTag;
#[repr(transparent)]
#[derive(Debug, Default)]
pub struct Request {
sqe: Sqe,
} }
pub(crate) fn convert_to_this_scheme_block(r: Result<Option<usize>>) -> Result<Option<OpenResult>> {
r.map(|o| o.map(|number| OpenResult::ThisScheme { number })) #[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
pub struct Id(u32);
#[derive(Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
pub struct Tag(Id);
#[derive(Debug)]
pub struct CancellationRequest {
pub id: Id,
} }
pub(crate) fn convert_in_scheme_handle_block(
_: &Packet, #[repr(transparent)]
result: Result<Option<OpenResult>>, #[derive(Debug)]
) -> Result<Option<usize>> { pub struct CallRequest {
match result { inner: Request,
Ok(Some(OpenResult::ThisScheme { number })) => Ok(Some(number)),
Ok(Some(OpenResult::OtherScheme { .. })) => Err(Error::new(EOPNOTSUPP)),
Ok(None) => Ok(None),
Err(err) => Err(err),
}
} }
pub(crate) fn convert_in_scheme_handle(
packet: &mut Packet, #[repr(transparent)]
result: Result<OpenResult>, #[derive(Debug)]
) -> Result<usize> { pub struct SendFdRequest {
match result { inner: Request,
Ok(OpenResult::ThisScheme { number }) => Ok(number),
Ok(OpenResult::OtherScheme { fd }) => {
packet.b = SKMSG_FRETURNFD;
packet.c = fd;
Err(Error::new(ESKMSG))
}
Err(err) => Err(err),
}
} }
impl CallerCtx { pub enum RequestKind {
pub fn from_packet(packet: &Packet) -> Self { Call(CallRequest),
Self { Cancellation(CancellationRequest),
pid: packet.pid, SendFd(SendFdRequest),
uid: packet.uid, MsyncMsg,
gid: packet.gid, MunmapMsg,
} MmapMsg,
OnClose { id: usize },
}
impl CallRequest {
#[inline]
pub fn request(&self) -> &Request {
&self.inner
}
#[inline]
pub fn request_id(&self) -> Id {
Id(self.inner.sqe.tag)
} }
} }
use core::mem::size_of; impl SendFdRequest {
#[inline]
pub fn request(&self) -> &Request {
&self.inner
}
#[inline]
pub fn request_id(&self) -> Id {
Id(self.inner.sqe.tag)
}
#[repr(transparent)] pub fn id(&self) -> usize {
#[derive(Clone, Copy, Default)] self.inner.sqe.args[0] as usize
pub struct Request(Packet); }
impl Request { pub fn flags(&self) -> SendFdFlags {
pub fn context_id(&self) -> usize { SendFdFlags::from_bits_retain(self.inner.sqe.args[1] as usize)
self.0.pid
} }
pub fn handle_scheme(mut self, scheme: &impl Scheme) -> Response {
unsafe { pub fn obtain_fd(
scheme.handle(&mut self.0); &self,
socket: &Socket,
flags: FobtainFdFlags,
dst_fd_or_ptr: Result<usize, &mut usize>,
) -> Result<()> {
assert!(!flags.contains(FobtainFdFlags::MANUAL_FD));
match dst_fd_or_ptr {
Ok(dst_fd) => {
socket.inner.write(&Cqe {
flags: CqeOpcode::ObtainFd as u8,
extra_raw: usize::to_ne_bytes((flags | FobtainFdFlags::MANUAL_FD).bits())[..3]
.try_into()
.unwrap(),
tag: self.request_id().0,
result: dst_fd as u64,
})?;
}
Err(ptr) => {
socket.inner.write(&Cqe {
flags: CqeOpcode::ObtainFd as u8,
extra_raw: usize::to_ne_bytes(flags.bits())[..3].try_into().unwrap(),
tag: self.request_id().0,
result: ptr as *mut usize as u64,
})?;
}
} }
Response(self.0) Ok(())
} }
pub fn handle_scheme_mut(mut self, scheme: &mut impl SchemeMut) -> Response { }
unsafe {
scheme.handle(&mut self.0); impl Request {
} #[inline]
Response(self.0) pub fn context_id(&self) -> usize {
} self.sqe.caller as usize
pub fn handle_scheme_block(
mut self,
scheme: &mut impl SchemeBlock,
) -> Result<Response, Request> {
match unsafe { scheme.handle(&mut self.0) } {
Some(code) => Ok(Response(Packet { a: code, ..self.0 })),
None => Err(self),
}
} }
pub fn handle_scheme_block_mut( pub fn kind(self) -> RequestKind {
mut self, match Opcode::try_from_raw(self.sqe.opcode) {
scheme: &mut impl SchemeBlockMut, Some(Opcode::Cancel) => RequestKind::Cancellation(CancellationRequest {
) -> Result<Response, Request> { id: Id(self.sqe.tag),
match unsafe { scheme.handle(&mut self.0) } { }),
Some(code) => Ok(Response(Packet { a: code, ..self.0 })), Some(Opcode::Sendfd) => RequestKind::SendFd(SendFdRequest {
None => Err(self), inner: Request { sqe: self.sqe },
}),
Some(Opcode::Msync) => RequestKind::MsyncMsg,
//Some(Opcode::Munmap) => RequestKind::MunmapMsg,
Some(Opcode::RequestMmap) => RequestKind::MmapMsg,
Some(Opcode::CloseMsg) => RequestKind::OnClose {
id: self.sqe.args[0] as usize,
},
_ => RequestKind::Call(CallRequest {
inner: Request { sqe: self.sqe },
}),
} }
} }
} }
pub struct Socket(libredox::Fd); pub struct Socket {
inner: libredox::Fd,
}
impl Socket { impl Socket {
fn create_inner(name: &str, nonblock: bool) -> Result<Self> { fn create_inner(name: &str, nonblock: bool) -> Result<Self> {
let mut flags = 0; let mut flags = flag::O_FSYNC | 0x0020_0000 /* O_EXLOCK */;
if nonblock { if nonblock {
flags |= flag::O_NONBLOCK; flags |= flag::O_NONBLOCK;
} }
let fd = libredox::Fd::open(&format!(":{name}"), flag::O_CLOEXEC | flag::O_CREAT | flags, 0)?; let fd = libredox::Fd::open(
Ok(Self(fd)) &format!(":{name}"),
flag::O_CLOEXEC | flag::O_CREAT | flags,
0,
)?;
Ok(Self { inner: fd })
} }
pub fn create(name: impl AsRef<str>) -> Result<Self> { pub fn create(name: impl AsRef<str>) -> Result<Self> {
Self::create_inner(name.as_ref(), false) Self::create_inner(name.as_ref(), false)
...@@ -136,33 +180,88 @@ impl Socket { ...@@ -136,33 +180,88 @@ impl Socket {
Self::create_inner(name.as_ref(), true) Self::create_inner(name.as_ref(), true)
} }
pub fn read_requests(&self, buf: &mut [Request], behavior: SignalBehavior) -> Result<usize> { pub fn read_requests(&self, buf: &mut [Request], behavior: SignalBehavior) -> Result<usize> {
read_requests(self.0.raw(), buf, behavior) read_requests(self.inner.raw(), buf, behavior)
} }
pub fn next_request(&self, behavior: SignalBehavior) -> Result<Option<Request>> { pub fn next_request(&self, behavior: SignalBehavior) -> Result<Option<Request>> {
let mut buf = [Request::default()]; let mut buf = [Request::default()];
Ok(if self.read_requests(&mut buf, behavior)? > 0 { Ok(if self.read_requests(&mut buf, behavior)? > 0 {
Some(buf[0]) let [req] = buf;
Some(req)
} else { } else {
None None
}) })
} }
pub fn write_responses(&self, buf: &[Response], behavior: SignalBehavior) -> Result<usize> { pub fn write_responses(&self, buf: &[Response], behavior: SignalBehavior) -> Result<usize> {
write_responses(self.0.raw(), buf, behavior) write_responses(self.inner.raw(), buf, behavior)
}
pub fn write_response(&self, resp: Response, behavior: SignalBehavior) -> Result<bool> {
Ok(self.write_responses(&[resp], behavior)? > 0)
}
pub fn post_fevent(&self, id: usize, flags: usize) -> Result<()> {
self.inner.write(&Cqe {
flags: CqeOpcode::SendFevent as u8,
extra_raw: [0_u8; 3],
tag: flags as u32,
result: id as u64,
})?;
Ok(())
} }
pub fn inner(&self) -> &libredox::Fd { pub fn inner(&self) -> &libredox::Fd {
&self.0 &self.inner
} }
} }
#[repr(transparent)] #[repr(transparent)]
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
pub struct Response(Packet); pub struct Response(Cqe);
impl Response { impl Response {
pub fn new(req: &Request, status: Result<usize>) -> Self { #[inline]
Self(Packet { pub fn err(err: i32, req: impl IntoTag) -> Self {
a: Error::mux(status), Self::new(Err(Error::new(err)), req)
..req.0 }
#[inline]
pub fn ok(status: usize, req: impl IntoTag) -> Self {
Self::new(Ok(status), req)
}
#[inline]
pub fn ready_ok(status: usize, req: impl IntoTag) -> Poll<Self> {
Poll::Ready(Self::ok(status, req))
}
#[inline]
pub fn ready_err(err: i32, req: impl IntoTag) -> Poll<Self> {
Poll::Ready(Self::err(err, req))
}
pub fn new(status: Result<usize>, req: impl IntoTag) -> Self {
Self(Cqe {
flags: CqeOpcode::RespondRegular as u8,
extra_raw: [0_u8; 3],
result: Error::mux(status) as u64,
tag: req.into_tag().0 .0,
})
}
pub fn open_dup_like(res: Result<OpenResult>, req: impl IntoTag) -> Response {
match res {
Ok(OpenResult::ThisScheme { number, flags }) => {
Response::new(Ok(number), req).with_extra([flags.bits(), 0, 0])
}
Err(e) => Response::new(Err(e), req),
Ok(OpenResult::OtherScheme { fd }) => Response::return_external_fd(fd, req),
}
}
pub fn return_external_fd(fd: usize, req: impl IntoTag) -> Self {
Self(Cqe {
flags: CqeOpcode::RespondWithFd as u8,
extra_raw: [0_u8; 3],
result: fd as u64,
tag: req.into_tag().0 .0,
})
}
pub fn with_extra(self, extra: [u8; 3]) -> Self {
Self(Cqe {
extra_raw: extra,
..self.0
}) })
} }
} }
...@@ -186,13 +285,11 @@ pub fn read_requests( ...@@ -186,13 +285,11 @@ pub fn read_requests(
core::slice::from_raw_parts_mut(buf.as_mut_ptr().cast(), len) core::slice::from_raw_parts_mut(buf.as_mut_ptr().cast(), len)
}) { }) {
Ok(n) => break n, Ok(n) => break n,
error @ Err(Error { Err(error) if error.errno() == EINTR => match behavior {
errno: libredox::errno::EINTR,
}) => match behavior {
SignalBehavior::Restart => continue, SignalBehavior::Restart => continue,
SignalBehavior::Interrupt => return error, SignalBehavior::Interrupt => return Err(error.into()),
}, },
Err(err) => return Err(err), Err(err) => return Err(err.into()),
} }
}; };
...@@ -213,13 +310,11 @@ pub fn write_responses(socket: usize, buf: &[Response], behavior: SignalBehavior ...@@ -213,13 +310,11 @@ pub fn write_responses(socket: usize, buf: &[Response], behavior: SignalBehavior
let bytes_written = loop { let bytes_written = loop {
match libredox::call::write(socket, bytes) { match libredox::call::write(socket, bytes) {
Ok(n) => break n, Ok(n) => break n,
error @ Err(Error { Err(error) if error.errno() == EINTR => match behavior {
errno: libredox::errno::EINTR,
}) => match behavior {
SignalBehavior::Restart => continue, SignalBehavior::Restart => continue,
SignalBehavior::Interrupt => return error, SignalBehavior::Interrupt => return Err(error.into()),
}, },
Err(err) => return Err(err), Err(err) => return Err(err.into()),
} }
}; };
debug_assert_eq!(bytes_written % size_of::<Response>(), 0); debug_assert_eq!(bytes_written % size_of::<Response>(), 0);
......
This diff is collapsed.
use core::{mem, slice};
use crate::*;
use syscall::data::*;
use syscall::error::*;
use syscall::flag::*;
use syscall::number::*;
pub trait SchemeBlock {
unsafe fn handle(&self, packet: &Packet) -> Option<usize> {
let res = match packet.a {
SYS_OPEN => {
if let Some(path) = str_from_raw_parts(packet.b as *const u8, packet.c) {
convert_in_scheme_handle_block(
packet,
self.xopen(path, packet.d, &CallerCtx::from_packet(&packet)),
)
} else {
Err(Error::new(EINVAL))
}
}
SYS_RMDIR => {
if let Some(path) = str_from_raw_parts(packet.b as *const u8, packet.c) {
self.rmdir(path, packet.uid, packet.gid)
} else {
Err(Error::new(EINVAL))
}
}
SYS_UNLINK => {
if let Some(path) = str_from_raw_parts(packet.b as *const u8, packet.c) {
self.unlink(path, packet.uid, packet.gid)
} else {
Err(Error::new(EINVAL))
}
}
SYS_DUP => convert_in_scheme_handle_block(
packet,
self.xdup(
packet.b,
slice::from_raw_parts(packet.c as *const u8, packet.d),
&CallerCtx::from_packet(&packet),
),
),
SYS_READ => self.read(packet.b, {
slice::from_raw_parts_mut(packet.c as *mut u8, packet.d)
}),
SYS_WRITE => self.write(packet.b, {
slice::from_raw_parts(packet.c as *const u8, packet.d)
}),
SYS_LSEEK => self
.seek(packet.b, packet.c as isize, packet.d)
.map(|o| o.map(|o| o as usize)),
SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16),
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
SYS_FEVENT => self
.fevent(packet.b, EventFlags::from_bits_truncate(packet.c))
.map(|f| f.map(|f| f.bits())),
SYS_FPATH => self.fpath(packet.b, {
slice::from_raw_parts_mut(packet.c as *mut u8, packet.d)
}),
SYS_FRENAME => {
if let Some(path) = str_from_raw_parts(packet.c as *const u8, packet.d) {
self.frename(packet.b, path, packet.uid, packet.gid)
} else {
Err(Error::new(EINVAL))
}
}
SYS_FSTAT => {
if packet.d >= mem::size_of::<Stat>() {
self.fstat(packet.b, &mut *(packet.c as *mut Stat))
} else {
Err(Error::new(EFAULT))
}
}
SYS_FSTATVFS => {
if packet.d >= mem::size_of::<StatVfs>() {
self.fstatvfs(packet.b, &mut *(packet.c as *mut StatVfs))
} else {
Err(Error::new(EFAULT))
}
}
SYS_FSYNC => self.fsync(packet.b),
SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c),
SYS_FUTIMENS => {
if packet.d >= mem::size_of::<TimeSpec>() {
self.futimens(packet.b, {
slice::from_raw_parts(
packet.c as *const TimeSpec,
packet.d / mem::size_of::<TimeSpec>(),
)
})
} else {
Err(Error::new(EFAULT))
}
}
SYS_CLOSE => self.close(packet.b),
KSMSG_MMAP_PREP => self.mmap_prep(
packet.b,
u64::from(packet.uid) | (u64::from(packet.gid) << 32),
packet.c,
MapFlags::from_bits_truncate(packet.d),
),
KSMSG_MUNMAP => self.munmap(
packet.b,
u64::from(packet.uid) | (u64::from(packet.gid) << 32),
packet.c,
MunmapFlags::from_bits_truncate(packet.d),
),
_ => Err(Error::new(ENOSYS)),
};
res.transpose().map(Error::mux)
}
/* Scheme operations */
#[allow(unused_variables)]
fn open(&self, path: &str, flags: usize, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(ENOENT))
}
#[allow(unused_variables)]
fn xopen(&self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<Option<OpenResult>> {
convert_to_this_scheme_block(self.open(path, flags, ctx.uid, ctx.gid))
}
#[allow(unused_variables)]
fn chmod(&self, path: &str, mode: u16, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(ENOENT))
}
#[allow(unused_variables)]
fn rmdir(&self, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(ENOENT))
}
#[allow(unused_variables)]
fn unlink(&self, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(ENOENT))
}
/* Resource operations */
#[allow(unused_variables)]
fn dup(&self, old_id: usize, buf: &[u8]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn xdup(&self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<Option<OpenResult>> {
convert_to_this_scheme_block(self.dup(old_id, buf))
}
#[allow(unused_variables)]
fn read(&self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn write(&self, id: usize, buf: &[u8]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn seek(&self, id: usize, pos: isize, whence: usize) -> Result<Option<isize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fchmod(&self, id: usize, mode: u16) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fchown(&self, id: usize, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fevent(&self, id: usize, flags: EventFlags) -> Result<Option<EventFlags>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn frename(&self, id: usize, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fstat(&self, id: usize, stat: &mut Stat) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fsync(&self, id: usize) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn ftruncate(&self, id: usize, len: usize) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn futimens(&self, id: usize, times: &[TimeSpec]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn close(&self, id: usize) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn mmap_prep(&self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result<Option<usize>> {
Err(Error::new(EOPNOTSUPP))
}
#[allow(unused_variables)]
fn munmap(&self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result<Option<usize>> {
Err(Error::new(EOPNOTSUPP))
}
}
use core::{mem, slice};
use crate::*;
use syscall::data::*;
use syscall::error::*;
use syscall::flag::*;
use syscall::number::*;
pub trait SchemeBlockMut {
unsafe fn handle(&mut self, packet: &Packet) -> Option<usize> {
let res = match packet.a {
SYS_OPEN => {
if let Some(path) = str_from_raw_parts(packet.b as *const u8, packet.c) {
convert_in_scheme_handle_block(
packet,
self.xopen(path, packet.d, &CallerCtx::from_packet(&packet)),
)
} else {
Err(Error::new(EINVAL))
}
}
SYS_RMDIR => {
if let Some(path) = str_from_raw_parts(packet.b as *const u8, packet.c) {
self.rmdir(path, packet.uid, packet.gid)
} else {
Err(Error::new(EINVAL))
}
}
SYS_UNLINK => {
if let Some(path) = str_from_raw_parts(packet.b as *const u8, packet.c) {
self.unlink(path, packet.uid, packet.gid)
} else {
Err(Error::new(EINVAL))
}
}
SYS_DUP => convert_in_scheme_handle_block(
packet,
self.xdup(
packet.b,
slice::from_raw_parts(packet.c as *const u8, packet.d),
&CallerCtx::from_packet(&packet),
),
),
SYS_READ => self.read(packet.b, {
slice::from_raw_parts_mut(packet.c as *mut u8, packet.d)
}),
SYS_WRITE => self.write(packet.b, {
slice::from_raw_parts(packet.c as *const u8, packet.d)
}),
SYS_LSEEK => self
.seek(packet.b, packet.c as isize, packet.d)
.map(|o| o.map(|o| o as usize)),
SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16),
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
SYS_FEVENT => self
.fevent(packet.b, EventFlags::from_bits_truncate(packet.c))
.map(|f| f.map(|f| f.bits())),
SYS_FPATH => self.fpath(packet.b, {
slice::from_raw_parts_mut(packet.c as *mut u8, packet.d)
}),
SYS_FRENAME => {
if let Some(path) = str_from_raw_parts(packet.c as *const u8, packet.d) {
self.frename(packet.b, path, packet.uid, packet.gid)
} else {
Err(Error::new(EINVAL))
}
}
SYS_FSTAT => {
if packet.d >= mem::size_of::<Stat>() {
self.fstat(packet.b, &mut *(packet.c as *mut Stat))
} else {
Err(Error::new(EFAULT))
}
}
SYS_FSTATVFS => {
if packet.d >= mem::size_of::<StatVfs>() {
self.fstatvfs(packet.b, &mut *(packet.c as *mut StatVfs))
} else {
Err(Error::new(EFAULT))
}
}
SYS_FSYNC => self.fsync(packet.b),
SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c),
SYS_FUTIMENS => {
if packet.d >= mem::size_of::<TimeSpec>() {
self.futimens(packet.b, {
slice::from_raw_parts(
packet.c as *const TimeSpec,
packet.d / mem::size_of::<TimeSpec>(),
)
})
} else {
Err(Error::new(EFAULT))
}
}
SYS_CLOSE => self.close(packet.b),
KSMSG_MMAP_PREP => self.mmap_prep(
packet.b,
u64::from(packet.uid) | (u64::from(packet.gid) << 32),
packet.c,
MapFlags::from_bits_truncate(packet.d),
),
KSMSG_MUNMAP => self.munmap(
packet.b,
u64::from(packet.uid) | (u64::from(packet.gid) << 32),
packet.c,
MunmapFlags::from_bits_truncate(packet.d),
),
_ => Err(Error::new(ENOSYS)),
};
res.transpose().map(Error::mux)
}
/* Scheme operations */
#[allow(unused_variables)]
fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(ENOENT))
}
#[allow(unused_variables)]
fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<Option<OpenResult>> {
convert_to_this_scheme_block(self.open(path, flags, ctx.uid, ctx.gid))
}
#[allow(unused_variables)]
fn chmod(&mut self, path: &str, mode: u16, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(ENOENT))
}
#[allow(unused_variables)]
fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(ENOENT))
}
#[allow(unused_variables)]
fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(ENOENT))
}
/* Resource operations */
#[allow(unused_variables)]
fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn xdup(&mut self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<Option<OpenResult>> {
convert_to_this_scheme_block(self.dup(old_id, buf))
}
#[allow(unused_variables)]
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn write(&mut self, id: usize, buf: &[u8]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result<Option<isize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fchmod(&mut self, id: usize, mode: u16) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fevent(&mut self, id: usize, flags: EventFlags) -> Result<Option<EventFlags>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn frename(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fsync(&mut self, id: usize) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn ftruncate(&mut self, id: usize, len: usize) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn futimens(&mut self, id: usize, times: &[TimeSpec]) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn close(&mut self, id: usize) -> Result<Option<usize>> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result<Option<usize>> {
Err(Error::new(EOPNOTSUPP))
}
#[allow(unused_variables)]
fn munmap(&mut self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result<Option<usize>> {
Err(Error::new(EOPNOTSUPP))
}
}
use core::{mem, slice};
use crate::*;
use syscall::data::*;
use syscall::error::*;
use syscall::flag::*;
use syscall::number::*;
pub trait SchemeMut {
unsafe fn handle(&mut self, packet: &mut Packet) {
let res = match packet.a {
SYS_OPEN => {
if let Some(path) = str_from_raw_parts(packet.b as *const u8, packet.c) {
convert_in_scheme_handle(
packet,
self.xopen(path, packet.d, &CallerCtx::from_packet(&packet)),
)
} else {
Err(Error::new(EINVAL))
}
}
SYS_RMDIR => {
if let Some(path) = str_from_raw_parts(packet.b as *const u8, packet.c) {
self.rmdir(path, packet.uid, packet.gid)
} else {
Err(Error::new(EINVAL))
}
}
SYS_UNLINK => {
if let Some(path) = str_from_raw_parts(packet.b as *const u8, packet.c) {
self.unlink(path, packet.uid, packet.gid)
} else {
Err(Error::new(EINVAL))
}
}
SYS_DUP => convert_in_scheme_handle(
packet,
self.xdup(
packet.b,
slice::from_raw_parts(packet.c as *const u8, packet.d),
&CallerCtx::from_packet(&packet),
),
),
SYS_READ => self.read(packet.b, {
slice::from_raw_parts_mut(packet.c as *mut u8, packet.d)
}),
SYS_WRITE => self.write(packet.b, {
slice::from_raw_parts(packet.c as *const u8, packet.d)
}),
SYS_LSEEK => self
.seek(packet.b, packet.c as isize, packet.d)
.map(|o| o as usize),
SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16),
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
SYS_FEVENT => self
.fevent(packet.b, EventFlags::from_bits_truncate(packet.c))
.map(|f| f.bits()),
SYS_FPATH => self.fpath(packet.b, {
slice::from_raw_parts_mut(packet.c as *mut u8, packet.d)
}),
SYS_FRENAME => {
if let Some(path) = str_from_raw_parts(packet.c as *const u8, packet.d) {
self.frename(packet.b, path, packet.uid, packet.gid)
} else {
Err(Error::new(EINVAL))
}
}
SYS_FSTAT => {
if packet.d >= mem::size_of::<Stat>() {
self.fstat(packet.b, &mut *(packet.c as *mut Stat))
} else {
Err(Error::new(EFAULT))
}
}
SYS_FSTATVFS => {
if packet.d >= mem::size_of::<StatVfs>() {
self.fstatvfs(packet.b, &mut *(packet.c as *mut StatVfs))
} else {
Err(Error::new(EFAULT))
}
}
SYS_FSYNC => self.fsync(packet.b),
SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c),
SYS_FUTIMENS => {
if packet.d >= mem::size_of::<TimeSpec>() {
self.futimens(packet.b, {
slice::from_raw_parts(
packet.c as *const TimeSpec,
packet.d / mem::size_of::<TimeSpec>(),
)
})
} else {
Err(Error::new(EFAULT))
}
}
SYS_CLOSE => self.close(packet.b),
KSMSG_MMAP_PREP => self.mmap_prep(
packet.b,
u64::from(packet.uid) | (u64::from(packet.gid) << 32),
packet.c,
MapFlags::from_bits_truncate(packet.d),
),
KSMSG_MUNMAP => self.munmap(
packet.b,
u64::from(packet.uid) | (u64::from(packet.gid) << 32),
packet.c,
MunmapFlags::from_bits_truncate(packet.d),
),
_ => Err(Error::new(ENOSYS)),
};
packet.a = Error::mux(res);
}
/* Scheme operations */
#[allow(unused_variables)]
fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> Result<usize> {
Err(Error::new(ENOENT))
}
#[allow(unused_variables)]
fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
convert_to_this_scheme(self.open(path, flags, ctx.uid, ctx.gid))
}
#[allow(unused_variables)]
fn chmod(&mut self, path: &str, mode: u16, uid: u32, gid: u32) -> Result<usize> {
Err(Error::new(ENOENT))
}
#[allow(unused_variables)]
fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> Result<usize> {
Err(Error::new(ENOENT))
}
#[allow(unused_variables)]
fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> Result<usize> {
Err(Error::new(ENOENT))
}
/* Resource operations */
#[allow(unused_variables)]
fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn xdup(&mut self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<OpenResult> {
convert_to_this_scheme(self.dup(old_id, buf))
}
#[allow(unused_variables)]
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn write(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result<isize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fchmod(&mut self, id: usize, mode: u16) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fevent(&mut self, id: usize, flags: EventFlags) -> Result<EventFlags> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn frename(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn fsync(&mut self, id: usize) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn ftruncate(&mut self, id: usize, len: usize) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn futimens(&mut self, id: usize, times: &[TimeSpec]) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn close(&mut self, id: usize) -> Result<usize> {
Err(Error::new(EBADF))
}
#[allow(unused_variables)]
fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
#[allow(unused_variables)]
fn munmap(&mut self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
}
use core::cmp;
use core::convert::TryFrom;
use syscall::error::*;
use syscall::flag::*;
/// Helper for seek calls
/// In most cases it's easier to use a usize to track the offset and buffer size internally,
/// but the seek interface uses isize. This wrapper ensures EOVERFLOW errors are returned
/// as appropriate if the value in the usize can't fit in the isize.
pub fn calc_seek_offset_usize(
cur_offset: usize,
pos: isize,
whence: usize,
buf_len: usize,
) -> Result<isize> {
let cur_offset = isize::try_from(cur_offset).or_else(|_| Err(Error::new(EOVERFLOW)))?;
let buf_len = isize::try_from(buf_len).or_else(|_| Err(Error::new(EOVERFLOW)))?;
calc_seek_offset_isize(cur_offset, pos, whence, buf_len)
}
/// Helper for seek calls
/// Result is guaranteed to be positive.
/// EOVERFLOW returned if the arguments would cause an overflow.
/// EINVAL returned if the new offset is out of bounds.
pub fn calc_seek_offset_isize(
cur_offset: isize,
pos: isize,
whence: usize,
buf_len: isize,
) -> Result<isize> {
let new_offset = match whence {
SEEK_CUR => pos.checked_add(cur_offset),
SEEK_END => pos.checked_add(buf_len),
SEEK_SET => Some(pos),
_ => None,
};
match new_offset {
Some(new_offset) if new_offset < 0 => Err(Error::new(EINVAL)),
Some(new_offset) => Ok(cmp::min(new_offset, buf_len)),
None => Err(Error::new(EOVERFLOW)),
}
}