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