redox_scheme/
scheme.rs

1#![allow(async_fn_in_trait)]
2
3use core::fmt::{self, Debug};
4use core::mem::size_of;
5use syscall::dirent::DirentBuf;
6use syscall::schemev2::{Opcode, Sqe};
7use syscall::{error::*, flag::*, Stat, StatVfs, TimeSpec};
8
9use crate::{
10    CallRequest, CallerCtx, Id, OpenResult, RecvFdRequest, Request, Response, SendFdRequest, Tag,
11};
12
13pub struct OpPathLike<Flags> {
14    req: Tag,
15    path: *const str, // &req
16    pub flags: Flags,
17}
18impl<F> OpPathLike<F> {
19    pub fn path(&self) -> &str {
20        // SAFETY: borrowed from self.req
21        unsafe { &*self.path }
22    }
23}
24impl<Flags: Debug> Debug for OpPathLike<Flags> {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        f.debug_struct("OpPathLike")
27            .field("path", &self.path())
28            .field("flags", &self.flags)
29            .finish()
30    }
31}
32
33pub struct OpFdPathLike<Flags> {
34    pub fd: usize,
35    pub fcntl_flags: u32,
36    inner: OpPathLike<Flags>,
37}
38
39impl<F> OpFdPathLike<F> {
40    pub fn path(&self) -> &str {
41        self.inner.path()
42    }
43    pub fn flags(&self) -> &F {
44        &self.inner.flags
45    }
46}
47
48impl<Flags: Debug> Debug for OpFdPathLike<Flags> {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        f.debug_struct("OpFdPathLike")
51            .field("fd", &self.fd)
52            .field("path", &self.path())
53            .field("flags", &self.inner.flags)
54            .field("fcntl_flags", &self.fcntl_flags)
55            .finish()
56    }
57}
58
59pub struct OpCall {
60    req: Tag,
61    pub fd: usize,
62    payload: *mut [u8], // &req
63    metadata: [u64; 3],
64}
65impl OpCall {
66    pub fn payload_and_metadata(&mut self) -> (&mut [u8], &[u64]) {
67        // SAFETY: borrows &self.req
68        unsafe { (&mut *self.payload, &self.metadata) }
69    }
70    pub fn payload(&mut self) -> &mut [u8] {
71        self.payload_and_metadata().0
72    }
73    pub fn metadata(&self) -> &[u64] {
74        &self.metadata
75    }
76}
77impl Debug for OpCall {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        f.debug_struct("OpCall")
80            .field("fd", &self.fd)
81            // TODO: debug first and last few bytes, collapse middle to ...
82            .field("payload", &self.payload)
83            .field("metadata", &self.metadata())
84            .finish()
85    }
86}
87#[derive(Debug)]
88pub struct OpQueryRead<T: ?Sized> {
89    pub fd: usize,
90    req: Tag,
91    buf: *mut T,
92}
93impl<T: ?Sized> OpQueryRead<T> {
94    pub fn buf(&mut self) -> &mut T {
95        // SAFETY: borrows &mut self.req
96        unsafe { &mut *self.buf }
97    }
98}
99#[derive(Debug)]
100pub struct OpQueryWrite<T: ?Sized> {
101    pub fd: usize,
102    req: Tag,
103    buf: *const T,
104}
105impl<T: ?Sized> OpQueryWrite<T> {
106    pub fn buf(&self) -> &T {
107        // SAFETY: borrows &self.req
108        unsafe { &*self.buf }
109    }
110}
111#[derive(Debug)]
112pub struct OpGetdents {
113    req: Tag,
114    pub fd: usize,
115    buf: *mut [u8],
116    pub header_size: u16,
117    pub opaque_offset: u64,
118}
119impl OpGetdents {
120    pub fn raw_buf(&mut self) -> &mut [u8] {
121        // SAFETY: borrows
122        unsafe { &mut *self.buf }
123    }
124    pub fn buf(&mut self) -> Option<DirentBuf<&mut [u8]>> {
125        let sz = self.header_size;
126        DirentBuf::new(self.raw_buf(), sz)
127    }
128}
129#[derive(Debug)]
130pub struct OpRead {
131    req: Tag,
132    pub fd: usize,
133    pub offset: u64,
134    pub flags: u32,
135    buf: *mut [u8],
136}
137impl OpRead {
138    pub fn buf(&mut self) -> &mut [u8] {
139        // SAFETY: Borrows &mut self.req
140        unsafe { &mut *self.buf }
141    }
142}
143#[derive(Debug)]
144pub struct OpWrite {
145    req: Tag,
146    pub fd: usize,
147    pub offset: u64,
148    pub flags: u32,
149    buf: *const [u8],
150}
151impl OpWrite {
152    pub fn buf(&self) -> &[u8] {
153        // SAFETY: Borrows &self.req
154        unsafe { &*self.buf }
155    }
156}
157
158#[non_exhaustive]
159#[derive(Debug)]
160pub enum Op {
161    Open(OpPathLike<usize>),
162    OpenAt(OpFdPathLike<usize>),
163    Rmdir(OpPathLike<()>),
164    Unlink(OpPathLike<()>),
165    UnlinkAt(OpFdPathLike<usize>),
166    Dup(OpQueryWrite<[u8]>),
167    Read(OpRead),
168    Write(OpWrite),
169    Fsize {
170        req: Tag,
171        fd: usize,
172    },
173    Fchmod {
174        req: Tag,
175        fd: usize,
176        new_mode: u16,
177    },
178    Fchown {
179        req: Tag,
180        fd: usize,
181        new_uid: u32,
182        new_gid: u32,
183    },
184    Fcntl {
185        req: Tag,
186        fd: usize,
187        cmd: usize,
188        arg: usize,
189    },
190    Fevent {
191        req: Tag,
192        fd: usize,
193        req_flags: EventFlags,
194    },
195    Flink(OpQueryWrite<str>),
196    Fpath(OpQueryRead<[u8]>),
197    Frename(OpQueryWrite<str>),
198    Fstat(OpQueryRead<Stat>),
199    FstatVfs(OpQueryRead<StatVfs>),
200    Fsync {
201        req: Tag,
202        fd: usize,
203    },
204    Ftruncate {
205        req: Tag,
206        fd: usize,
207        new_sz: u64,
208    },
209    Futimens(OpQueryWrite<[TimeSpec]>),
210
211    MmapPrep {
212        req: Tag,
213        fd: usize,
214        offset: u64,
215        len: usize,
216        flags: MapFlags,
217    },
218    Munmap {
219        req: Tag,
220        fd: usize,
221        offset: u64,
222        len: usize,
223        flags: MunmapFlags,
224    },
225
226    Call(OpCall),
227
228    Getdents(OpGetdents),
229
230    Recvfd(RecvFdRequest),
231}
232
233impl Op {
234    /// Decode the raw SQE into an Op with borrowed buffers passed as slices.
235    ///
236    /// # Safety
237    ///
238    /// Any borrowed buffers will be unmapped whenever a response is sent, which unlike the
239    /// move-based CallRequest API, needs to be managed manually by the caller.
240    pub unsafe fn from_sqe_unchecked(sqe: &Sqe) -> Option<Op> {
241        let req = Tag(Id(sqe.tag));
242        let opcode = Opcode::try_from_raw(sqe.opcode)?;
243        let args = sqe.args;
244
245        let [a, b, c, d, e, _f] = args.map(|a| a as usize);
246        use core::{slice, str};
247
248        Some(match opcode {
249            Opcode::Open => Op::Open(OpPathLike {
250                req,
251                path: str::from_utf8_unchecked(slice::from_raw_parts(a as *const u8, b)),
252                flags: c,
253            }),
254            Opcode::OpenAt => Op::OpenAt(OpFdPathLike {
255                fd: a,
256                fcntl_flags: e as u32,
257                inner: OpPathLike {
258                    req,
259                    path: str::from_utf8_unchecked(slice::from_raw_parts(b as *const u8, c)),
260                    flags: d,
261                },
262            }),
263            Opcode::Rmdir => Op::Rmdir(OpPathLike {
264                req,
265                path: str::from_utf8_unchecked(slice::from_raw_parts(a as *const u8, b)),
266                flags: (),
267            }),
268            Opcode::Unlink => Op::Unlink(OpPathLike {
269                req,
270                path: str::from_utf8_unchecked(slice::from_raw_parts(a as *const u8, b)),
271                flags: (),
272            }),
273            Opcode::UnlinkAt => Op::UnlinkAt(OpFdPathLike {
274                fd: a,
275                fcntl_flags: 0,
276                inner: OpPathLike {
277                    req,
278                    path: str::from_utf8_unchecked(slice::from_raw_parts(b as *const u8, c)),
279                    flags: d,
280                },
281            }),
282            Opcode::Dup => Op::Dup(OpQueryWrite {
283                req,
284                fd: a,
285                buf: slice::from_raw_parts(b as *const u8, c),
286            }),
287            Opcode::Read => Op::Read(OpRead {
288                req,
289                fd: a,
290                buf: slice::from_raw_parts_mut(b as *mut u8, c),
291                offset: args[3],
292                flags: args[4] as u32,
293            }),
294            Opcode::Write => Op::Write(OpWrite {
295                req,
296                fd: a,
297                buf: slice::from_raw_parts(b as *const u8, c),
298                offset: args[3],
299                flags: args[4] as u32,
300            }),
301
302            // TODO: 64-bit offset on 32-bit platforms
303            Opcode::Fsize => Op::Fsize { req, fd: a },
304            Opcode::Fchmod => Op::Fchmod {
305                req,
306                fd: a,
307                new_mode: b as u16,
308            },
309            Opcode::Fchown => Op::Fchown {
310                req,
311                fd: a,
312                new_uid: b as u32,
313                new_gid: c as u32,
314            },
315            Opcode::Fcntl => Op::Fcntl {
316                req,
317                fd: a,
318                cmd: b,
319                arg: c,
320            },
321            Opcode::Fevent => Op::Fevent {
322                req,
323                fd: a,
324                req_flags: EventFlags::from_bits_retain(b),
325            },
326            Opcode::Flink => Op::Flink(OpQueryWrite {
327                req,
328                fd: a,
329                buf: str::from_utf8_unchecked(slice::from_raw_parts(b as *const u8, c)),
330            }),
331            Opcode::Fpath => Op::Fpath(OpQueryRead {
332                req,
333                fd: a,
334                buf: slice::from_raw_parts_mut(b as *mut u8, c),
335            }),
336            Opcode::Frename => Op::Frename(OpQueryWrite {
337                req,
338                fd: a,
339                buf: str::from_utf8_unchecked(slice::from_raw_parts(b as *const u8, c)),
340            }),
341            Opcode::Fstat => {
342                assert!(c >= size_of::<Stat>());
343                Op::Fstat(OpQueryRead {
344                    req,
345                    fd: a,
346                    buf: &mut *(b as *mut Stat),
347                })
348            }
349            Opcode::Fstatvfs => {
350                assert!(c >= size_of::<StatVfs>());
351                Op::FstatVfs(OpQueryRead {
352                    req,
353                    fd: a,
354                    buf: &mut *(b as *mut StatVfs),
355                })
356            }
357            Opcode::Fsync => Op::Fsync { req, fd: a },
358            Opcode::Ftruncate => Op::Ftruncate {
359                req,
360                fd: a,
361                new_sz: args[1],
362            },
363            Opcode::Futimens => {
364                assert!(c <= 2 * size_of::<TimeSpec>());
365                Op::Futimens(OpQueryWrite {
366                    req,
367                    fd: a,
368                    buf: slice::from_raw_parts(b as *const TimeSpec, c / size_of::<TimeSpec>()),
369                })
370            }
371
372            Opcode::Call => Op::Call(OpCall {
373                req,
374                fd: a,
375                payload: slice::from_raw_parts_mut(b as *mut u8, c),
376                metadata: [sqe.args[3], sqe.args[4], sqe.args[5]],
377            }),
378            Opcode::Getdents => Op::Getdents(OpGetdents {
379                req,
380                fd: a,
381                buf: slice::from_raw_parts_mut(b as *mut u8, c),
382                header_size: sqe.args[3] as u16,
383                opaque_offset: sqe.args[4],
384            }),
385
386            Opcode::MmapPrep => Op::MmapPrep {
387                req,
388                fd: a,
389                offset: args[3],
390                len: b,
391                flags: MapFlags::from_bits_retain(c),
392            },
393            Opcode::Munmap => Op::Munmap {
394                req,
395                fd: a,
396                offset: args[3],
397                len: b,
398                flags: MunmapFlags::from_bits_retain(c),
399            },
400
401            _ => return None,
402        })
403    }
404    pub fn is_explicitly_nonblock(&self) -> bool {
405        let flags = match self {
406            Self::Read(r) => r.flags,
407            Self::Write(w) => w.flags,
408            Self::OpenAt(o) => o.fcntl_flags,
409            Self::Open(o) => o.flags as u32,
410            _ => 0,
411        };
412        flags as usize & O_NONBLOCK != 0
413    }
414    pub fn file_id(&self) -> Option<usize> {
415        Some(match self {
416            Op::Open(_) | Op::Rmdir(_) | Op::Unlink(_) => return None,
417            Op::UnlinkAt(op) => op.fd,
418            Op::OpenAt(op) => op.fd,
419            Op::Dup(op) => op.fd,
420            Op::Read(op) => op.fd,
421            Op::Write(op) => op.fd,
422            Op::Fsize { fd, .. }
423            | Op::Fchmod { fd, .. }
424            | Op::Fchown { fd, .. }
425            | Op::Fcntl { fd, .. }
426            | Op::Fevent { fd, .. }
427            | Op::Fsync { fd, .. }
428            | Op::Ftruncate { fd, .. }
429            | Op::MmapPrep { fd, .. }
430            | Op::Munmap { fd, .. } => *fd,
431            Op::Flink(op) => op.fd,
432            Op::Fpath(op) => op.fd,
433            Op::Frename(op) => op.fd,
434            Op::Fstat(op) => op.fd,
435            Op::FstatVfs(op) => op.fd,
436            Op::Futimens(op) => op.fd,
437            Op::Call(op) => op.fd,
438            Op::Getdents(op) => op.fd,
439            Op::Recvfd(req) => req.id(),
440        })
441    }
442}
443impl CallRequest {
444    pub fn caller(&self) -> CallerCtx {
445        let sqe = &self.inner.sqe;
446
447        CallerCtx {
448            pid: sqe.caller as usize,
449            uid: sqe.args[5] as u32,
450            gid: (sqe.args[5] >> 32) as u32,
451            id: Id(sqe.tag),
452        }
453    }
454    pub fn op(self) -> Result<Op, Self> {
455        match unsafe { Op::from_sqe_unchecked(&self.inner.sqe) } {
456            Some(op) => Ok(op),
457            None => Err(self),
458        }
459    }
460    pub async fn handle_async(self, s: &mut impl SchemeAsync) -> Response {
461        let caller = self.caller();
462
463        let op = match self.op() {
464            Ok(op) => op,
465            Err(this) => return Response::new(Err(Error::new(ENOSYS)), this),
466        };
467
468        op.handle_async(caller, s).await
469    }
470    pub fn handle_sync(self, s: &mut impl SchemeSync) -> Response {
471        let caller = self.caller();
472
473        let op = match self.op() {
474            Ok(op) => op,
475            Err(this) => return Response::new(Err(Error::new(ENOSYS)), this),
476        };
477        op.handle_sync(caller, s)
478    }
479}
480
481impl SendFdRequest {
482    pub fn caller(&self) -> CallerCtx {
483        let sqe = &self.inner.sqe;
484
485        CallerCtx {
486            pid: sqe.caller as usize,
487            uid: sqe.args[5] as u32,
488            gid: (sqe.args[5] >> 32) as u32,
489            id: self.request_id(),
490        }
491    }
492}
493
494impl RecvFdRequest {
495    pub fn op(self) -> Op {
496        Op::Recvfd(self)
497    }
498    pub fn caller(&self) -> CallerCtx {
499        let sqe = &self.inner.sqe;
500
501        CallerCtx {
502            pid: sqe.caller as usize,
503            uid: sqe.args[5] as u32,
504            gid: (sqe.args[5] >> 32) as u32,
505            id: self.request_id(),
506        }
507    }
508}
509
510pub enum SchemeResponse {
511    Regular(Result<usize>),
512    Opened(Result<OpenResult>),
513}
514impl From<Result<usize>> for SchemeResponse {
515    fn from(value: Result<usize>) -> Self {
516        Self::Regular(value)
517    }
518}
519impl Op {
520    pub fn handle_sync(mut self, caller: CallerCtx, s: &mut impl SchemeSync) -> Response {
521        match self.handle_sync_dont_consume(&caller, s) {
522            SchemeResponse::Opened(open) => Response::open_dup_like(open, self),
523            SchemeResponse::Regular(reg) => Response::new(reg, self),
524        }
525    }
526    pub fn handle_sync_dont_consume(
527        &mut self,
528        caller: &CallerCtx,
529        s: &mut impl SchemeSync,
530    ) -> SchemeResponse {
531        match *self {
532            Op::Open(ref req) => {
533                let res = s.open(req.path(), req.flags, &caller);
534                return SchemeResponse::Opened(res);
535            }
536            Op::OpenAt(ref req) => {
537                let res = s.openat(
538                    req.fd,
539                    req.path(),
540                    req.inner.flags,
541                    req.fcntl_flags,
542                    &caller,
543                );
544                return SchemeResponse::Opened(res);
545            }
546            Op::Rmdir(ref req) => s.rmdir(req.path(), &caller).map(|()| 0).into(),
547            Op::Unlink(ref req) => s.unlink(req.path(), &caller).map(|()| 0).into(),
548            Op::UnlinkAt(ref req) => s
549                .unlinkat(req.fd, req.path(), req.inner.flags, &caller)
550                .map(|()| 0)
551                .into(),
552            Op::Dup(ref req) => {
553                let res = s.dup(req.fd, req.buf(), &caller);
554                return SchemeResponse::Opened(res);
555            }
556            Op::Read(ref mut req) => {
557                let OpRead {
558                    fd, offset, flags, ..
559                } = *req;
560                s.read(fd, req.buf(), offset, flags, &caller).into()
561            }
562            Op::Write(ref req) => s
563                .write(req.fd, req.buf(), req.offset, req.flags, &caller)
564                .into(),
565
566            // TODO: Don't convert to usize
567            Op::Fsize { fd, .. } => s.fsize(fd, &caller).map(|l| l as usize).into(),
568
569            Op::Fchmod { fd, new_mode, .. } => s.fchmod(fd, new_mode, &caller).map(|()| 0).into(),
570            Op::Fchown {
571                fd,
572                new_uid,
573                new_gid,
574                ..
575            } => s.fchown(fd, new_uid, new_gid, &caller).map(|()| 0).into(),
576            Op::Fcntl { fd, cmd, arg, .. } => s.fcntl(fd, cmd, arg, &caller).into(),
577            Op::Fevent { fd, req_flags, .. } => {
578                s.fevent(fd, req_flags, &caller).map(|f| f.bits()).into()
579            }
580            Op::Flink(ref req) => s.flink(req.fd, req.buf(), &caller).into(),
581            Op::Fpath(ref mut req) => s.fpath(req.fd, req.buf(), &caller).into(),
582            Op::Frename(ref req) => s.frename(req.fd, req.buf(), &caller).into(),
583            Op::Fstat(ref mut req) => s.fstat(req.fd, req.buf(), &caller).map(|()| 0).into(),
584            Op::FstatVfs(ref mut req) => s.fstatvfs(req.fd, req.buf(), &caller).map(|()| 0).into(),
585            Op::Fsync { fd, .. } => s.fsync(fd, &caller).map(|()| 0).into(),
586            Op::Ftruncate { fd, new_sz, .. } => s.ftruncate(fd, new_sz, &caller).map(|()| 0).into(),
587            Op::Futimens(ref req) => s.futimens(req.fd, req.buf(), &caller).map(|()| 0).into(),
588
589            Op::MmapPrep {
590                fd,
591                offset,
592                len,
593                flags,
594                ..
595            } => s.mmap_prep(fd, offset, len, flags, &caller).into(),
596            Op::Munmap {
597                fd,
598                offset,
599                len,
600                flags,
601                ..
602            } => s.munmap(fd, offset, len, flags, &caller).map(|()| 0).into(),
603
604            Op::Call(ref mut req) => {
605                let fd = req.fd;
606                let (payload, metadata) = req.payload_and_metadata();
607                s.call(fd, payload, metadata, &caller).into()
608            }
609
610            Op::Getdents(ref mut req) => {
611                let OpGetdents {
612                    fd, opaque_offset, ..
613                } = *req;
614                let Some(buf) = req.buf() else {
615                    return Err(Error::new(EINVAL)).into();
616                };
617                let buf_res = s.getdents(fd, buf, opaque_offset);
618                buf_res.map(|b| b.finalize()).into()
619            }
620            Op::Recvfd(ref req) => {
621                let res = s.on_recvfd(req);
622                return SchemeResponse::Opened(res);
623            }
624        }
625    }
626    // XXX: Although this has not yet been benchmarked, it likely makes sense for the
627    // readiness-based (or non-blockable) and completion-based APIs to diverge, as it is imperative
628    // that futures stay small.
629    pub async fn handle_async(self, caller: CallerCtx, s: &mut impl SchemeAsync) -> Response {
630        let (res, tag) = match self {
631            Op::Open(req) => {
632                let res = s.open(req.path(), req.flags, &caller).await;
633                return Response::open_dup_like(res, req);
634            }
635            Op::OpenAt(req) => {
636                let res = s
637                    .openat(
638                        req.fd,
639                        req.path(),
640                        req.inner.flags,
641                        req.fcntl_flags,
642                        &caller,
643                    )
644                    .await;
645                return Response::open_dup_like(res, req);
646            }
647            Op::Rmdir(req) => (
648                s.rmdir(req.path(), &caller).await.map(|()| 0),
649                req.into_tag(),
650            ),
651            Op::Unlink(req) => (
652                s.unlink(req.path(), &caller).await.map(|()| 0),
653                req.into_tag(),
654            ),
655            Op::UnlinkAt(req) => (
656                s.unlinkat(req.fd, req.path(), req.inner.flags, &caller)
657                    .await
658                    .map(|()| 0)
659                    .into(),
660                req.into_tag(),
661            ),
662            Op::Dup(req) => {
663                let res = s.dup(req.fd, req.buf(), &caller).await;
664                return Response::open_dup_like(res, req);
665            }
666            Op::Read(mut req) => {
667                let OpRead {
668                    fd, offset, flags, ..
669                } = req;
670                (
671                    s.read(fd, req.buf(), offset, flags, &caller).await,
672                    req.into_tag(),
673                )
674            }
675            Op::Write(req) => (
676                s.write(req.fd, req.buf(), req.offset, req.flags, &caller)
677                    .await,
678                req.into_tag(),
679            ),
680
681            // TODO: Don't convert to usize
682            Op::Fsize { req, fd } => (s.fsize(fd, &caller).await.map(|l| l as usize), req),
683
684            Op::Fchmod { req, fd, new_mode } => {
685                (s.fchmod(fd, new_mode, &caller).await.map(|()| 0), req)
686            }
687            Op::Fchown {
688                req,
689                fd,
690                new_uid,
691                new_gid,
692            } => (
693                s.fchown(fd, new_uid, new_gid, &caller).await.map(|()| 0),
694                req,
695            ),
696            Op::Fcntl { req, fd, cmd, arg } => (s.fcntl(fd, cmd, arg, &caller).await, req),
697            Op::Fevent { req, fd, req_flags } => (
698                s.fevent(fd, req_flags, &caller).await.map(|f| f.bits()),
699                req,
700            ),
701            Op::Flink(req) => (s.flink(req.fd, req.buf(), &caller).await, req.into_tag()),
702            Op::Fpath(mut req) => (s.fpath(req.fd, req.buf(), &caller).await, req.into_tag()),
703            Op::Frename(req) => (s.frename(req.fd, req.buf(), &caller).await, req.into_tag()),
704            Op::Fstat(mut req) => (
705                s.fstat(req.fd, req.buf(), &caller).await.map(|()| 0),
706                req.into_tag(),
707            ),
708            Op::FstatVfs(mut req) => (
709                s.fstatvfs(req.fd, req.buf(), &caller).await.map(|()| 0),
710                req.into_tag(),
711            ),
712            Op::Fsync { req, fd } => (s.fsync(fd, &caller).await.map(|()| 0), req),
713            Op::Ftruncate { req, fd, new_sz } => {
714                (s.ftruncate(fd, new_sz, &caller).await.map(|()| 0), req)
715            }
716            Op::Futimens(req) => (
717                s.futimens(req.fd, req.buf(), &caller).await.map(|()| 0),
718                req.into_tag(),
719            ),
720
721            Op::MmapPrep {
722                req,
723                fd,
724                offset,
725                len,
726                flags,
727            } => (s.mmap_prep(fd, offset, len, flags, &caller).await, req),
728            Op::Munmap {
729                req,
730                fd,
731                offset,
732                len,
733                flags,
734            } => (
735                s.munmap(fd, offset, len, flags, &caller).await.map(|()| 0),
736                req,
737            ),
738
739            Op::Call(mut req) => {
740                let fd = req.fd;
741                let (payload, metadata) = req.payload_and_metadata();
742                (s.call(fd, payload, metadata, &caller).await, req.into_tag())
743            }
744
745            Op::Getdents(mut req) => {
746                let OpGetdents {
747                    fd, opaque_offset, ..
748                } = req;
749                let Some(buf) = req.buf() else {
750                    return Response::err(EINVAL, req);
751                };
752                let buf_res = s.getdents(fd, buf, opaque_offset).await;
753                (buf_res.map(|b| b.finalize()), req.into_tag())
754            }
755            Op::Recvfd(req) => {
756                let res = s.on_recvfd(&req).await;
757                return Response::open_dup_like(res, req);
758            }
759        };
760        Response::new(res, tag)
761    }
762}
763
764#[allow(unused_variables)]
765pub trait SchemeAsync {
766    /* Scheme operations */
767    async fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
768        Err(Error::new(ENOENT))
769    }
770
771    async fn openat(
772        &mut self,
773        fd: usize,
774        path: &str,
775        flags: usize,
776        fcntl_flags: u32,
777        ctx: &CallerCtx,
778    ) -> Result<OpenResult> {
779        Err(Error::new(EOPNOTSUPP))
780    }
781
782    async fn rmdir(&mut self, path: &str, ctx: &CallerCtx) -> Result<()> {
783        Err(Error::new(ENOENT))
784    }
785
786    async fn unlink(&mut self, path: &str, ctx: &CallerCtx) -> Result<()> {
787        Err(Error::new(ENOENT))
788    }
789
790    async fn unlinkat(
791        &mut self,
792        fd: usize,
793        path: &str,
794        flags: usize,
795        ctx: &CallerCtx,
796    ) -> Result<()> {
797        Err(Error::new(ENOENT))
798    }
799
800    /* Resource operations */
801    async fn dup(&mut self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<OpenResult> {
802        Err(Error::new(EOPNOTSUPP))
803    }
804
805    async fn read(
806        &mut self,
807        id: usize,
808        buf: &mut [u8],
809        offset: u64,
810        fcntl_flags: u32,
811        ctx: &CallerCtx,
812    ) -> Result<usize> {
813        Err(Error::new(EBADF))
814    }
815
816    async fn write(
817        &mut self,
818        id: usize,
819        buf: &[u8],
820        offset: u64,
821        fcntl_flags: u32,
822        ctx: &CallerCtx,
823    ) -> Result<usize> {
824        Err(Error::new(EBADF))
825    }
826
827    async fn fsize(&mut self, id: usize, ctx: &CallerCtx) -> Result<u64> {
828        Err(Error::new(ESPIPE))
829    }
830
831    async fn fchmod(&mut self, id: usize, new_mode: u16, ctx: &CallerCtx) -> Result<()> {
832        Err(Error::new(EOPNOTSUPP))
833    }
834
835    async fn fchown(
836        &mut self,
837        id: usize,
838        new_uid: u32,
839        new_gid: u32,
840        ctx: &CallerCtx,
841    ) -> Result<()> {
842        Err(Error::new(EOPNOTSUPP))
843    }
844
845    async fn fcntl(&mut self, id: usize, cmd: usize, arg: usize, ctx: &CallerCtx) -> Result<usize> {
846        Err(Error::new(EOPNOTSUPP))
847    }
848
849    async fn fevent(
850        &mut self,
851        id: usize,
852        flags: EventFlags,
853        ctx: &CallerCtx,
854    ) -> Result<EventFlags> {
855        Ok(EventFlags::empty())
856    }
857
858    async fn flink(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
859        Err(Error::new(EOPNOTSUPP))
860    }
861
862    async fn fpath(&mut self, id: usize, buf: &mut [u8], ctx: &CallerCtx) -> Result<usize> {
863        Err(Error::new(EOPNOTSUPP))
864    }
865
866    async fn frename(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
867        Err(Error::new(EOPNOTSUPP))
868    }
869
870    async fn fstat(&mut self, id: usize, stat: &mut Stat, ctx: &CallerCtx) -> Result<()> {
871        Err(Error::new(EOPNOTSUPP))
872    }
873
874    async fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs, ctx: &CallerCtx) -> Result<()> {
875        Err(Error::new(EOPNOTSUPP))
876    }
877
878    async fn fsync(&mut self, id: usize, ctx: &CallerCtx) -> Result<()> {
879        Ok(())
880    }
881
882    async fn ftruncate(&mut self, id: usize, len: u64, ctx: &CallerCtx) -> Result<()> {
883        Err(Error::new(EBADF))
884    }
885
886    async fn futimens(&mut self, id: usize, times: &[TimeSpec], ctx: &CallerCtx) -> Result<()> {
887        Err(Error::new(EBADF))
888    }
889
890    async fn call(
891        &mut self,
892        id: usize,
893        payload: &mut [u8],
894        metadata: &[u64],
895        ctx: &CallerCtx, // Only pid and id are correct here, uid/gid are not used
896    ) -> Result<usize> {
897        Err(Error::new(EOPNOTSUPP))
898    }
899
900    async fn getdents<'buf>(
901        &mut self,
902        id: usize,
903        buf: DirentBuf<&'buf mut [u8]>,
904        opaque_offset: u64,
905    ) -> Result<DirentBuf<&'buf mut [u8]>> {
906        Err(Error::new(ENOTDIR))
907    }
908
909    async fn mmap_prep(
910        &mut self,
911        id: usize,
912        offset: u64,
913        size: usize,
914        flags: MapFlags,
915        ctx: &CallerCtx,
916    ) -> Result<usize> {
917        Err(Error::new(EOPNOTSUPP))
918    }
919
920    async fn munmap(
921        &mut self,
922        id: usize,
923        offset: u64,
924        size: usize,
925        flags: MunmapFlags,
926        ctx: &CallerCtx,
927    ) -> Result<()> {
928        Err(Error::new(EOPNOTSUPP))
929    }
930
931    async fn on_recvfd(&mut self, recvfd_request: &RecvFdRequest) -> Result<OpenResult> {
932        Err(Error::new(EOPNOTSUPP))
933    }
934}
935#[allow(unused_variables)]
936pub trait SchemeSync {
937    /* Scheme operations */
938    fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
939        Err(Error::new(ENOENT))
940    }
941
942    fn openat(
943        &mut self,
944        fd: usize,
945        path: &str,
946        flags: usize,
947        fcntl_flags: u32,
948        ctx: &CallerCtx,
949    ) -> Result<OpenResult> {
950        Err(Error::new(EOPNOTSUPP))
951    }
952
953    fn rmdir(&mut self, path: &str, ctx: &CallerCtx) -> Result<()> {
954        Err(Error::new(ENOENT))
955    }
956
957    fn unlink(&mut self, path: &str, ctx: &CallerCtx) -> Result<()> {
958        Err(Error::new(ENOENT))
959    }
960
961    fn unlinkat(&mut self, fd: usize, path: &str, flags: usize, ctx: &CallerCtx) -> Result<()> {
962        Err(Error::new(ENOENT))
963    }
964
965    /* Resource operations */
966    fn dup(&mut self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<OpenResult> {
967        Err(Error::new(EOPNOTSUPP))
968    }
969
970    fn read(
971        &mut self,
972        id: usize,
973        buf: &mut [u8],
974        offset: u64,
975        fcntl_flags: u32,
976        ctx: &CallerCtx,
977    ) -> Result<usize> {
978        Err(Error::new(EBADF))
979    }
980
981    fn write(
982        &mut self,
983        id: usize,
984        buf: &[u8],
985        offset: u64,
986        fcntl_flags: u32,
987        ctx: &CallerCtx,
988    ) -> Result<usize> {
989        Err(Error::new(EBADF))
990    }
991
992    fn fsize(&mut self, id: usize, ctx: &CallerCtx) -> Result<u64> {
993        Err(Error::new(ESPIPE))
994    }
995
996    fn fchmod(&mut self, id: usize, new_mode: u16, ctx: &CallerCtx) -> Result<()> {
997        Err(Error::new(EOPNOTSUPP))
998    }
999
1000    fn fchown(&mut self, id: usize, new_uid: u32, new_gid: u32, ctx: &CallerCtx) -> Result<()> {
1001        Err(Error::new(EOPNOTSUPP))
1002    }
1003
1004    fn fcntl(&mut self, id: usize, cmd: usize, arg: usize, ctx: &CallerCtx) -> Result<usize> {
1005        Err(Error::new(EOPNOTSUPP))
1006    }
1007
1008    fn fevent(&mut self, id: usize, flags: EventFlags, ctx: &CallerCtx) -> Result<EventFlags> {
1009        Ok(EventFlags::empty())
1010    }
1011
1012    fn flink(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
1013        Err(Error::new(EOPNOTSUPP))
1014    }
1015
1016    fn fpath(&mut self, id: usize, buf: &mut [u8], ctx: &CallerCtx) -> Result<usize> {
1017        Err(Error::new(EOPNOTSUPP))
1018    }
1019
1020    fn frename(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
1021        Err(Error::new(EOPNOTSUPP))
1022    }
1023
1024    fn fstat(&mut self, id: usize, stat: &mut Stat, ctx: &CallerCtx) -> Result<()> {
1025        Err(Error::new(EOPNOTSUPP))
1026    }
1027
1028    fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs, ctx: &CallerCtx) -> Result<()> {
1029        Err(Error::new(EOPNOTSUPP))
1030    }
1031
1032    fn fsync(&mut self, id: usize, ctx: &CallerCtx) -> Result<()> {
1033        Ok(())
1034    }
1035
1036    fn ftruncate(&mut self, id: usize, len: u64, ctx: &CallerCtx) -> Result<()> {
1037        Err(Error::new(EBADF))
1038    }
1039
1040    fn futimens(&mut self, id: usize, times: &[TimeSpec], ctx: &CallerCtx) -> Result<()> {
1041        Err(Error::new(EBADF))
1042    }
1043
1044    fn call(
1045        &mut self,
1046        id: usize,
1047        payload: &mut [u8],
1048        metadata: &[u64],
1049        ctx: &CallerCtx, // Only pid and id are correct here, uid/gid are not used
1050    ) -> Result<usize> {
1051        Err(Error::new(EOPNOTSUPP))
1052    }
1053
1054    fn getdents<'buf>(
1055        &mut self,
1056        id: usize,
1057        buf: DirentBuf<&'buf mut [u8]>,
1058        opaque_offset: u64,
1059    ) -> Result<DirentBuf<&'buf mut [u8]>> {
1060        Err(Error::new(ENOTDIR))
1061    }
1062
1063    fn mmap_prep(
1064        &mut self,
1065        id: usize,
1066        offset: u64,
1067        size: usize,
1068        flags: MapFlags,
1069        ctx: &CallerCtx,
1070    ) -> Result<usize> {
1071        Err(Error::new(EOPNOTSUPP))
1072    }
1073
1074    fn munmap(
1075        &mut self,
1076        id: usize,
1077        offset: u64,
1078        size: usize,
1079        flags: MunmapFlags,
1080        ctx: &CallerCtx,
1081    ) -> Result<()> {
1082        Err(Error::new(EOPNOTSUPP))
1083    }
1084
1085    fn on_close(&mut self, id: usize) {}
1086
1087    fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
1088        Err(Error::new(EOPNOTSUPP))
1089    }
1090    fn on_recvfd(&mut self, recvfd_request: &RecvFdRequest) -> Result<OpenResult> {
1091        Err(Error::new(EOPNOTSUPP))
1092    }
1093}
1094pub trait IntoTag {
1095    fn into_tag(self) -> Tag;
1096    fn req_id(&self) -> Id;
1097}
1098impl IntoTag for Tag {
1099    fn into_tag(self) -> Tag {
1100        self
1101    }
1102    fn req_id(&self) -> Id {
1103        self.0
1104    }
1105}
1106impl IntoTag for CallRequest {
1107    fn into_tag(self) -> Tag {
1108        Tag(self.request_id())
1109    }
1110    fn req_id(&self) -> Id {
1111        self.request_id()
1112    }
1113}
1114impl IntoTag for SendFdRequest {
1115    fn into_tag(self) -> Tag {
1116        Tag(self.request_id())
1117    }
1118    fn req_id(&self) -> Id {
1119        self.request_id()
1120    }
1121}
1122impl IntoTag for RecvFdRequest {
1123    fn into_tag(self) -> Tag {
1124        Tag(self.request_id())
1125    }
1126    fn req_id(&self) -> Id {
1127        self.request_id()
1128    }
1129}
1130macro_rules! trivial_into {
1131    [$($name:ident,)*] => {
1132        $(
1133        impl IntoTag for $name {
1134            #[inline]
1135            fn into_tag(self) -> Tag {
1136                self.req
1137            }
1138            #[inline]
1139            fn req_id(&self) -> Id {
1140                self.req.req_id()
1141            }
1142        }
1143        )*
1144    }
1145}
1146trivial_into![OpCall, OpRead, OpWrite, OpGetdents,];
1147impl<T: ?Sized> IntoTag for OpQueryWrite<T> {
1148    fn into_tag(self) -> Tag {
1149        self.req
1150    }
1151    fn req_id(&self) -> Id {
1152        self.req.0
1153    }
1154}
1155impl<T: ?Sized> IntoTag for OpQueryRead<T> {
1156    fn into_tag(self) -> Tag {
1157        self.req
1158    }
1159    fn req_id(&self) -> Id {
1160        self.req.0
1161    }
1162}
1163impl<F> IntoTag for OpPathLike<F> {
1164    fn into_tag(self) -> Tag {
1165        self.req
1166    }
1167    fn req_id(&self) -> Id {
1168        self.req.0
1169    }
1170}
1171impl<F> IntoTag for OpFdPathLike<F> {
1172    fn into_tag(self) -> Tag {
1173        self.inner.req
1174    }
1175    fn req_id(&self) -> Id {
1176        self.inner.req.0
1177    }
1178}
1179impl IntoTag for Op {
1180    fn into_tag(self) -> Tag {
1181        use Op::*;
1182        match self {
1183            Open(op) => op.into_tag(),
1184            OpenAt(op) => op.into_tag(),
1185            Rmdir(op) | Self::Unlink(op) => op.into_tag(),
1186            UnlinkAt(op) => op.into_tag(),
1187            Dup(op) => op.into_tag(),
1188            Read(op) => op.into_tag(),
1189            Write(op) => op.into_tag(),
1190            Fsize { req, .. }
1191            | Fchmod { req, .. }
1192            | Fchown { req, .. }
1193            | Fcntl { req, .. }
1194            | Fevent { req, .. }
1195            | Fsync { req, .. }
1196            | Ftruncate { req, .. }
1197            | MmapPrep { req, .. }
1198            | Munmap { req, .. } => req,
1199            Flink(op) => op.into_tag(),
1200            Fpath(op) => op.into_tag(),
1201            Frename(op) => op.into_tag(),
1202            Fstat(op) => op.into_tag(),
1203            FstatVfs(op) => op.into_tag(),
1204            Futimens(op) => op.into_tag(),
1205            Call(op) => op.into_tag(),
1206            Getdents(op) => op.into_tag(),
1207            Recvfd(req) => req.into_tag(),
1208        }
1209    }
1210    fn req_id(&self) -> Id {
1211        use Op::*;
1212        match self {
1213            Open(op) => op.req_id(),
1214            OpenAt(op) => op.req_id(),
1215            Rmdir(op) | Self::Unlink(op) => op.req_id(),
1216            UnlinkAt(op) => op.req_id(),
1217            Dup(op) => op.req_id(),
1218            Read(op) => op.req_id(),
1219            Write(op) => op.req_id(),
1220            Fsize { req, .. }
1221            | Fchmod { req, .. }
1222            | Fchown { req, .. }
1223            | Fcntl { req, .. }
1224            | Fevent { req, .. }
1225            | Fsync { req, .. }
1226            | Ftruncate { req, .. }
1227            | MmapPrep { req, .. }
1228            | Munmap { req, .. } => req.req_id(),
1229            Flink(op) => op.req_id(),
1230            Fpath(op) => op.req_id(),
1231            Frename(op) => op.req_id(),
1232            Fstat(op) => op.req_id(),
1233            FstatVfs(op) => op.req_id(),
1234            Futimens(op) => op.req_id(),
1235            Call(op) => op.req_id(),
1236            Getdents(op) => op.req_id(),
1237            Recvfd(req) => req.req_id(),
1238        }
1239    }
1240}