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: [u64; 3],
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        &self.metadata
70    }
71}
72impl Debug for OpCall {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        f.debug_struct("OpCall")
75            .field("fd", &self.fd)
76            // TODO: debug first and last few bytes, collapse middle to ...
77            .field("payload", &self.payload)
78            .field("metadata", &self.metadata())
79            .finish()
80    }
81}
82#[derive(Debug)]
83pub struct OpQueryRead<T: ?Sized> {
84    pub fd: usize,
85    req: Tag,
86    buf: *mut T,
87}
88impl<T: ?Sized> OpQueryRead<T> {
89    pub fn buf(&mut self) -> &mut T {
90        // SAFETY: borrows &mut self.req
91        unsafe { &mut *self.buf }
92    }
93}
94#[derive(Debug)]
95pub struct OpQueryWrite<T: ?Sized> {
96    pub fd: usize,
97    req: Tag,
98    buf: *const T,
99}
100impl<T: ?Sized> OpQueryWrite<T> {
101    pub fn buf(&self) -> &T {
102        // SAFETY: borrows &self.req
103        unsafe { &*self.buf }
104    }
105}
106#[derive(Debug)]
107pub struct OpGetdents {
108    req: Tag,
109    pub fd: usize,
110    buf: *mut [u8],
111    pub header_size: u16,
112    pub opaque_offset: u64,
113}
114impl OpGetdents {
115    pub fn raw_buf(&mut self) -> &mut [u8] {
116        // SAFETY: borrows
117        unsafe { &mut *self.buf }
118    }
119    pub fn buf(&mut self) -> Option<DirentBuf<&mut [u8]>> {
120        let sz = self.header_size;
121        DirentBuf::new(self.raw_buf(), sz)
122    }
123}
124#[derive(Debug)]
125pub struct OpRead {
126    req: Tag,
127    pub fd: usize,
128    pub offset: u64,
129    pub flags: u32,
130    buf: *mut [u8],
131}
132impl OpRead {
133    pub fn buf(&mut self) -> &mut [u8] {
134        // SAFETY: Borrows &mut self.req
135        unsafe { &mut *self.buf }
136    }
137}
138#[derive(Debug)]
139pub struct OpWrite {
140    req: Tag,
141    pub fd: usize,
142    pub offset: u64,
143    pub flags: u32,
144    buf: *const [u8],
145}
146impl OpWrite {
147    pub fn buf(&self) -> &[u8] {
148        // SAFETY: Borrows &self.req
149        unsafe { &*self.buf }
150    }
151}
152
153#[non_exhaustive]
154#[derive(Debug)]
155pub enum Op {
156    Open(OpPathLike<usize>),
157    OpenAt(OpFdPathLike<usize>),
158    Rmdir(OpPathLike<()>),
159    Unlink(OpPathLike<()>),
160    Dup(OpQueryWrite<[u8]>),
161    Read(OpRead),
162    Write(OpWrite),
163    Fsize {
164        req: Tag,
165        fd: usize,
166    },
167    Fchmod {
168        req: Tag,
169        fd: usize,
170        new_mode: u16,
171    },
172    Fchown {
173        req: Tag,
174        fd: usize,
175        new_uid: u32,
176        new_gid: u32,
177    },
178    Fcntl {
179        req: Tag,
180        fd: usize,
181        cmd: usize,
182        arg: usize,
183    },
184    Fevent {
185        req: Tag,
186        fd: usize,
187        req_flags: EventFlags,
188    },
189    Flink(OpQueryWrite<str>),
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::Flink => Op::Flink(OpQueryWrite {
310                req,
311                fd: a,
312                buf: str::from_utf8_unchecked(slice::from_raw_parts(b as *const u8, c)),
313            }),
314            Opcode::Fpath => Op::Fpath(OpQueryRead {
315                req,
316                fd: a,
317                buf: slice::from_raw_parts_mut(b as *mut u8, c),
318            }),
319            Opcode::Frename => Op::Frename(OpQueryWrite {
320                req,
321                fd: a,
322                buf: str::from_utf8_unchecked(slice::from_raw_parts(b as *const u8, c)),
323            }),
324            Opcode::Fstat => {
325                assert!(c >= size_of::<Stat>());
326                Op::Fstat(OpQueryRead {
327                    req,
328                    fd: a,
329                    buf: &mut *(b as *mut Stat),
330                })
331            }
332            Opcode::Fstatvfs => {
333                assert!(c >= size_of::<StatVfs>());
334                Op::FstatVfs(OpQueryRead {
335                    req,
336                    fd: a,
337                    buf: &mut *(b as *mut StatVfs),
338                })
339            }
340            Opcode::Fsync => Op::Fsync { req, fd: a },
341            Opcode::Ftruncate => Op::Ftruncate {
342                req,
343                fd: a,
344                new_sz: args[1],
345            },
346            Opcode::Futimens => {
347                assert!(c <= 2 * size_of::<TimeSpec>());
348                Op::Futimens(OpQueryWrite {
349                    req,
350                    fd: a,
351                    buf: slice::from_raw_parts(b as *const TimeSpec, c / size_of::<TimeSpec>()),
352                })
353            }
354
355            Opcode::Call => Op::Call(OpCall {
356                req,
357                fd: a,
358                payload: slice::from_raw_parts_mut(b as *mut u8, c),
359                metadata: [sqe.args[3], sqe.args[4], sqe.args[5]],
360            }),
361            Opcode::Getdents => Op::Getdents(OpGetdents {
362                req,
363                fd: a,
364                buf: slice::from_raw_parts_mut(b as *mut u8, c),
365                header_size: sqe.args[3] as u16,
366                opaque_offset: sqe.args[4],
367            }),
368
369            Opcode::MmapPrep => Op::MmapPrep {
370                req,
371                fd: a,
372                offset: args[3],
373                len: b,
374                flags: MapFlags::from_bits_retain(c),
375            },
376            Opcode::Munmap => Op::Munmap {
377                req,
378                fd: a,
379                offset: args[3],
380                len: b,
381                flags: MunmapFlags::from_bits_retain(c),
382            },
383
384            _ => return None,
385        })
386    }
387    pub fn is_explicitly_nonblock(&self) -> bool {
388        let flags = match self {
389            Self::Read(r) => r.flags,
390            Self::Write(w) => w.flags,
391            Self::OpenAt(o) => o.fcntl_flags,
392            Self::Open(o) => o.flags as u32,
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}
461
462impl SendFdRequest {
463    pub fn caller(&self) -> CallerCtx {
464        let sqe = &self.inner.sqe;
465
466        CallerCtx {
467            pid: sqe.caller as usize,
468            uid: sqe.args[5] as u32,
469            gid: (sqe.args[5] >> 32) as u32,
470            id: self.request_id(),
471        }
472    }
473}
474
475pub enum SchemeResponse {
476    Regular(Result<usize>),
477    Opened(Result<OpenResult>),
478}
479impl From<Result<usize>> for SchemeResponse {
480    fn from(value: Result<usize>) -> Self {
481        Self::Regular(value)
482    }
483}
484impl Op {
485    pub fn handle_sync(mut self, caller: CallerCtx, s: &mut impl SchemeSync) -> Response {
486        match self.handle_sync_dont_consume(&caller, s) {
487            SchemeResponse::Opened(open) => Response::open_dup_like(open, self),
488            SchemeResponse::Regular(reg) => Response::new(reg, self),
489        }
490    }
491    pub fn handle_sync_dont_consume(
492        &mut self,
493        caller: &CallerCtx,
494        s: &mut impl SchemeSync,
495    ) -> SchemeResponse {
496        match *self {
497            Op::Open(ref req) => {
498                let res = s.open(req.path(), req.flags, &caller);
499                return SchemeResponse::Opened(res);
500            }
501            Op::OpenAt(ref req) => {
502                let res = s.openat(
503                    req.fd,
504                    req.path(),
505                    req.inner.flags,
506                    req.fcntl_flags,
507                    &caller,
508                );
509                return SchemeResponse::Opened(res);
510            }
511            Op::Rmdir(ref req) => s.rmdir(req.path(), &caller).map(|()| 0).into(),
512            Op::Unlink(ref req) => s.unlink(req.path(), &caller).map(|()| 0).into(),
513
514            Op::Dup(ref req) => {
515                let res = s.dup(req.fd, req.buf(), &caller);
516                return SchemeResponse::Opened(res);
517            }
518            Op::Read(ref mut req) => {
519                let OpRead {
520                    fd, offset, flags, ..
521                } = *req;
522                s.read(fd, req.buf(), offset, flags, &caller).into()
523            }
524            Op::Write(ref req) => s
525                .write(req.fd, req.buf(), req.offset, req.flags, &caller)
526                .into(),
527
528            // TODO: Don't convert to usize
529            Op::Fsize { fd, .. } => s.fsize(fd, &caller).map(|l| l as usize).into(),
530
531            Op::Fchmod { fd, new_mode, .. } => s.fchmod(fd, new_mode, &caller).map(|()| 0).into(),
532            Op::Fchown {
533                fd,
534                new_uid,
535                new_gid,
536                ..
537            } => s.fchown(fd, new_uid, new_gid, &caller).map(|()| 0).into(),
538            Op::Fcntl { fd, cmd, arg, .. } => s.fcntl(fd, cmd, arg, &caller).into(),
539            Op::Fevent { fd, req_flags, .. } => {
540                s.fevent(fd, req_flags, &caller).map(|f| f.bits()).into()
541            }
542            Op::Flink(ref req) => s.flink(req.fd, req.buf(), &caller).into(),
543            Op::Fpath(ref mut req) => s.fpath(req.fd, req.buf(), &caller).into(),
544            Op::Frename(ref req) => s.frename(req.fd, req.buf(), &caller).into(),
545            Op::Fstat(ref mut req) => s.fstat(req.fd, req.buf(), &caller).map(|()| 0).into(),
546            Op::FstatVfs(ref mut req) => s.fstatvfs(req.fd, req.buf(), &caller).map(|()| 0).into(),
547            Op::Fsync { fd, .. } => s.fsync(fd, &caller).map(|()| 0).into(),
548            Op::Ftruncate { fd, new_sz, .. } => s.ftruncate(fd, new_sz, &caller).map(|()| 0).into(),
549            Op::Futimens(ref req) => s.futimens(req.fd, req.buf(), &caller).map(|()| 0).into(),
550
551            Op::MmapPrep {
552                fd,
553                offset,
554                len,
555                flags,
556                ..
557            } => s.mmap_prep(fd, offset, len, flags, &caller).into(),
558            Op::Munmap {
559                fd,
560                offset,
561                len,
562                flags,
563                ..
564            } => s.munmap(fd, offset, len, flags, &caller).map(|()| 0).into(),
565
566            Op::Call(ref mut req) => {
567                let fd = req.fd;
568                let (payload, metadata) = req.payload_and_metadata();
569                s.call(fd, payload, metadata, &caller).into()
570            }
571
572            Op::Getdents(ref mut req) => {
573                let OpGetdents {
574                    fd, opaque_offset, ..
575                } = *req;
576                let Some(buf) = req.buf() else {
577                    return Err(Error::new(EINVAL)).into();
578                };
579                let buf_res = s.getdents(fd, buf, opaque_offset);
580                buf_res.map(|b| b.finalize()).into()
581            }
582        }
583    }
584    // XXX: Although this has not yet been benchmarked, it likely makes sense for the
585    // readiness-based (or non-blockable) and completion-based APIs to diverge, as it is imperative
586    // that futures stay small.
587    pub async fn handle_async(self, caller: CallerCtx, s: &mut impl SchemeAsync) -> Response {
588        let (res, tag) = match self {
589            Op::Open(req) => {
590                let res = s.open(req.path(), req.flags, &caller).await;
591                return Response::open_dup_like(res, req);
592            }
593            Op::OpenAt(req) => {
594                let res = s
595                    .openat(
596                        req.fd,
597                        req.path(),
598                        req.inner.flags,
599                        req.fcntl_flags,
600                        &caller,
601                    )
602                    .await;
603                return Response::open_dup_like(res, req);
604            }
605            Op::Rmdir(req) => (
606                s.rmdir(req.path(), &caller).await.map(|()| 0),
607                req.into_tag(),
608            ),
609            Op::Unlink(req) => (
610                s.unlink(req.path(), &caller).await.map(|()| 0),
611                req.into_tag(),
612            ),
613
614            Op::Dup(req) => {
615                let res = s.dup(req.fd, req.buf(), &caller).await;
616                return Response::open_dup_like(res, req);
617            }
618            Op::Read(mut req) => {
619                let OpRead {
620                    fd, offset, flags, ..
621                } = req;
622                (
623                    s.read(fd, req.buf(), offset, flags, &caller).await,
624                    req.into_tag(),
625                )
626            }
627            Op::Write(req) => (
628                s.write(req.fd, req.buf(), req.offset, req.flags, &caller)
629                    .await,
630                req.into_tag(),
631            ),
632
633            // TODO: Don't convert to usize
634            Op::Fsize { req, fd } => (s.fsize(fd, &caller).await.map(|l| l as usize), req),
635
636            Op::Fchmod { req, fd, new_mode } => {
637                (s.fchmod(fd, new_mode, &caller).await.map(|()| 0), req)
638            }
639            Op::Fchown {
640                req,
641                fd,
642                new_uid,
643                new_gid,
644            } => (
645                s.fchown(fd, new_uid, new_gid, &caller).await.map(|()| 0),
646                req,
647            ),
648            Op::Fcntl { req, fd, cmd, arg } => (s.fcntl(fd, cmd, arg, &caller).await, req),
649            Op::Fevent { req, fd, req_flags } => (
650                s.fevent(fd, req_flags, &caller).await.map(|f| f.bits()),
651                req,
652            ),
653            Op::Flink(req) => (s.flink(req.fd, req.buf(), &caller).await, req.into_tag()),
654            Op::Fpath(mut req) => (s.fpath(req.fd, req.buf(), &caller).await, req.into_tag()),
655            Op::Frename(req) => (s.frename(req.fd, req.buf(), &caller).await, req.into_tag()),
656            Op::Fstat(mut req) => (
657                s.fstat(req.fd, req.buf(), &caller).await.map(|()| 0),
658                req.into_tag(),
659            ),
660            Op::FstatVfs(mut req) => (
661                s.fstatvfs(req.fd, req.buf(), &caller).await.map(|()| 0),
662                req.into_tag(),
663            ),
664            Op::Fsync { req, fd } => (s.fsync(fd, &caller).await.map(|()| 0), req),
665            Op::Ftruncate { req, fd, new_sz } => {
666                (s.ftruncate(fd, new_sz, &caller).await.map(|()| 0), req)
667            }
668            Op::Futimens(req) => (
669                s.futimens(req.fd, req.buf(), &caller).await.map(|()| 0),
670                req.into_tag(),
671            ),
672
673            Op::MmapPrep {
674                req,
675                fd,
676                offset,
677                len,
678                flags,
679            } => (s.mmap_prep(fd, offset, len, flags, &caller).await, req),
680            Op::Munmap {
681                req,
682                fd,
683                offset,
684                len,
685                flags,
686            } => (
687                s.munmap(fd, offset, len, flags, &caller).await.map(|()| 0),
688                req,
689            ),
690
691            Op::Call(mut req) => {
692                let fd = req.fd;
693                let (payload, metadata) = req.payload_and_metadata();
694                (s.call(fd, payload, metadata, &caller).await, req.into_tag())
695            }
696
697            Op::Getdents(mut req) => {
698                let OpGetdents {
699                    fd, opaque_offset, ..
700                } = req;
701                let Some(buf) = req.buf() else {
702                    return Response::err(EINVAL, req);
703                };
704                let buf_res = s.getdents(fd, buf, opaque_offset).await;
705                (buf_res.map(|b| b.finalize()), req.into_tag())
706            }
707        };
708        Response::new(res, tag)
709    }
710}
711
712#[allow(unused_variables)]
713pub trait SchemeAsync {
714    /* Scheme operations */
715    async fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
716        Err(Error::new(ENOENT))
717    }
718
719    async fn openat(
720        &mut self,
721        fd: usize,
722        path: &str,
723        flags: usize,
724        fcntl_flags: u32,
725        ctx: &CallerCtx,
726    ) -> Result<OpenResult> {
727        Err(Error::new(EOPNOTSUPP))
728    }
729
730    async fn rmdir(&mut self, path: &str, ctx: &CallerCtx) -> Result<()> {
731        Err(Error::new(ENOENT))
732    }
733
734    async fn unlink(&mut self, path: &str, ctx: &CallerCtx) -> Result<()> {
735        Err(Error::new(ENOENT))
736    }
737
738    /* Resource operations */
739    async fn dup(&mut self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<OpenResult> {
740        Err(Error::new(EOPNOTSUPP))
741    }
742
743    async fn read(
744        &mut self,
745        id: usize,
746        buf: &mut [u8],
747        offset: u64,
748        fcntl_flags: u32,
749        ctx: &CallerCtx,
750    ) -> Result<usize> {
751        Err(Error::new(EBADF))
752    }
753
754    async fn write(
755        &mut self,
756        id: usize,
757        buf: &[u8],
758        offset: u64,
759        fcntl_flags: u32,
760        ctx: &CallerCtx,
761    ) -> Result<usize> {
762        Err(Error::new(EBADF))
763    }
764
765    async fn fsize(&mut self, id: usize, ctx: &CallerCtx) -> Result<u64> {
766        Err(Error::new(ESPIPE))
767    }
768
769    async fn fchmod(&mut self, id: usize, new_mode: u16, ctx: &CallerCtx) -> Result<()> {
770        Err(Error::new(EOPNOTSUPP))
771    }
772
773    async fn fchown(
774        &mut self,
775        id: usize,
776        new_uid: u32,
777        new_gid: u32,
778        ctx: &CallerCtx,
779    ) -> Result<()> {
780        Err(Error::new(EOPNOTSUPP))
781    }
782
783    async fn fcntl(&mut self, id: usize, cmd: usize, arg: usize, ctx: &CallerCtx) -> Result<usize> {
784        Err(Error::new(EOPNOTSUPP))
785    }
786
787    async fn fevent(
788        &mut self,
789        id: usize,
790        flags: EventFlags,
791        ctx: &CallerCtx,
792    ) -> Result<EventFlags> {
793        Ok(EventFlags::empty())
794    }
795
796    async fn flink(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
797        Err(Error::new(EOPNOTSUPP))
798    }
799
800    async fn fpath(&mut self, id: usize, buf: &mut [u8], ctx: &CallerCtx) -> Result<usize> {
801        Err(Error::new(EOPNOTSUPP))
802    }
803
804    async fn frename(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
805        Err(Error::new(EOPNOTSUPP))
806    }
807
808    async fn fstat(&mut self, id: usize, stat: &mut Stat, ctx: &CallerCtx) -> Result<()> {
809        Err(Error::new(EOPNOTSUPP))
810    }
811
812    async fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs, ctx: &CallerCtx) -> Result<()> {
813        Err(Error::new(EOPNOTSUPP))
814    }
815
816    async fn fsync(&mut self, id: usize, ctx: &CallerCtx) -> Result<()> {
817        Ok(())
818    }
819
820    async fn ftruncate(&mut self, id: usize, len: u64, ctx: &CallerCtx) -> Result<()> {
821        Err(Error::new(EBADF))
822    }
823
824    async fn futimens(&mut self, id: usize, times: &[TimeSpec], ctx: &CallerCtx) -> Result<()> {
825        Err(Error::new(EBADF))
826    }
827
828    async fn call(
829        &mut self,
830        id: usize,
831        payload: &mut [u8],
832        metadata: &[u64],
833        ctx: &CallerCtx, // Only pid and id are correct here, uid/gid are not used
834    ) -> Result<usize> {
835        Err(Error::new(EOPNOTSUPP))
836    }
837
838    async fn getdents<'buf>(
839        &mut self,
840        id: usize,
841        buf: DirentBuf<&'buf mut [u8]>,
842        opaque_offset: u64,
843    ) -> Result<DirentBuf<&'buf mut [u8]>> {
844        Err(Error::new(ENOTDIR))
845    }
846
847    async fn mmap_prep(
848        &mut self,
849        id: usize,
850        offset: u64,
851        size: usize,
852        flags: MapFlags,
853        ctx: &CallerCtx,
854    ) -> Result<usize> {
855        Err(Error::new(EOPNOTSUPP))
856    }
857
858    async fn munmap(
859        &mut self,
860        id: usize,
861        offset: u64,
862        size: usize,
863        flags: MunmapFlags,
864        ctx: &CallerCtx,
865    ) -> Result<()> {
866        Err(Error::new(EOPNOTSUPP))
867    }
868}
869#[allow(unused_variables)]
870pub trait SchemeSync {
871    /* Scheme operations */
872    fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
873        Err(Error::new(ENOENT))
874    }
875
876    fn openat(
877        &mut self,
878        fd: usize,
879        path: &str,
880        flags: usize,
881        fcntl_flags: u32,
882        ctx: &CallerCtx,
883    ) -> Result<OpenResult> {
884        Err(Error::new(EOPNOTSUPP))
885    }
886
887    fn rmdir(&mut self, path: &str, ctx: &CallerCtx) -> Result<()> {
888        Err(Error::new(ENOENT))
889    }
890
891    fn unlink(&mut self, path: &str, ctx: &CallerCtx) -> Result<()> {
892        Err(Error::new(ENOENT))
893    }
894
895    /* Resource operations */
896    fn dup(&mut self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<OpenResult> {
897        Err(Error::new(EOPNOTSUPP))
898    }
899
900    fn read(
901        &mut self,
902        id: usize,
903        buf: &mut [u8],
904        offset: u64,
905        fcntl_flags: u32,
906        ctx: &CallerCtx,
907    ) -> Result<usize> {
908        Err(Error::new(EBADF))
909    }
910
911    fn write(
912        &mut self,
913        id: usize,
914        buf: &[u8],
915        offset: u64,
916        fcntl_flags: u32,
917        ctx: &CallerCtx,
918    ) -> Result<usize> {
919        Err(Error::new(EBADF))
920    }
921
922    fn fsize(&mut self, id: usize, ctx: &CallerCtx) -> Result<u64> {
923        Err(Error::new(ESPIPE))
924    }
925
926    fn fchmod(&mut self, id: usize, new_mode: u16, ctx: &CallerCtx) -> Result<()> {
927        Err(Error::new(EOPNOTSUPP))
928    }
929
930    fn fchown(&mut self, id: usize, new_uid: u32, new_gid: u32, ctx: &CallerCtx) -> Result<()> {
931        Err(Error::new(EOPNOTSUPP))
932    }
933
934    fn fcntl(&mut self, id: usize, cmd: usize, arg: usize, ctx: &CallerCtx) -> Result<usize> {
935        Err(Error::new(EOPNOTSUPP))
936    }
937
938    fn fevent(&mut self, id: usize, flags: EventFlags, ctx: &CallerCtx) -> Result<EventFlags> {
939        Ok(EventFlags::empty())
940    }
941
942    fn flink(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
943        Err(Error::new(EOPNOTSUPP))
944    }
945
946    fn fpath(&mut self, id: usize, buf: &mut [u8], ctx: &CallerCtx) -> Result<usize> {
947        Err(Error::new(EOPNOTSUPP))
948    }
949
950    fn frename(&mut self, id: usize, path: &str, ctx: &CallerCtx) -> Result<usize> {
951        Err(Error::new(EOPNOTSUPP))
952    }
953
954    fn fstat(&mut self, id: usize, stat: &mut Stat, ctx: &CallerCtx) -> Result<()> {
955        Err(Error::new(EOPNOTSUPP))
956    }
957
958    fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs, ctx: &CallerCtx) -> Result<()> {
959        Err(Error::new(EOPNOTSUPP))
960    }
961
962    fn fsync(&mut self, id: usize, ctx: &CallerCtx) -> Result<()> {
963        Ok(())
964    }
965
966    fn ftruncate(&mut self, id: usize, len: u64, ctx: &CallerCtx) -> Result<()> {
967        Err(Error::new(EBADF))
968    }
969
970    fn futimens(&mut self, id: usize, times: &[TimeSpec], ctx: &CallerCtx) -> Result<()> {
971        Err(Error::new(EBADF))
972    }
973
974    fn call(
975        &mut self,
976        id: usize,
977        payload: &mut [u8],
978        metadata: &[u64],
979        ctx: &CallerCtx, // Only pid and id are correct here, uid/gid are not used
980    ) -> Result<usize> {
981        Err(Error::new(EOPNOTSUPP))
982    }
983
984    fn getdents<'buf>(
985        &mut self,
986        id: usize,
987        buf: DirentBuf<&'buf mut [u8]>,
988        opaque_offset: u64,
989    ) -> Result<DirentBuf<&'buf mut [u8]>> {
990        Err(Error::new(ENOTDIR))
991    }
992
993    fn mmap_prep(
994        &mut self,
995        id: usize,
996        offset: u64,
997        size: usize,
998        flags: MapFlags,
999        ctx: &CallerCtx,
1000    ) -> Result<usize> {
1001        Err(Error::new(EOPNOTSUPP))
1002    }
1003
1004    fn munmap(
1005        &mut self,
1006        id: usize,
1007        offset: u64,
1008        size: usize,
1009        flags: MunmapFlags,
1010        ctx: &CallerCtx,
1011    ) -> Result<()> {
1012        Err(Error::new(EOPNOTSUPP))
1013    }
1014
1015    fn on_close(&mut self, id: usize) {}
1016
1017    fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
1018        Err(Error::new(EOPNOTSUPP))
1019    }
1020}
1021pub trait IntoTag {
1022    fn into_tag(self) -> Tag;
1023    fn req_id(&self) -> Id;
1024}
1025impl IntoTag for Tag {
1026    fn into_tag(self) -> Tag {
1027        self
1028    }
1029    fn req_id(&self) -> Id {
1030        self.0
1031    }
1032}
1033impl IntoTag for CallRequest {
1034    fn into_tag(self) -> Tag {
1035        Tag(self.request_id())
1036    }
1037    fn req_id(&self) -> Id {
1038        self.request_id()
1039    }
1040}
1041impl IntoTag for SendFdRequest {
1042    fn into_tag(self) -> Tag {
1043        Tag(self.request_id())
1044    }
1045    fn req_id(&self) -> Id {
1046        self.request_id()
1047    }
1048}
1049macro_rules! trivial_into {
1050    [$($name:ident,)*] => {
1051        $(
1052        impl IntoTag for $name {
1053            #[inline]
1054            fn into_tag(self) -> Tag {
1055                self.req
1056            }
1057            #[inline]
1058            fn req_id(&self) -> Id {
1059                self.req.req_id()
1060            }
1061        }
1062        )*
1063    }
1064}
1065trivial_into![OpCall, OpRead, OpWrite, OpGetdents,];
1066impl<T: ?Sized> IntoTag for OpQueryWrite<T> {
1067    fn into_tag(self) -> Tag {
1068        self.req
1069    }
1070    fn req_id(&self) -> Id {
1071        self.req.0
1072    }
1073}
1074impl<T: ?Sized> IntoTag for OpQueryRead<T> {
1075    fn into_tag(self) -> Tag {
1076        self.req
1077    }
1078    fn req_id(&self) -> Id {
1079        self.req.0
1080    }
1081}
1082impl<F> IntoTag for OpPathLike<F> {
1083    fn into_tag(self) -> Tag {
1084        self.req
1085    }
1086    fn req_id(&self) -> Id {
1087        self.req.0
1088    }
1089}
1090impl<F> IntoTag for OpFdPathLike<F> {
1091    fn into_tag(self) -> Tag {
1092        self.inner.req
1093    }
1094    fn req_id(&self) -> Id {
1095        self.inner.req.0
1096    }
1097}
1098impl IntoTag for Op {
1099    fn into_tag(self) -> Tag {
1100        use Op::*;
1101        match self {
1102            Open(op) => op.into_tag(),
1103            OpenAt(op) => op.into_tag(),
1104            Rmdir(op) | Self::Unlink(op) => op.into_tag(),
1105            Dup(op) => op.into_tag(),
1106            Read(op) => op.into_tag(),
1107            Write(op) => op.into_tag(),
1108            Fsize { req, .. }
1109            | Fchmod { req, .. }
1110            | Fchown { req, .. }
1111            | Fcntl { req, .. }
1112            | Fevent { req, .. }
1113            | Fsync { req, .. }
1114            | Ftruncate { req, .. }
1115            | MmapPrep { req, .. }
1116            | Munmap { req, .. } => req,
1117            Flink(op) => op.into_tag(),
1118            Fpath(op) => op.into_tag(),
1119            Frename(op) => op.into_tag(),
1120            Fstat(op) => op.into_tag(),
1121            FstatVfs(op) => op.into_tag(),
1122            Futimens(op) => op.into_tag(),
1123            Call(op) => op.into_tag(),
1124            Getdents(op) => op.into_tag(),
1125        }
1126    }
1127    fn req_id(&self) -> Id {
1128        use Op::*;
1129        match self {
1130            Open(op) => op.req_id(),
1131            OpenAt(op) => op.req_id(),
1132            Rmdir(op) | Self::Unlink(op) => op.req_id(),
1133            Dup(op) => op.req_id(),
1134            Read(op) => op.req_id(),
1135            Write(op) => op.req_id(),
1136            Fsize { req, .. }
1137            | Fchmod { req, .. }
1138            | Fchown { req, .. }
1139            | Fcntl { req, .. }
1140            | Fevent { req, .. }
1141            | Fsync { req, .. }
1142            | Ftruncate { req, .. }
1143            | MmapPrep { req, .. }
1144            | Munmap { req, .. } => req.req_id(),
1145            Flink(op) => op.req_id(),
1146            Fpath(op) => op.req_id(),
1147            Frename(op) => op.req_id(),
1148            Fstat(op) => op.req_id(),
1149            FstatVfs(op) => op.req_id(),
1150            Futimens(op) => op.req_id(),
1151            Call(op) => op.req_id(),
1152            Getdents(op) => op.req_id(),
1153        }
1154    }
1155}