#![allow(async_fn_in_trait)]
use core::fmt::{self, Debug};
use core::mem::size_of;
use core::ops::{Deref, DerefMut};
use syscall::dirent::DirentBuf;
use syscall::schemev2::{Opcode, Sqe};
use syscall::{error::*, flag::*, Stat, StatVfs, TimeSpec};
use crate::{
CallRequest, CallerCtx, Id, OpenResult, RecvFdRequest, Request, Response, SendFdRequest,
Socket, Tag,
};
pub struct OpPathLike<Flags> {
req: Tag,
path: *const str, pub flags: Flags,
}
impl<F> OpPathLike<F> {
pub fn path(&self) -> &str {
unsafe { &*self.path }
}
}
impl<Flags: Debug> Debug for OpPathLike<Flags> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OpPathLike")
.field("path", &self.path())
.field("flags", &self.flags)
.finish()
}
}
pub struct OpFdPathLike<Flags> {
pub fd: usize,
pub fcntl_flags: u32,
inner: OpPathLike<Flags>,
}
impl<F> OpFdPathLike<F> {
pub fn path(&self) -> &str {
self.inner.path()
}
pub fn flags(&self) -> &F {
&self.inner.flags
}
}
impl<Flags: Debug> Debug for OpFdPathLike<Flags> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OpFdPathLike")
.field("fd", &self.fd)
.field("path", &self.path())
.field("flags", &self.inner.flags)
.field("fcntl_flags", &self.fcntl_flags)
.finish()
}
}
pub struct OpCall {
req: Tag,
pub fd: usize,
payload: *mut [u8], metadata: [u64; 3],
}
impl OpCall {
pub fn payload_and_metadata(&mut self) -> (&mut [u8], &[u64]) {
unsafe { (&mut *self.payload, &self.metadata) }
}
pub fn payload(&mut self) -> &mut [u8] {
self.payload_and_metadata().0
}
pub fn metadata(&self) -> &[u64] {
&self.metadata
}
}
impl Debug for OpCall {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OpCall")
.field("fd", &self.fd)
.field("payload", &self.payload)
.field("metadata", &self.metadata())
.finish()
}
}
#[derive(Debug)]
pub struct OpQueryRead<T: ?Sized> {
pub fd: usize,
req: Tag,
buf: *mut T,
}
impl<T: ?Sized> OpQueryRead<T> {
pub fn buf(&mut self) -> &mut T {
unsafe { &mut *self.buf }
}
}
#[derive(Debug)]
pub struct OpQueryWrite<T: ?Sized> {
pub fd: usize,
req: Tag,
buf: *const T,
}
impl<T: ?Sized> OpQueryWrite<T> {
pub fn buf(&self) -> &T {
unsafe { &*self.buf }
}
}
#[derive(Debug)]
pub struct OpGetdents {
req: Tag,
pub fd: usize,
buf: *mut [u8],
pub header_size: u16,
pub opaque_offset: u64,
}
impl OpGetdents {
pub fn raw_buf(&mut self) -> &mut [u8] {
unsafe { &mut *self.buf }
}
pub fn buf(&mut self) -> Option<DirentBuf<&mut [u8]>> {
let sz = self.header_size;
DirentBuf::new(self.raw_buf(), sz)
}
}
#[derive(Debug)]
pub struct OpRead {
req: Tag,
pub fd: usize,
pub offset: u64,
pub flags: u32,
buf: *mut [u8],
}
impl OpRead {
pub fn buf(&mut self) -> &mut [u8] {
unsafe { &mut *self.buf }
}
}
#[derive(Debug)]
pub struct OpWrite {
req: Tag,
pub fd: usize,
pub offset: u64,
pub flags: u32,
buf: *const [u8],
}
impl OpWrite {
pub fn buf(&self) -> &[u8] {
unsafe { &*self.buf }
}
}
#[non_exhaustive]
#[derive(Debug)]
pub enum Op {
OpenAt(OpFdPathLike<usize>),
UnlinkAt(OpFdPathLike<usize>),
Dup(OpQueryWrite<[u8]>),
Read(OpRead),
Write(OpWrite),
Fsize {
req: Tag,
fd: usize,
},
Fchmod {
req: Tag,
fd: usize,
new_mode: u16,
},
Fchown {
req: Tag,
fd: usize,
new_uid: u32,
new_gid: u32,
},
Fcntl {
req: Tag,
fd: usize,
cmd: usize,
arg: usize,
},
Fevent {
req: Tag,
fd: usize,
req_flags: EventFlags,
},
Flink(OpQueryWrite<str>),
Fpath(OpQueryRead<[u8]>),
Frename(OpQueryWrite<str>),
Fstat(OpQueryRead<Stat>),
FstatVfs(OpQueryRead<StatVfs>),
Fsync {
req: Tag,
fd: usize,
},
Ftruncate {
req: Tag,
fd: usize,
new_sz: u64,
},
Futimens(OpQueryWrite<[TimeSpec]>),
MmapPrep {
req: Tag,
fd: usize,
offset: u64,
len: usize,
flags: MapFlags,
},
Munmap {
req: Tag,
fd: usize,
offset: u64,
len: usize,
flags: MunmapFlags,
},
Call(OpCall),
Getdents(OpGetdents),
Recvfd(RecvFdRequest),
}
impl Op {
pub unsafe fn from_sqe_unchecked(sqe: &Sqe) -> Option<Op> {
let req = Tag(Id(sqe.tag));
let opcode = Opcode::try_from_raw(sqe.opcode)?;
let args = sqe.args;
let [a, b, c, d, e, _f] = args.map(|a| a as usize);
use core::{slice, str};
Some(match opcode {
Opcode::OpenAt => Op::OpenAt(OpFdPathLike {
fd: a,
fcntl_flags: e as u32,
inner: OpPathLike {
req,
path: str::from_utf8_unchecked(slice::from_raw_parts(b as *const u8, c)),
flags: d,
},
}),
Opcode::UnlinkAt => Op::UnlinkAt(OpFdPathLike {
fd: a,
fcntl_flags: 0,
inner: OpPathLike {
req,
path: str::from_utf8_unchecked(slice::from_raw_parts(b as *const u8, c)),
flags: d,
},
}),
Opcode::Dup => Op::Dup(OpQueryWrite {
req,
fd: a,
buf: slice::from_raw_parts(b as *const u8, c),
}),
Opcode::Read => Op::Read(OpRead {
req,
fd: a,
buf: slice::from_raw_parts_mut(b as *mut u8, c),
offset: args[3],
flags: args[4] as u32,
}),
Opcode::Write => Op::Write(OpWrite {
req,
fd: a,
buf: slice::from_raw_parts(b as *const u8, c),
offset: args[3],
flags: args[4] as u32,
}),
Opcode::Fsize => Op::Fsize { req, fd: a },
Opcode::Fchmod => Op::Fchmod {
req,
fd: a,
new_mode: b as u16,
},
Opcode::Fchown => Op::Fchown {
req,
fd: a,
new_uid: b as u32,
new_gid: c as u32,
},
Opcode::Fcntl => Op::Fcntl {
req,
fd: a,
cmd: b,
arg: c,
},
Opcode::Fevent => Op::Fevent {
req,
fd: a,
req_flags: EventFlags::from_bits_retain(b),
},
Opcode::Flink => Op::Flink(OpQueryWrite {
req,
fd: a,
buf: str::from_utf8_unchecked(slice::from_raw_parts(b as *const u8, c)),
}),
Opcode::Fpath => Op::Fpath(OpQueryRead {
req,
fd: a,
buf: slice::from_raw_parts_mut(b as *mut u8, c),
}),
Opcode::Frename => Op::Frename(OpQueryWrite {
req,
fd: a,
buf: str::from_utf8_unchecked(slice::from_raw_parts(b as *const u8, c)),
}),
Opcode::Fstat => {
assert!(c >= size_of::<Stat>());
Op::Fstat(OpQueryRead {
req,
fd: a,
buf: &mut *(b as *mut Stat),
})
}
Opcode::Fstatvfs => {
assert!(c >= size_of::<StatVfs>());
Op::FstatVfs(OpQueryRead {
req,
fd: a,
buf: &mut *(b as *mut StatVfs),
})
}
Opcode::Fsync => Op::Fsync { req, fd: a },
Opcode::Ftruncate => Op::Ftruncate {
req,
fd: a,
new_sz: args[1],
},
Opcode::Futimens => {
assert!(c <= 2 * size_of::<TimeSpec>());
Op::Futimens(OpQueryWrite {
req,
fd: a,
buf: slice::from_raw_parts(b as *const TimeSpec, c / size_of::<TimeSpec>()),
})
}
Opcode::Call => Op::Call(OpCall {
req,
fd: a,
payload: slice::from_raw_parts_mut(b as *mut u8, c),
metadata: [sqe.args[3], sqe.args[4], sqe.args[5]],
}),
Opcode::Getdents => Op::Getdents(OpGetdents {
req,
fd: a,
buf: slice::from_raw_parts_mut(b as *mut u8, c),
header_size: sqe.args[3] as u16,
opaque_offset: sqe.args[4],
}),
Opcode::MmapPrep => Op::MmapPrep {
req,
fd: a,
offset: args[3],
len: b,
flags: MapFlags::from_bits_retain(c),
},
Opcode::Munmap => Op::Munmap {
req,
fd: a,
offset: args[3],
len: b,
flags: MunmapFlags::from_bits_retain(c),
},
_ => return None,
})
}
pub fn is_explicitly_nonblock(&self) -> bool {
let flags = match self {
Self::Read(r) => r.flags,
Self::Write(w) => w.flags,
Self::OpenAt(o) => o.fcntl_flags,
_ => 0,
};
flags as usize & O_NONBLOCK != 0
}
pub fn file_id(&self) -> Option<usize> {
Some(match self {
Op::UnlinkAt(op) => op.fd,
Op::OpenAt(op) => op.fd,
Op::Dup(op) => op.fd,
Op::Read(op) => op.fd,
Op::Write(op) => op.fd,
Op::Fsize { fd, .. }
| Op::Fchmod { fd, .. }
| Op::Fchown { fd, .. }
| Op::Fcntl { fd, .. }
| Op::Fevent { fd, .. }
| Op::Fsync { fd, .. }
| Op::Ftruncate { fd, .. }
| Op::MmapPrep { fd, .. }
| Op::Munmap { fd, .. } => *fd,
Op::Flink(op) => op.fd,
Op::Fpath(op) => op.fd,
Op::Frename(op) => op.fd,
Op::Fstat(op) => op.fd,
Op::FstatVfs(op) => op.fd,
Op::Futimens(op) => op.fd,
Op::Call(op) => op.fd,
Op::Getdents(op) => op.fd,
Op::Recvfd(req) => req.id(),
})
}
}
impl CallRequest {
pub fn caller(&self) -> CallerCtx {
let sqe = &self.inner.sqe;
CallerCtx {
pid: sqe.caller as usize,
uid: sqe.args[5] as u32,
gid: (sqe.args[5] >> 32) as u32,
id: Id(sqe.tag),
}
}
pub fn op(self) -> Result<Op, Self> {
match unsafe { Op::from_sqe_unchecked(&self.inner.sqe) } {
Some(op) => Ok(op),
None => Err(self),
}
}
pub async fn handle_async(self, s: &mut impl SchemeAsync) -> Response {
let caller = self.caller();
let op = match self.op() {
Ok(op) => op,
Err(this) => return Response::new(Err(Error::new(ENOSYS)), this),
};
op.handle_async(caller, s).await
}
pub fn handle_sync(self, s: &mut impl SchemeSync) -> Response {
let caller = self.caller();
let op = match self.op() {
Ok(op) => op,
Err(this) => return Response::new(Err(Error::new(ENOSYS)), this),
};
op.handle_sync(caller, s)
}
}
impl SendFdRequest {
pub fn caller(&self) -> CallerCtx {
let sqe = &self.inner.sqe;
CallerCtx {
pid: sqe.caller as usize,
uid: sqe.args[5] as u32,
gid: (sqe.args[5] >> 32) as u32,
id: self.request_id(),
}
}
}
impl RecvFdRequest {
pub fn op(self) -> Op {
Op::Recvfd(self)
}
pub fn caller(&self) -> CallerCtx {
let sqe = &self.inner.sqe;
CallerCtx {
pid: sqe.caller as usize,
uid: sqe.args[5] as u32,
gid: (sqe.args[5] >> 32) as u32,
id: self.request_id(),
}
}
}
pub enum SchemeResponse {
Regular(Result<usize>),
Opened(Result<OpenResult>),
}
impl From<Result<usize>> for SchemeResponse {
fn from(value: Result<usize>) -> Self {
Self::Regular(value)
}
}
impl Op {
pub fn handle_sync(mut self, caller: CallerCtx, s: &mut impl SchemeSync) -> Response {
match self.handle_sync_dont_consume(&caller, s) {
SchemeResponse::Opened(open) => Response::open_dup_like(open, self),
SchemeResponse::Regular(reg) => Response::new(reg, self),
}
}
pub fn handle_sync_dont_consume(
&mut self,
caller: &CallerCtx,
s: &mut impl SchemeSync,
) -> SchemeResponse {
match *self {
Op::OpenAt(ref req) => {
let res = s.openat(
req.fd,
req.path(),
req.inner.flags,
req.fcntl_flags,
&caller,
);
return SchemeResponse::Opened(res);
}
Op::UnlinkAt(ref req) => s
.unlinkat(req.fd, req.path(), req.inner.flags, &caller)
.map(|()| 0)
.into(),
Op::Dup(ref req) => {
let res = s.dup(req.fd, req.buf(), &caller);
return SchemeResponse::Opened(res);
}
Op::Read(ref mut req) => {
let OpRead {
fd, offset, flags, ..
} = *req;
s.read(fd, req.buf(), offset, flags, &caller).into()
}
Op::Write(ref req) => s
.write(req.fd, req.buf(), req.offset, req.flags, &caller)
.into(),
Op::Fsize { fd, .. } => s.fsize(fd, &caller).map(|l| l as usize).into(),
Op::Fchmod { fd, new_mode, .. } => s.fchmod(fd, new_mode, &caller).map(|()| 0).into(),
Op::Fchown {
fd,
new_uid,
new_gid,
..
} => s.fchown(fd, new_uid, new_gid, &caller).map(|()| 0).into(),
Op::Fcntl { fd, cmd, arg, .. } => s.fcntl(fd, cmd, arg, &caller).into(),
Op::Fevent { fd, req_flags, .. } => {
s.fevent(fd, req_flags, &caller).map(|f| f.bits()).into()
}
Op::Flink(ref req) => s.flink(req.fd, req.buf(), &caller).into(),
Op::Fpath(ref mut req) => s.fpath(req.fd, req.buf(), &caller).into(),
Op::Frename(ref req) => s.frename(req.fd, req.buf(), &caller).into(),
Op::Fstat(ref mut req) => s.fstat(req.fd, req.buf(), &caller).map(|()| 0).into(),
Op::FstatVfs(ref mut req) => s.fstatvfs(req.fd, req.buf(), &caller).map(|()| 0).into(),
Op::Fsync { fd, .. } => s.fsync(fd, &caller).map(|()| 0).into(),
Op::Ftruncate { fd, new_sz, .. } => s.ftruncate(fd, new_sz, &caller).map(|()| 0).into(),
Op::Futimens(ref req) => s.futimens(req.fd, req.buf(), &caller).map(|()| 0).into(),
Op::MmapPrep {
fd,
offset,
len,
flags,
..
} => s.mmap_prep(fd, offset, len, flags, &caller).into(),
Op::Munmap {
fd,
offset,
len,
flags,
..
} => s.munmap(fd, offset, len, flags, &caller).map(|()| 0).into(),
Op::Call(ref mut req) => {
let fd = req.fd;
let (payload, metadata) = req.payload_and_metadata();
s.call(fd, payload, metadata, &caller).into()
}
Op::Getdents(ref mut req) => {
let OpGetdents {
fd, opaque_offset, ..
} = *req;
let Some(buf) = req.buf() else {
return Err(Error::new(EINVAL)).into();
};
let buf_res = s.getdents(fd, buf, opaque_offset);
buf_res.map(|b| b.finalize()).into()
}
Op::Recvfd(ref req) => {
let res = s.on_recvfd(req);
return SchemeResponse::Opened(res);
}
}
}
pub async fn handle_async(self, caller: CallerCtx, s: &mut impl SchemeAsync) -> Response {
let (res, tag) = match self {
Op::OpenAt(req) => {
let res = s
.openat(
req.fd,
req.path(),
req.inner.flags,
req.fcntl_flags,
&caller,
)
.await;
return Response::open_dup_like(res, req);
}
Op::UnlinkAt(req) => (
s.unlinkat(req.fd, req.path(), req.inner.flags, &caller)
.await
.map(|()| 0)
.into(),
req.into_tag(),
),
Op::Dup(req) => {
let res = s.dup(req.fd, req.buf(), &caller).await;
return Response::open_dup_like(res, req);
}
Op::Read(mut req) => {
let OpRead {
fd, offset, flags, ..
} = req;
(
s.read(fd, req.buf(), offset, flags, &caller).await,
req.into_tag(),
)
}
Op::Write(req) => (
s.write(req.fd, req.buf(), req.offset, req.flags, &caller)
.await,
req.into_tag(),
),
Op::Fsize { req, fd } => (s.fsize(fd, &caller).await.map(|l| l as usize), req),
Op::Fchmod { req, fd, new_mode } => {
(s.fchmod(fd, new_mode, &caller).await.map(|()| 0), req)
}
Op::Fchown {
req,
fd,
new_uid,
new_gid,
} => (
s.fchown(fd, new_uid, new_gid, &caller).await.map(|()| 0),
req,
),
Op::Fcntl { req, fd, cmd, arg } => (s.fcntl(fd, cmd, arg, &caller).await, req),
Op::Fevent { req, fd, req_flags } => (
s.fevent(fd, req_flags, &caller).await.map(|f| f.bits()),
req,
),
Op::Flink(req) => (s.flink(req.fd, req.buf(), &caller).await, req.into_tag()),
Op::Fpath(mut req) => (s.fpath(req.fd, req.buf(), &caller).await, req.into_tag()),
Op::Frename(req) => (s.frename(req.fd, req.buf(), &caller).await, req.into_tag()),
Op::Fstat(mut req) => (
s.fstat(req.fd, req.buf(), &caller).await.map(|()| 0),
req.into_tag(),
),
Op::FstatVfs(mut req) => (
s.fstatvfs(req.fd, req.buf(), &caller).await.map(|()| 0),
req.into_tag(),
),
Op::Fsync { req, fd } => (s.fsync(fd, &caller).await.map(|()| 0), req),
Op::Ftruncate { req, fd, new_sz } => {
(s.ftruncate(fd, new_sz, &caller).await.map(|()| 0), req)
}
Op::Futimens(req) => (
s.futimens(req.fd, req.buf(), &caller).await.map(|()| 0),
req.into_tag(),
),
Op::MmapPrep {
req,
fd,
offset,
len,
flags,
} => (s.mmap_prep(fd, offset, len, flags, &caller).await, req),
Op::Munmap {
req,
fd,
offset,
len,
flags,
} => (
s.munmap(fd, offset, len, flags, &caller).await.map(|()| 0),
req,
),
Op::Call(mut req) => {
let fd = req.fd;
let (payload, metadata) = req.payload_and_metadata();
(s.call(fd, payload, metadata, &caller).await, req.into_tag())
}
Op::Getdents(mut req) => {
let OpGetdents {
fd, opaque_offset, ..
} = req;
let Some(buf) = req.buf() else {
return Response::err(EINVAL, req);
};
let buf_res = s.getdents(fd, buf, opaque_offset).await;
(buf_res.map(|b| b.finalize()), req.into_tag())
}
Op::Recvfd(req) => {
let res = s.on_recvfd(&req).await;
return Response::open_dup_like(res, req);
}
};
Response::new(res, tag)
}
}
#[allow(unused_variables)]
pub trait SchemeAsync {
fn scheme_root(&mut self) -> Result<usize> {
Err(Error::new(ENOSYS))
}
async fn openat(
&mut self,
fd: usize,
path: &str,
flags: usize,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
Err(Error::new(EOPNOTSUPP))
}
async fn unlinkat(
&mut self,
fd: usize,
path: &str,
flags: usize,
ctx: &CallerCtx,
) -> Result<()> {
Err(Error::new(ENOENT))
}
async fn dup(&mut self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<OpenResult> {
Err(Error::new(EOPNOTSUPP))
}
async fn read(
&mut self,
id: usize,
buf: &mut [u8],
offset: u64,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<usize> {
Err(Error::new(EBADF))
}
async fn write(
&mut self,
id: usize,
buf: &[u8],
offset: u64,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<usize> {
Err(Error::new(EBADF))
}
async fn fsize(&mut self, id: usize, ctx: &CallerCtx) -> Result<u64> {
Err(Error::new(ESPIPE))
}
async fn fchmod(&mut self, id: usize, new_mode: u16, ctx: &CallerCtx) -> Result<()> {
Err(Error::new(EOPNOTSUPP))
}
async fn fchown(
&mut self,
id: usize,
new_uid: u32,
new_gid: u32,
ctx: &CallerCtx,
) -> Result<()> {
Err(Error::new(EOPNOTSUPP))
}
async fn fcntl(&mut self, id: usize, cmd: usize, arg: usize, ctx: &CallerCtx) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
async fn fevent(
&mut self,
id: usize,
flags: EventFlags,
ctx: &CallerCtx,
) -> Result<EventFlags> {
Ok(EventFlags::empty())
}
async fn flink(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
async fn fpath(&mut self, id: usize, buf: &mut [u8], ctx: &CallerCtx) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
async fn frename(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
async fn fstat(&mut self, id: usize, stat: &mut Stat, ctx: &CallerCtx) -> Result<()> {
Err(Error::new(EOPNOTSUPP))
}
async fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs, ctx: &CallerCtx) -> Result<()> {
Err(Error::new(EOPNOTSUPP))
}
async fn fsync(&mut self, id: usize, ctx: &CallerCtx) -> Result<()> {
Ok(())
}
async fn ftruncate(&mut self, id: usize, len: u64, ctx: &CallerCtx) -> Result<()> {
Err(Error::new(EBADF))
}
async fn futimens(&mut self, id: usize, times: &[TimeSpec], ctx: &CallerCtx) -> Result<()> {
Err(Error::new(EBADF))
}
async fn call(
&mut self,
id: usize,
payload: &mut [u8],
metadata: &[u64],
ctx: &CallerCtx, ) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
async fn getdents<'buf>(
&mut self,
id: usize,
buf: DirentBuf<&'buf mut [u8]>,
opaque_offset: u64,
) -> Result<DirentBuf<&'buf mut [u8]>> {
Err(Error::new(ENOTDIR))
}
async fn mmap_prep(
&mut self,
id: usize,
offset: u64,
size: usize,
flags: MapFlags,
ctx: &CallerCtx,
) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
async fn munmap(
&mut self,
id: usize,
offset: u64,
size: usize,
flags: MunmapFlags,
ctx: &CallerCtx,
) -> Result<()> {
Err(Error::new(EOPNOTSUPP))
}
async fn on_recvfd(&mut self, recvfd_request: &RecvFdRequest) -> Result<OpenResult> {
Err(Error::new(EOPNOTSUPP))
}
}
#[allow(unused_variables)]
pub trait SchemeSync {
fn scheme_root(&mut self) -> Result<usize> {
Err(Error::new(ENOSYS))
}
fn openat(
&mut self,
fd: usize,
path: &str,
flags: usize,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
Err(Error::new(EOPNOTSUPP))
}
fn unlinkat(&mut self, fd: usize, path: &str, flags: usize, ctx: &CallerCtx) -> Result<()> {
Err(Error::new(ENOENT))
}
fn dup(&mut self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<OpenResult> {
Err(Error::new(EOPNOTSUPP))
}
fn read(
&mut self,
id: usize,
buf: &mut [u8],
offset: u64,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<usize> {
Err(Error::new(EBADF))
}
fn write(
&mut self,
id: usize,
buf: &[u8],
offset: u64,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<usize> {
Err(Error::new(EBADF))
}
fn fsize(&mut self, id: usize, ctx: &CallerCtx) -> Result<u64> {
Err(Error::new(ESPIPE))
}
fn fchmod(&mut self, id: usize, new_mode: u16, ctx: &CallerCtx) -> Result<()> {
Err(Error::new(EOPNOTSUPP))
}
fn fchown(&mut self, id: usize, new_uid: u32, new_gid: u32, ctx: &CallerCtx) -> Result<()> {
Err(Error::new(EOPNOTSUPP))
}
fn fcntl(&mut self, id: usize, cmd: usize, arg: usize, ctx: &CallerCtx) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
fn fevent(&mut self, id: usize, flags: EventFlags, ctx: &CallerCtx) -> Result<EventFlags> {
Ok(EventFlags::empty())
}
fn flink(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
fn fpath(&mut self, id: usize, buf: &mut [u8], ctx: &CallerCtx) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
fn frename(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
fn fstat(&mut self, id: usize, stat: &mut Stat, ctx: &CallerCtx) -> Result<()> {
Err(Error::new(EOPNOTSUPP))
}
fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs, ctx: &CallerCtx) -> Result<()> {
Err(Error::new(EOPNOTSUPP))
}
fn fsync(&mut self, id: usize, ctx: &CallerCtx) -> Result<()> {
Ok(())
}
fn ftruncate(&mut self, id: usize, len: u64, ctx: &CallerCtx) -> Result<()> {
Err(Error::new(EBADF))
}
fn futimens(&mut self, id: usize, times: &[TimeSpec], ctx: &CallerCtx) -> Result<()> {
Err(Error::new(EBADF))
}
fn call(
&mut self,
id: usize,
payload: &mut [u8],
metadata: &[u64],
ctx: &CallerCtx, ) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
fn getdents<'buf>(
&mut self,
id: usize,
buf: DirentBuf<&'buf mut [u8]>,
opaque_offset: u64,
) -> Result<DirentBuf<&'buf mut [u8]>> {
Err(Error::new(ENOTDIR))
}
fn mmap_prep(
&mut self,
id: usize,
offset: u64,
size: usize,
flags: MapFlags,
ctx: &CallerCtx,
) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
fn munmap(
&mut self,
id: usize,
offset: u64,
size: usize,
flags: MunmapFlags,
ctx: &CallerCtx,
) -> Result<()> {
Err(Error::new(EOPNOTSUPP))
}
fn on_close(&mut self, id: usize) {}
fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
Err(Error::new(EOPNOTSUPP))
}
fn on_recvfd(&mut self, recvfd_request: &RecvFdRequest) -> Result<OpenResult> {
Err(Error::new(EOPNOTSUPP))
}
}
pub fn register_sync_scheme<S: SchemeSync>(
socket: &Socket,
name: &str,
scheme: &mut S,
) -> Result<()> {
let cap_id = scheme.scheme_root()?;
register_scheme_inner(socket, name, cap_id)
}
pub fn register_async_scheme<S: SchemeAsync>(
socket: &Socket,
name: &str,
scheme: &mut S,
) -> Result<()> {
let cap_id = scheme.scheme_root()?;
register_scheme_inner(socket, name, cap_id)
}
pub fn register_scheme_inner(socket: &Socket, name: &str, cap_id: usize) -> Result<()> {
let cap_fd = socket.create_this_scheme_fd(0, cap_id, 0, 0)?;
let current_namespace_fd = libredox::call::getns()?;
Ok(libredox::call::register_scheme_to_ns(
current_namespace_fd,
name,
cap_fd,
)?)
}
pub trait IntoTag {
fn into_tag(self) -> Tag;
fn req_id(&self) -> Id;
}
impl IntoTag for Tag {
fn into_tag(self) -> Tag {
self
}
fn req_id(&self) -> Id {
self.0
}
}
impl IntoTag for CallRequest {
fn into_tag(self) -> Tag {
Tag(self.request_id())
}
fn req_id(&self) -> Id {
self.request_id()
}
}
impl IntoTag for SendFdRequest {
fn into_tag(self) -> Tag {
Tag(self.request_id())
}
fn req_id(&self) -> Id {
self.request_id()
}
}
impl IntoTag for RecvFdRequest {
fn into_tag(self) -> Tag {
Tag(self.request_id())
}
fn req_id(&self) -> Id {
self.request_id()
}
}
macro_rules! trivial_into {
[$($name:ident,)*] => {
$(
impl IntoTag for $name {
#[inline]
fn into_tag(self) -> Tag {
self.req
}
#[inline]
fn req_id(&self) -> Id {
self.req.req_id()
}
}
)*
}
}
trivial_into![OpCall, OpRead, OpWrite, OpGetdents,];
impl<T: ?Sized> IntoTag for OpQueryWrite<T> {
fn into_tag(self) -> Tag {
self.req
}
fn req_id(&self) -> Id {
self.req.0
}
}
impl<T: ?Sized> IntoTag for OpQueryRead<T> {
fn into_tag(self) -> Tag {
self.req
}
fn req_id(&self) -> Id {
self.req.0
}
}
impl<F> IntoTag for OpPathLike<F> {
fn into_tag(self) -> Tag {
self.req
}
fn req_id(&self) -> Id {
self.req.0
}
}
impl<F> IntoTag for OpFdPathLike<F> {
fn into_tag(self) -> Tag {
self.inner.req
}
fn req_id(&self) -> Id {
self.inner.req.0
}
}
impl IntoTag for Op {
fn into_tag(self) -> Tag {
use Op::*;
match self {
OpenAt(op) => op.into_tag(),
UnlinkAt(op) => op.into_tag(),
Dup(op) => op.into_tag(),
Read(op) => op.into_tag(),
Write(op) => op.into_tag(),
Fsize { req, .. }
| Fchmod { req, .. }
| Fchown { req, .. }
| Fcntl { req, .. }
| Fevent { req, .. }
| Fsync { req, .. }
| Ftruncate { req, .. }
| MmapPrep { req, .. }
| Munmap { req, .. } => req,
Flink(op) => op.into_tag(),
Fpath(op) => op.into_tag(),
Frename(op) => op.into_tag(),
Fstat(op) => op.into_tag(),
FstatVfs(op) => op.into_tag(),
Futimens(op) => op.into_tag(),
Call(op) => op.into_tag(),
Getdents(op) => op.into_tag(),
Recvfd(req) => req.into_tag(),
}
}
fn req_id(&self) -> Id {
use Op::*;
match self {
OpenAt(op) => op.req_id(),
UnlinkAt(op) => op.req_id(),
Dup(op) => op.req_id(),
Read(op) => op.req_id(),
Write(op) => op.req_id(),
Fsize { req, .. }
| Fchmod { req, .. }
| Fchown { req, .. }
| Fcntl { req, .. }
| Fevent { req, .. }
| Fsync { req, .. }
| Ftruncate { req, .. }
| MmapPrep { req, .. }
| Munmap { req, .. } => req.req_id(),
Flink(op) => op.req_id(),
Fpath(op) => op.req_id(),
Frename(op) => op.req_id(),
Fstat(op) => op.req_id(),
FstatVfs(op) => op.req_id(),
Futimens(op) => op.req_id(),
Call(op) => op.req_id(),
Getdents(op) => op.req_id(),
Recvfd(req) => req.req_id(),
}
}
}