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