wasi_common/snapshots/
preview_0.rs

1use crate::file::TableFileExt;
2use crate::sched::{
3    Poll, Userdata,
4    subscription::{RwEventFlags, SubscriptionResult},
5};
6use crate::snapshots::preview_1::types as snapshot1_types;
7use crate::snapshots::preview_1::wasi_snapshot_preview1::WasiSnapshotPreview1 as Snapshot1;
8use crate::{ErrorExt, WasiCtx};
9use cap_std::time::Duration;
10use std::collections::HashSet;
11use wiggle::{GuestMemory, GuestPtr};
12
13wiggle::from_witx!({
14    witx: ["witx/preview0/wasi_unstable.witx"],
15    errors: { errno => trappable Error },
16    async: *,
17    wasmtime: false,
18});
19
20use types::Error;
21
22impl ErrorExt for Error {
23    fn not_found() -> Self {
24        types::Errno::Noent.into()
25    }
26    fn too_big() -> Self {
27        types::Errno::TooBig.into()
28    }
29    fn badf() -> Self {
30        types::Errno::Badf.into()
31    }
32    fn exist() -> Self {
33        types::Errno::Exist.into()
34    }
35    fn illegal_byte_sequence() -> Self {
36        types::Errno::Ilseq.into()
37    }
38    fn invalid_argument() -> Self {
39        types::Errno::Inval.into()
40    }
41    fn io() -> Self {
42        types::Errno::Io.into()
43    }
44    fn name_too_long() -> Self {
45        types::Errno::Nametoolong.into()
46    }
47    fn not_dir() -> Self {
48        types::Errno::Notdir.into()
49    }
50    fn not_supported() -> Self {
51        types::Errno::Notsup.into()
52    }
53    fn overflow() -> Self {
54        types::Errno::Overflow.into()
55    }
56    fn range() -> Self {
57        types::Errno::Range.into()
58    }
59    fn seek_pipe() -> Self {
60        types::Errno::Spipe.into()
61    }
62    fn perm() -> Self {
63        types::Errno::Perm.into()
64    }
65}
66
67impl wiggle::GuestErrorType for types::Errno {
68    fn success() -> Self {
69        Self::Success
70    }
71}
72
73impl From<wiggle::GuestError> for Error {
74    fn from(err: wiggle::GuestError) -> Error {
75        snapshot1_types::Error::from(err).into()
76    }
77}
78
79impl From<snapshot1_types::Error> for Error {
80    fn from(error: snapshot1_types::Error) -> Error {
81        match error.downcast() {
82            Ok(errno) => Error::from(types::Errno::from(errno)),
83            Err(trap) => Error::trap(trap),
84        }
85    }
86}
87
88impl From<std::num::TryFromIntError> for Error {
89    fn from(_err: std::num::TryFromIntError) -> Error {
90        types::Errno::Overflow.into()
91    }
92}
93
94// Type conversions
95// The vast majority of the types defined in `types` and `snapshot1_types` are identical. However,
96// since they are defined in separate places for mechanical (wiggle) reasons, we need to manually
97// define conversion functions between them.
98// Below we have defined these functions as they are needed.
99
100/// Fd is a newtype wrapper around u32. Unwrap and wrap it.
101impl From<types::Fd> for snapshot1_types::Fd {
102    fn from(fd: types::Fd) -> snapshot1_types::Fd {
103        u32::from(fd).into()
104    }
105}
106/// Fd is a newtype wrapper around u32. Unwrap and wrap it.
107impl From<snapshot1_types::Fd> for types::Fd {
108    fn from(fd: snapshot1_types::Fd) -> types::Fd {
109        u32::from(fd).into()
110    }
111}
112
113/// Trivial conversion between two c-style enums that have the exact same set of variants.
114/// Could we do something unsafe and not list all these variants out? Probably, but doing
115/// it this way doesn't bother me much. I copy-pasted the list of variants out of the
116/// rendered rustdocs.
117/// LLVM ought to compile these From impls into no-ops, inshallah
118macro_rules! convert_enum {
119    ($from:ty, $to:ty, $($var:ident),+) => {
120        impl From<$from> for $to {
121            fn from(e: $from) -> $to {
122                match e {
123                    $( <$from>::$var => <$to>::$var, )+
124                }
125            }
126        }
127    }
128}
129convert_enum!(
130    snapshot1_types::Errno,
131    types::Errno,
132    Success,
133    TooBig,
134    Acces,
135    Addrinuse,
136    Addrnotavail,
137    Afnosupport,
138    Again,
139    Already,
140    Badf,
141    Badmsg,
142    Busy,
143    Canceled,
144    Child,
145    Connaborted,
146    Connrefused,
147    Connreset,
148    Deadlk,
149    Destaddrreq,
150    Dom,
151    Dquot,
152    Exist,
153    Fault,
154    Fbig,
155    Hostunreach,
156    Idrm,
157    Ilseq,
158    Inprogress,
159    Intr,
160    Inval,
161    Io,
162    Isconn,
163    Isdir,
164    Loop,
165    Mfile,
166    Mlink,
167    Msgsize,
168    Multihop,
169    Nametoolong,
170    Netdown,
171    Netreset,
172    Netunreach,
173    Nfile,
174    Nobufs,
175    Nodev,
176    Noent,
177    Noexec,
178    Nolck,
179    Nolink,
180    Nomem,
181    Nomsg,
182    Noprotoopt,
183    Nospc,
184    Nosys,
185    Notconn,
186    Notdir,
187    Notempty,
188    Notrecoverable,
189    Notsock,
190    Notsup,
191    Notty,
192    Nxio,
193    Overflow,
194    Ownerdead,
195    Perm,
196    Pipe,
197    Proto,
198    Protonosupport,
199    Prototype,
200    Range,
201    Rofs,
202    Spipe,
203    Srch,
204    Stale,
205    Timedout,
206    Txtbsy,
207    Xdev,
208    Notcapable
209);
210convert_enum!(
211    types::Clockid,
212    snapshot1_types::Clockid,
213    Realtime,
214    Monotonic,
215    ProcessCputimeId,
216    ThreadCputimeId
217);
218
219convert_enum!(
220    types::Advice,
221    snapshot1_types::Advice,
222    Normal,
223    Sequential,
224    Random,
225    Willneed,
226    Dontneed,
227    Noreuse
228);
229convert_enum!(
230    snapshot1_types::Filetype,
231    types::Filetype,
232    Directory,
233    BlockDevice,
234    CharacterDevice,
235    RegularFile,
236    SocketDgram,
237    SocketStream,
238    SymbolicLink,
239    Unknown
240);
241convert_enum!(types::Whence, snapshot1_types::Whence, Cur, End, Set);
242
243/// Prestat isn't a c-style enum, its a union where the variant has a payload. Its the only one of
244/// those we need to convert, so write it by hand.
245impl From<snapshot1_types::Prestat> for types::Prestat {
246    fn from(p: snapshot1_types::Prestat) -> types::Prestat {
247        match p {
248            snapshot1_types::Prestat::Dir(d) => types::Prestat::Dir(d.into()),
249        }
250    }
251}
252
253/// Trivial conversion between two structs that have the exact same set of fields,
254/// with recursive descent into the field types.
255macro_rules! convert_struct {
256    ($from:ty, $to:path, $($field:ident),+) => {
257        impl From<$from> for $to {
258            fn from(e: $from) -> $to {
259                $to {
260                    $( $field: e.$field.into(), )+
261                }
262            }
263        }
264    }
265}
266
267convert_struct!(snapshot1_types::PrestatDir, types::PrestatDir, pr_name_len);
268convert_struct!(
269    snapshot1_types::Fdstat,
270    types::Fdstat,
271    fs_filetype,
272    fs_rights_base,
273    fs_rights_inheriting,
274    fs_flags
275);
276
277/// Snapshot1 Filestat is incompatible with Snapshot0 Filestat - the nlink
278/// field is u32 on this Filestat, and u64 on theirs. If you've got more than
279/// 2^32 links I don't know what to tell you
280impl From<snapshot1_types::Filestat> for types::Filestat {
281    fn from(f: snapshot1_types::Filestat) -> types::Filestat {
282        types::Filestat {
283            dev: f.dev,
284            ino: f.ino,
285            filetype: f.filetype.into(),
286            nlink: f.nlink.try_into().unwrap_or(u32::MAX),
287            size: f.size,
288            atim: f.atim,
289            mtim: f.mtim,
290            ctim: f.ctim,
291        }
292    }
293}
294
295/// Trivial conversion between two bitflags that have the exact same set of flags.
296macro_rules! convert_flags {
297    ($from:ty, $to:ty, $($flag:ident),+) => {
298        impl From<$from> for $to {
299            fn from(f: $from) -> $to {
300                let mut out = <$to>::empty();
301                $(
302                    if f.contains(<$from>::$flag) {
303                        out |= <$to>::$flag;
304                    }
305                )+
306                out
307            }
308        }
309    }
310}
311
312/// Need to convert in both directions? This saves listing out the flags twice
313macro_rules! convert_flags_bidirectional {
314    ($from:ty, $to:ty, $($flag:tt)*) => {
315        convert_flags!($from, $to, $($flag)*);
316        convert_flags!($to, $from, $($flag)*);
317    }
318}
319
320convert_flags_bidirectional!(
321    snapshot1_types::Fdflags,
322    types::Fdflags,
323    APPEND,
324    DSYNC,
325    NONBLOCK,
326    RSYNC,
327    SYNC
328);
329convert_flags!(
330    types::Lookupflags,
331    snapshot1_types::Lookupflags,
332    SYMLINK_FOLLOW
333);
334convert_flags!(
335    types::Fstflags,
336    snapshot1_types::Fstflags,
337    ATIM,
338    ATIM_NOW,
339    MTIM,
340    MTIM_NOW
341);
342convert_flags!(
343    types::Oflags,
344    snapshot1_types::Oflags,
345    CREAT,
346    DIRECTORY,
347    EXCL,
348    TRUNC
349);
350convert_flags_bidirectional!(
351    types::Rights,
352    snapshot1_types::Rights,
353    FD_DATASYNC,
354    FD_READ,
355    FD_SEEK,
356    FD_FDSTAT_SET_FLAGS,
357    FD_SYNC,
358    FD_TELL,
359    FD_WRITE,
360    FD_ADVISE,
361    FD_ALLOCATE,
362    PATH_CREATE_DIRECTORY,
363    PATH_CREATE_FILE,
364    PATH_LINK_SOURCE,
365    PATH_LINK_TARGET,
366    PATH_OPEN,
367    FD_READDIR,
368    PATH_READLINK,
369    PATH_RENAME_SOURCE,
370    PATH_RENAME_TARGET,
371    PATH_FILESTAT_GET,
372    PATH_FILESTAT_SET_SIZE,
373    PATH_FILESTAT_SET_TIMES,
374    FD_FILESTAT_GET,
375    FD_FILESTAT_SET_SIZE,
376    FD_FILESTAT_SET_TIMES,
377    PATH_SYMLINK,
378    PATH_REMOVE_DIRECTORY,
379    PATH_UNLINK_FILE,
380    POLL_FD_READWRITE,
381    SOCK_SHUTDOWN
382);
383
384// This implementation, wherever possible, delegates directly to the Snapshot1 implementation,
385// performing the no-op type conversions along the way.
386impl wasi_unstable::WasiUnstable for WasiCtx {
387    async fn args_get(
388        &mut self,
389        memory: &mut GuestMemory<'_>,
390        argv: GuestPtr<GuestPtr<u8>>,
391        argv_buf: GuestPtr<u8>,
392    ) -> Result<(), Error> {
393        Snapshot1::args_get(self, memory, argv, argv_buf).await?;
394        Ok(())
395    }
396
397    async fn args_sizes_get(
398        &mut self,
399        memory: &mut GuestMemory<'_>,
400    ) -> Result<(types::Size, types::Size), Error> {
401        let s = Snapshot1::args_sizes_get(self, memory).await?;
402        Ok(s)
403    }
404
405    async fn environ_get(
406        &mut self,
407        memory: &mut GuestMemory<'_>,
408        environ: GuestPtr<GuestPtr<u8>>,
409        environ_buf: GuestPtr<u8>,
410    ) -> Result<(), Error> {
411        Snapshot1::environ_get(self, memory, environ, environ_buf).await?;
412        Ok(())
413    }
414
415    async fn environ_sizes_get(
416        &mut self,
417        memory: &mut GuestMemory<'_>,
418    ) -> Result<(types::Size, types::Size), Error> {
419        let s = Snapshot1::environ_sizes_get(self, memory).await?;
420        Ok(s)
421    }
422
423    async fn clock_res_get(
424        &mut self,
425        memory: &mut GuestMemory<'_>,
426        id: types::Clockid,
427    ) -> Result<types::Timestamp, Error> {
428        let t = Snapshot1::clock_res_get(self, memory, id.into()).await?;
429        Ok(t)
430    }
431
432    async fn clock_time_get(
433        &mut self,
434        memory: &mut GuestMemory<'_>,
435        id: types::Clockid,
436        precision: types::Timestamp,
437    ) -> Result<types::Timestamp, Error> {
438        let t = Snapshot1::clock_time_get(self, memory, id.into(), precision).await?;
439        Ok(t)
440    }
441
442    async fn fd_advise(
443        &mut self,
444        memory: &mut GuestMemory<'_>,
445        fd: types::Fd,
446        offset: types::Filesize,
447        len: types::Filesize,
448        advice: types::Advice,
449    ) -> Result<(), Error> {
450        Snapshot1::fd_advise(self, memory, fd.into(), offset, len, advice.into()).await?;
451        Ok(())
452    }
453
454    async fn fd_allocate(
455        &mut self,
456        memory: &mut GuestMemory<'_>,
457        fd: types::Fd,
458        offset: types::Filesize,
459        len: types::Filesize,
460    ) -> Result<(), Error> {
461        Snapshot1::fd_allocate(self, memory, fd.into(), offset, len).await?;
462        Ok(())
463    }
464
465    async fn fd_close(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
466        Snapshot1::fd_close(self, memory, fd.into()).await?;
467        Ok(())
468    }
469
470    async fn fd_datasync(
471        &mut self,
472        memory: &mut GuestMemory<'_>,
473        fd: types::Fd,
474    ) -> Result<(), Error> {
475        Snapshot1::fd_datasync(self, memory, fd.into()).await?;
476        Ok(())
477    }
478
479    async fn fd_fdstat_get(
480        &mut self,
481        memory: &mut GuestMemory<'_>,
482        fd: types::Fd,
483    ) -> Result<types::Fdstat, Error> {
484        Ok(Snapshot1::fd_fdstat_get(self, memory, fd.into())
485            .await?
486            .into())
487    }
488
489    async fn fd_fdstat_set_flags(
490        &mut self,
491        memory: &mut GuestMemory<'_>,
492        fd: types::Fd,
493        flags: types::Fdflags,
494    ) -> Result<(), Error> {
495        Snapshot1::fd_fdstat_set_flags(self, memory, fd.into(), flags.into()).await?;
496        Ok(())
497    }
498
499    async fn fd_fdstat_set_rights(
500        &mut self,
501        memory: &mut GuestMemory<'_>,
502        fd: types::Fd,
503        fs_rights_base: types::Rights,
504        fs_rights_inheriting: types::Rights,
505    ) -> Result<(), Error> {
506        Snapshot1::fd_fdstat_set_rights(
507            self,
508            memory,
509            fd.into(),
510            fs_rights_base.into(),
511            fs_rights_inheriting.into(),
512        )
513        .await?;
514        Ok(())
515    }
516
517    async fn fd_filestat_get(
518        &mut self,
519        memory: &mut GuestMemory<'_>,
520        fd: types::Fd,
521    ) -> Result<types::Filestat, Error> {
522        Ok(Snapshot1::fd_filestat_get(self, memory, fd.into())
523            .await?
524            .into())
525    }
526
527    async fn fd_filestat_set_size(
528        &mut self,
529        memory: &mut GuestMemory<'_>,
530        fd: types::Fd,
531        size: types::Filesize,
532    ) -> Result<(), Error> {
533        Snapshot1::fd_filestat_set_size(self, memory, fd.into(), size).await?;
534        Ok(())
535    }
536
537    async fn fd_filestat_set_times(
538        &mut self,
539        memory: &mut GuestMemory<'_>,
540        fd: types::Fd,
541        atim: types::Timestamp,
542        mtim: types::Timestamp,
543        fst_flags: types::Fstflags,
544    ) -> Result<(), Error> {
545        Snapshot1::fd_filestat_set_times(self, memory, fd.into(), atim, mtim, fst_flags.into())
546            .await?;
547        Ok(())
548    }
549
550    // NOTE on fd_read, fd_pread, fd_write, fd_pwrite implementations:
551    // these cast their pointers from preview0 vectors to preview1 vectors and
552    // this only works because the representation didn't change between preview0
553    // and preview1.
554
555    async fn fd_read(
556        &mut self,
557        memory: &mut GuestMemory<'_>,
558        fd: types::Fd,
559        iovs: types::IovecArray,
560    ) -> Result<types::Size, Error> {
561        Ok(Snapshot1::fd_read(self, memory, fd.into(), iovs.cast()).await?)
562    }
563
564    async fn fd_pread(
565        &mut self,
566        memory: &mut GuestMemory<'_>,
567        fd: types::Fd,
568        iovs: types::IovecArray,
569        offset: types::Filesize,
570    ) -> Result<types::Size, Error> {
571        Ok(Snapshot1::fd_pread(self, memory, fd.into(), iovs.cast(), offset).await?)
572    }
573
574    async fn fd_write(
575        &mut self,
576        memory: &mut GuestMemory<'_>,
577        fd: types::Fd,
578        ciovs: types::CiovecArray,
579    ) -> Result<types::Size, Error> {
580        Ok(Snapshot1::fd_write(self, memory, fd.into(), ciovs.cast()).await?)
581    }
582
583    async fn fd_pwrite(
584        &mut self,
585        memory: &mut GuestMemory<'_>,
586        fd: types::Fd,
587        ciovs: types::CiovecArray,
588        offset: types::Filesize,
589    ) -> Result<types::Size, Error> {
590        Ok(Snapshot1::fd_pwrite(self, memory, fd.into(), ciovs.cast(), offset).await?)
591    }
592
593    async fn fd_prestat_get(
594        &mut self,
595        memory: &mut GuestMemory<'_>,
596        fd: types::Fd,
597    ) -> Result<types::Prestat, Error> {
598        Ok(Snapshot1::fd_prestat_get(self, memory, fd.into())
599            .await?
600            .into())
601    }
602
603    async fn fd_prestat_dir_name(
604        &mut self,
605        memory: &mut GuestMemory<'_>,
606        fd: types::Fd,
607        path: GuestPtr<u8>,
608        path_max_len: types::Size,
609    ) -> Result<(), Error> {
610        Snapshot1::fd_prestat_dir_name(self, memory, fd.into(), path, path_max_len).await?;
611        Ok(())
612    }
613
614    async fn fd_renumber(
615        &mut self,
616        memory: &mut GuestMemory<'_>,
617        from: types::Fd,
618        to: types::Fd,
619    ) -> Result<(), Error> {
620        Snapshot1::fd_renumber(self, memory, from.into(), to.into()).await?;
621        Ok(())
622    }
623
624    async fn fd_seek(
625        &mut self,
626        memory: &mut GuestMemory<'_>,
627        fd: types::Fd,
628        offset: types::Filedelta,
629        whence: types::Whence,
630    ) -> Result<types::Filesize, Error> {
631        Ok(Snapshot1::fd_seek(self, memory, fd.into(), offset, whence.into()).await?)
632    }
633
634    async fn fd_sync(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
635        Snapshot1::fd_sync(self, memory, fd.into()).await?;
636        Ok(())
637    }
638
639    async fn fd_tell(
640        &mut self,
641        memory: &mut GuestMemory<'_>,
642        fd: types::Fd,
643    ) -> Result<types::Filesize, Error> {
644        Ok(Snapshot1::fd_tell(self, memory, fd.into()).await?)
645    }
646
647    async fn fd_readdir(
648        &mut self,
649        memory: &mut GuestMemory<'_>,
650        fd: types::Fd,
651        buf: GuestPtr<u8>,
652        buf_len: types::Size,
653        cookie: types::Dircookie,
654    ) -> Result<types::Size, Error> {
655        Ok(Snapshot1::fd_readdir(self, memory, fd.into(), buf, buf_len, cookie).await?)
656    }
657
658    async fn path_create_directory(
659        &mut self,
660        memory: &mut GuestMemory<'_>,
661        dirfd: types::Fd,
662        path: GuestPtr<str>,
663    ) -> Result<(), Error> {
664        Snapshot1::path_create_directory(self, memory, dirfd.into(), path).await?;
665        Ok(())
666    }
667
668    async fn path_filestat_get(
669        &mut self,
670        memory: &mut GuestMemory<'_>,
671        dirfd: types::Fd,
672        flags: types::Lookupflags,
673        path: GuestPtr<str>,
674    ) -> Result<types::Filestat, Error> {
675        Ok(
676            Snapshot1::path_filestat_get(self, memory, dirfd.into(), flags.into(), path)
677                .await?
678                .into(),
679        )
680    }
681
682    async fn path_filestat_set_times(
683        &mut self,
684        memory: &mut GuestMemory<'_>,
685        dirfd: types::Fd,
686        flags: types::Lookupflags,
687        path: GuestPtr<str>,
688        atim: types::Timestamp,
689        mtim: types::Timestamp,
690        fst_flags: types::Fstflags,
691    ) -> Result<(), Error> {
692        Snapshot1::path_filestat_set_times(
693            self,
694            memory,
695            dirfd.into(),
696            flags.into(),
697            path,
698            atim,
699            mtim,
700            fst_flags.into(),
701        )
702        .await?;
703        Ok(())
704    }
705
706    async fn path_link(
707        &mut self,
708        memory: &mut GuestMemory<'_>,
709        src_fd: types::Fd,
710        src_flags: types::Lookupflags,
711        src_path: GuestPtr<str>,
712        target_fd: types::Fd,
713        target_path: GuestPtr<str>,
714    ) -> Result<(), Error> {
715        Snapshot1::path_link(
716            self,
717            memory,
718            src_fd.into(),
719            src_flags.into(),
720            src_path,
721            target_fd.into(),
722            target_path,
723        )
724        .await?;
725        Ok(())
726    }
727
728    async fn path_open(
729        &mut self,
730        memory: &mut GuestMemory<'_>,
731        dirfd: types::Fd,
732        dirflags: types::Lookupflags,
733        path: GuestPtr<str>,
734        oflags: types::Oflags,
735        fs_rights_base: types::Rights,
736        fs_rights_inheriting: types::Rights,
737        fdflags: types::Fdflags,
738    ) -> Result<types::Fd, Error> {
739        Ok(Snapshot1::path_open(
740            self,
741            memory,
742            dirfd.into(),
743            dirflags.into(),
744            path,
745            oflags.into(),
746            fs_rights_base.into(),
747            fs_rights_inheriting.into(),
748            fdflags.into(),
749        )
750        .await?
751        .into())
752    }
753
754    async fn path_readlink(
755        &mut self,
756        memory: &mut GuestMemory<'_>,
757        dirfd: types::Fd,
758        path: GuestPtr<str>,
759        buf: GuestPtr<u8>,
760        buf_len: types::Size,
761    ) -> Result<types::Size, Error> {
762        Ok(Snapshot1::path_readlink(self, memory, dirfd.into(), path, buf, buf_len).await?)
763    }
764
765    async fn path_remove_directory(
766        &mut self,
767        memory: &mut GuestMemory<'_>,
768        dirfd: types::Fd,
769        path: GuestPtr<str>,
770    ) -> Result<(), Error> {
771        Snapshot1::path_remove_directory(self, memory, dirfd.into(), path).await?;
772        Ok(())
773    }
774
775    async fn path_rename(
776        &mut self,
777        memory: &mut GuestMemory<'_>,
778        src_fd: types::Fd,
779        src_path: GuestPtr<str>,
780        dest_fd: types::Fd,
781        dest_path: GuestPtr<str>,
782    ) -> Result<(), Error> {
783        Snapshot1::path_rename(
784            self,
785            memory,
786            src_fd.into(),
787            src_path,
788            dest_fd.into(),
789            dest_path,
790        )
791        .await?;
792        Ok(())
793    }
794
795    async fn path_symlink(
796        &mut self,
797        memory: &mut GuestMemory<'_>,
798        src_path: GuestPtr<str>,
799        dirfd: types::Fd,
800        dest_path: GuestPtr<str>,
801    ) -> Result<(), Error> {
802        Snapshot1::path_symlink(self, memory, src_path, dirfd.into(), dest_path).await?;
803        Ok(())
804    }
805
806    async fn path_unlink_file(
807        &mut self,
808        memory: &mut GuestMemory<'_>,
809        dirfd: types::Fd,
810        path: GuestPtr<str>,
811    ) -> Result<(), Error> {
812        Snapshot1::path_unlink_file(self, memory, dirfd.into(), path).await?;
813        Ok(())
814    }
815
816    // NOTE on poll_oneoff implementation:
817    // Like fd_write and friends, the arguments and return values are behind GuestPtrs,
818    // so they are not values we can convert and pass to the poll_oneoff in Snapshot1.
819    // Instead, we have copied the implementation of these functions from the Snapshot1 code.
820    // The implementations are identical, but the `types::` in scope locally is different.
821    // The bodies of these functions is mostly about converting the GuestPtr and types::-based
822    // representation to use the Poll abstraction.
823    async fn poll_oneoff(
824        &mut self,
825        memory: &mut GuestMemory<'_>,
826        subs: GuestPtr<types::Subscription>,
827        events: GuestPtr<types::Event>,
828        nsubscriptions: types::Size,
829    ) -> Result<types::Size, Error> {
830        if nsubscriptions == 0 {
831            return Err(Error::invalid_argument().context("nsubscriptions must be nonzero"));
832        }
833
834        // Special-case a `poll_oneoff` which is just sleeping on a single
835        // relative timer event, such as what WASI libc uses to implement sleep
836        // functions. This supports all clock IDs, because POSIX says that
837        // `clock_settime` doesn't effect relative sleeps.
838        if nsubscriptions == 1 {
839            let sub = memory.read(subs)?;
840            if let types::SubscriptionU::Clock(clocksub) = sub.u {
841                if !clocksub
842                    .flags
843                    .contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)
844                {
845                    self.sched
846                        .sleep(Duration::from_nanos(clocksub.timeout))
847                        .await?;
848                    memory.write(
849                        events,
850                        types::Event {
851                            userdata: sub.userdata,
852                            error: types::Errno::Success,
853                            type_: types::Eventtype::Clock,
854                            fd_readwrite: fd_readwrite_empty(),
855                        },
856                    )?;
857                    return Ok(1);
858                }
859            }
860        }
861
862        let table = &self.table;
863        let mut sub_fds: HashSet<types::Fd> = HashSet::new();
864        // We need these refmuts to outlive Poll, which will hold the &mut dyn WasiFile inside
865        let mut reads: Vec<(u32, Userdata)> = Vec::new();
866        let mut writes: Vec<(u32, Userdata)> = Vec::new();
867        let mut poll = Poll::new();
868
869        let subs = subs.as_array(nsubscriptions);
870        for sub_elem in subs.iter() {
871            let sub_ptr = sub_elem?;
872            let sub = memory.read(sub_ptr)?;
873            match sub.u {
874                types::SubscriptionU::Clock(clocksub) => match clocksub.id {
875                    types::Clockid::Monotonic => {
876                        let clock = self.clocks.monotonic()?;
877                        let precision = Duration::from_nanos(clocksub.precision);
878                        let duration = Duration::from_nanos(clocksub.timeout);
879                        let start = if clocksub
880                            .flags
881                            .contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)
882                        {
883                            clock.creation_time
884                        } else {
885                            clock.abs_clock.now(precision)
886                        };
887                        let deadline = start
888                            .checked_add(duration)
889                            .ok_or_else(|| Error::overflow().context("deadline"))?;
890                        poll.subscribe_monotonic_clock(
891                            &*clock.abs_clock,
892                            deadline,
893                            precision,
894                            sub.userdata.into(),
895                        )
896                    }
897                    _ => Err(Error::invalid_argument()
898                        .context("timer subscriptions only support monotonic timer"))?,
899                },
900                types::SubscriptionU::FdRead(readsub) => {
901                    let fd = readsub.file_descriptor;
902                    if sub_fds.contains(&fd) {
903                        return Err(Error::invalid_argument()
904                            .context("Fd can be subscribed to at most once per poll"));
905                    } else {
906                        sub_fds.insert(fd);
907                    }
908                    table.get_file(u32::from(fd))?;
909                    reads.push((u32::from(fd), sub.userdata.into()));
910                }
911                types::SubscriptionU::FdWrite(writesub) => {
912                    let fd = writesub.file_descriptor;
913                    if sub_fds.contains(&fd) {
914                        return Err(Error::invalid_argument()
915                            .context("Fd can be subscribed to at most once per poll"));
916                    } else {
917                        sub_fds.insert(fd);
918                    }
919                    table.get_file(u32::from(fd))?;
920                    writes.push((u32::from(fd), sub.userdata.into()));
921                }
922            }
923        }
924
925        self.sched.poll_oneoff(&mut poll).await?;
926
927        let results = poll.results();
928        let num_results = results.len();
929        assert!(
930            num_results <= nsubscriptions as usize,
931            "results exceeds subscriptions"
932        );
933        let events = events.as_array(
934            num_results
935                .try_into()
936                .expect("not greater than nsubscriptions"),
937        );
938        for ((result, userdata), event_elem) in results.into_iter().zip(events.iter()) {
939            let event_ptr = event_elem?;
940            let userdata: types::Userdata = userdata.into();
941            memory.write(
942                event_ptr,
943                match result {
944                    SubscriptionResult::Read(r) => {
945                        let type_ = types::Eventtype::FdRead;
946                        match r {
947                            Ok((nbytes, flags)) => types::Event {
948                                userdata,
949                                error: types::Errno::Success,
950                                type_,
951                                fd_readwrite: types::EventFdReadwrite {
952                                    nbytes,
953                                    flags: types::Eventrwflags::from(&flags),
954                                },
955                            },
956                            Err(e) => types::Event {
957                                userdata,
958                                error: types::Errno::from(e.downcast().map_err(Error::trap)?),
959                                type_,
960                                fd_readwrite: fd_readwrite_empty(),
961                            },
962                        }
963                    }
964                    SubscriptionResult::Write(r) => {
965                        let type_ = types::Eventtype::FdWrite;
966                        match r {
967                            Ok((nbytes, flags)) => types::Event {
968                                userdata,
969                                error: types::Errno::Success,
970                                type_,
971                                fd_readwrite: types::EventFdReadwrite {
972                                    nbytes,
973                                    flags: types::Eventrwflags::from(&flags),
974                                },
975                            },
976                            Err(e) => types::Event {
977                                userdata,
978                                error: types::Errno::from(e.downcast().map_err(Error::trap)?),
979                                type_,
980                                fd_readwrite: fd_readwrite_empty(),
981                            },
982                        }
983                    }
984                    SubscriptionResult::MonotonicClock(r) => {
985                        let type_ = types::Eventtype::Clock;
986                        types::Event {
987                            userdata,
988                            error: match r {
989                                Ok(()) => types::Errno::Success,
990                                Err(e) => types::Errno::from(e.downcast().map_err(Error::trap)?),
991                            },
992                            type_,
993                            fd_readwrite: fd_readwrite_empty(),
994                        }
995                    }
996                },
997            )?;
998        }
999
1000        Ok(num_results.try_into().expect("results fit into memory"))
1001    }
1002
1003    async fn proc_exit(
1004        &mut self,
1005        memory: &mut GuestMemory<'_>,
1006        status: types::Exitcode,
1007    ) -> anyhow::Error {
1008        Snapshot1::proc_exit(self, memory, status).await
1009    }
1010
1011    async fn proc_raise(
1012        &mut self,
1013        _memory: &mut GuestMemory<'_>,
1014        _sig: types::Signal,
1015    ) -> Result<(), Error> {
1016        Err(Error::trap(anyhow::Error::msg("proc_raise unsupported")))
1017    }
1018
1019    async fn sched_yield(&mut self, memory: &mut GuestMemory<'_>) -> Result<(), Error> {
1020        Snapshot1::sched_yield(self, memory).await?;
1021        Ok(())
1022    }
1023
1024    async fn random_get(
1025        &mut self,
1026        memory: &mut GuestMemory<'_>,
1027        buf: GuestPtr<u8>,
1028        buf_len: types::Size,
1029    ) -> Result<(), Error> {
1030        Snapshot1::random_get(self, memory, buf, buf_len).await?;
1031        Ok(())
1032    }
1033
1034    async fn sock_recv(
1035        &mut self,
1036        _memory: &mut GuestMemory<'_>,
1037        _fd: types::Fd,
1038        _ri_data: types::IovecArray,
1039        _ri_flags: types::Riflags,
1040    ) -> Result<(types::Size, types::Roflags), Error> {
1041        Err(Error::trap(anyhow::Error::msg("sock_recv unsupported")))
1042    }
1043
1044    async fn sock_send(
1045        &mut self,
1046        _memory: &mut GuestMemory<'_>,
1047        _fd: types::Fd,
1048        _si_data: types::CiovecArray,
1049        _si_flags: types::Siflags,
1050    ) -> Result<types::Size, Error> {
1051        Err(Error::trap(anyhow::Error::msg("sock_send unsupported")))
1052    }
1053
1054    async fn sock_shutdown(
1055        &mut self,
1056        _memory: &mut GuestMemory<'_>,
1057        _fd: types::Fd,
1058        _how: types::Sdflags,
1059    ) -> Result<(), Error> {
1060        Err(Error::trap(anyhow::Error::msg("sock_shutdown unsupported")))
1061    }
1062}
1063
1064impl From<&RwEventFlags> for types::Eventrwflags {
1065    fn from(flags: &RwEventFlags) -> types::Eventrwflags {
1066        let mut out = types::Eventrwflags::empty();
1067        if flags.contains(RwEventFlags::HANGUP) {
1068            out = out | types::Eventrwflags::FD_READWRITE_HANGUP;
1069        }
1070        out
1071    }
1072}
1073
1074fn fd_readwrite_empty() -> types::EventFdReadwrite {
1075    types::EventFdReadwrite {
1076        nbytes: 0,
1077        flags: types::Eventrwflags::empty(),
1078    }
1079}