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