Skip to main content

wasmtime_wasi/
p0.rs

1//! Bindings for WASIp0 aka Preview 0 aka `wasi_unstable`.
2//!
3//! This module is purely here for backwards compatibility in the Wasmtime CLI.
4//! You probably want to use [`p1`](crate::p1) instead.
5
6use crate::p0::types::Error;
7use crate::p1::WasiP1Ctx;
8use crate::p1::types as snapshot1_types;
9use crate::p1::wasi_snapshot_preview1::WasiSnapshotPreview1 as Snapshot1;
10use wiggle::{GuestError, GuestMemory, GuestPtr};
11
12pub fn add_to_linker_async<T: Send + 'static>(
13    linker: &mut wasmtime::Linker<T>,
14    f: impl Fn(&mut T) -> &mut WasiP1Ctx + Copy + Send + Sync + 'static,
15) -> wasmtime::Result<()> {
16    wasi_unstable::add_to_linker(linker, f)
17}
18
19pub fn add_to_linker_sync<T: Send + 'static>(
20    linker: &mut wasmtime::Linker<T>,
21    f: impl Fn(&mut T) -> &mut WasiP1Ctx + Copy + Send + Sync + 'static,
22) -> wasmtime::Result<()> {
23    sync::add_wasi_unstable_to_linker(linker, f)
24}
25
26wiggle::from_witx!({
27    witx: ["witx/p0/wasi_unstable.witx"],
28    async: {
29        wasi_unstable::{
30            fd_advise, fd_close, fd_datasync, fd_fdstat_get, fd_filestat_get, fd_filestat_set_size,
31            fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write,
32            fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get,
33            path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory,
34            path_rename, path_symlink, path_unlink_file
35        }
36    },
37    errors: { errno => trappable Error },
38});
39
40mod sync {
41    use std::future::Future;
42    use wasmtime::Result;
43
44    wiggle::wasmtime_integration!({
45        witx: ["witx/p0/wasi_unstable.witx"],
46        target: super,
47        block_on[in_tokio]: {
48            wasi_unstable::{
49                fd_advise, fd_close, fd_datasync, fd_fdstat_get, fd_filestat_get, fd_filestat_set_size,
50                fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write,
51                fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get,
52                path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory,
53                path_rename, path_symlink, path_unlink_file
54            }
55        },
56        errors: { errno => trappable Error },
57    });
58
59    // Small wrapper around `in_tokio` to add a `Result` layer which is always
60    // `Ok`
61    fn in_tokio<F: Future>(future: F) -> Result<F::Output> {
62        Ok(crate::runtime::in_tokio(future))
63    }
64}
65
66impl wiggle::GuestErrorType for types::Errno {
67    fn success() -> Self {
68        Self::Success
69    }
70}
71
72impl<T: Snapshot1 + Send> wasi_unstable::WasiUnstable for T {
73    fn args_get(
74        &mut self,
75        memory: &mut GuestMemory<'_>,
76        argv: GuestPtr<GuestPtr<u8>>,
77        argv_buf: GuestPtr<u8>,
78    ) -> Result<(), Error> {
79        Snapshot1::args_get(self, memory, argv, argv_buf)?;
80        Ok(())
81    }
82
83    fn args_sizes_get(
84        &mut self,
85        memory: &mut GuestMemory<'_>,
86    ) -> Result<(types::Size, types::Size), Error> {
87        let s = Snapshot1::args_sizes_get(self, memory)?;
88        Ok(s)
89    }
90
91    fn environ_get(
92        &mut self,
93        memory: &mut GuestMemory<'_>,
94        environ: GuestPtr<GuestPtr<u8>>,
95        environ_buf: GuestPtr<u8>,
96    ) -> Result<(), Error> {
97        Snapshot1::environ_get(self, memory, environ, environ_buf)?;
98        Ok(())
99    }
100
101    fn environ_sizes_get(
102        &mut self,
103        memory: &mut GuestMemory<'_>,
104    ) -> Result<(types::Size, types::Size), Error> {
105        let s = Snapshot1::environ_sizes_get(self, memory)?;
106        Ok(s)
107    }
108
109    fn clock_res_get(
110        &mut self,
111        memory: &mut GuestMemory<'_>,
112        id: types::Clockid,
113    ) -> Result<types::Timestamp, Error> {
114        let t = Snapshot1::clock_res_get(self, memory, id.into())?;
115        Ok(t)
116    }
117
118    fn clock_time_get(
119        &mut self,
120        memory: &mut GuestMemory<'_>,
121        id: types::Clockid,
122        precision: types::Timestamp,
123    ) -> Result<types::Timestamp, Error> {
124        let t = Snapshot1::clock_time_get(self, memory, id.into(), precision)?;
125        Ok(t)
126    }
127
128    async fn fd_advise(
129        &mut self,
130        memory: &mut GuestMemory<'_>,
131        fd: types::Fd,
132        offset: types::Filesize,
133        len: types::Filesize,
134        advice: types::Advice,
135    ) -> Result<(), Error> {
136        Snapshot1::fd_advise(self, memory, fd.into(), offset, len, advice.into()).await?;
137        Ok(())
138    }
139
140    fn fd_allocate(
141        &mut self,
142        memory: &mut GuestMemory<'_>,
143        fd: types::Fd,
144        offset: types::Filesize,
145        len: types::Filesize,
146    ) -> Result<(), Error> {
147        Snapshot1::fd_allocate(self, memory, fd.into(), offset, len)?;
148        Ok(())
149    }
150
151    async fn fd_close(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
152        Snapshot1::fd_close(self, memory, fd.into()).await?;
153        Ok(())
154    }
155
156    async fn fd_datasync(
157        &mut self,
158        memory: &mut GuestMemory<'_>,
159        fd: types::Fd,
160    ) -> Result<(), Error> {
161        Snapshot1::fd_datasync(self, memory, fd.into()).await?;
162        Ok(())
163    }
164
165    async fn fd_fdstat_get(
166        &mut self,
167        memory: &mut GuestMemory<'_>,
168        fd: types::Fd,
169    ) -> Result<types::Fdstat, Error> {
170        Ok(Snapshot1::fd_fdstat_get(self, memory, fd.into())
171            .await?
172            .into())
173    }
174
175    fn fd_fdstat_set_flags(
176        &mut self,
177        memory: &mut GuestMemory<'_>,
178        fd: types::Fd,
179        flags: types::Fdflags,
180    ) -> Result<(), Error> {
181        Snapshot1::fd_fdstat_set_flags(self, memory, fd.into(), flags.into())?;
182        Ok(())
183    }
184
185    fn fd_fdstat_set_rights(
186        &mut self,
187        memory: &mut GuestMemory<'_>,
188        fd: types::Fd,
189        fs_rights_base: types::Rights,
190        fs_rights_inheriting: types::Rights,
191    ) -> Result<(), Error> {
192        Snapshot1::fd_fdstat_set_rights(
193            self,
194            memory,
195            fd.into(),
196            fs_rights_base.into(),
197            fs_rights_inheriting.into(),
198        )?;
199        Ok(())
200    }
201
202    async fn fd_filestat_get(
203        &mut self,
204        memory: &mut GuestMemory<'_>,
205        fd: types::Fd,
206    ) -> Result<types::Filestat, Error> {
207        Ok(Snapshot1::fd_filestat_get(self, memory, fd.into())
208            .await?
209            .into())
210    }
211
212    async fn fd_filestat_set_size(
213        &mut self,
214        memory: &mut GuestMemory<'_>,
215        fd: types::Fd,
216        size: types::Filesize,
217    ) -> Result<(), Error> {
218        Snapshot1::fd_filestat_set_size(self, memory, fd.into(), size).await?;
219        Ok(())
220    }
221
222    async fn fd_filestat_set_times(
223        &mut self,
224        memory: &mut GuestMemory<'_>,
225        fd: types::Fd,
226        atim: types::Timestamp,
227        mtim: types::Timestamp,
228        fst_flags: types::Fstflags,
229    ) -> Result<(), Error> {
230        Snapshot1::fd_filestat_set_times(self, memory, fd.into(), atim, mtim, fst_flags.into())
231            .await?;
232        Ok(())
233    }
234
235    async fn fd_read(
236        &mut self,
237        memory: &mut GuestMemory<'_>,
238        fd: types::Fd,
239        iovs: types::IovecArray,
240    ) -> Result<types::Size, Error> {
241        assert_iovec_array_same();
242        let result = Snapshot1::fd_read(self, memory, fd.into(), iovs.cast()).await?;
243        Ok(result)
244    }
245
246    async fn fd_pread(
247        &mut self,
248        memory: &mut GuestMemory<'_>,
249        fd: types::Fd,
250        iovs: types::IovecArray,
251        offset: types::Filesize,
252    ) -> Result<types::Size, Error> {
253        assert_iovec_array_same();
254        let result = Snapshot1::fd_pread(self, memory, fd.into(), iovs.cast(), offset).await?;
255        Ok(result)
256    }
257
258    async fn fd_write(
259        &mut self,
260        memory: &mut GuestMemory<'_>,
261        fd: types::Fd,
262        ciovs: types::CiovecArray,
263    ) -> Result<types::Size, Error> {
264        assert_ciovec_array_same();
265        let result = Snapshot1::fd_write(self, memory, fd.into(), ciovs.cast()).await?;
266        Ok(result)
267    }
268
269    async fn fd_pwrite(
270        &mut self,
271        memory: &mut GuestMemory<'_>,
272        fd: types::Fd,
273        ciovs: types::CiovecArray,
274        offset: types::Filesize,
275    ) -> Result<types::Size, Error> {
276        assert_ciovec_array_same();
277        let result = Snapshot1::fd_pwrite(self, memory, fd.into(), ciovs.cast(), offset).await?;
278        Ok(result)
279    }
280
281    fn fd_prestat_get(
282        &mut self,
283        memory: &mut GuestMemory<'_>,
284        fd: types::Fd,
285    ) -> Result<types::Prestat, Error> {
286        Ok(Snapshot1::fd_prestat_get(self, memory, fd.into())?.into())
287    }
288
289    fn fd_prestat_dir_name(
290        &mut self,
291        memory: &mut GuestMemory<'_>,
292        fd: types::Fd,
293        path: GuestPtr<u8>,
294        path_max_len: types::Size,
295    ) -> Result<(), Error> {
296        Snapshot1::fd_prestat_dir_name(self, memory, fd.into(), path, path_max_len)?;
297        Ok(())
298    }
299
300    fn fd_renumber(
301        &mut self,
302        memory: &mut GuestMemory<'_>,
303        from: types::Fd,
304        to: types::Fd,
305    ) -> Result<(), Error> {
306        Snapshot1::fd_renumber(self, memory, from.into(), to.into())?;
307        Ok(())
308    }
309
310    async fn fd_seek(
311        &mut self,
312        memory: &mut GuestMemory<'_>,
313        fd: types::Fd,
314        offset: types::Filedelta,
315        whence: types::Whence,
316    ) -> Result<types::Filesize, Error> {
317        Ok(Snapshot1::fd_seek(self, memory, fd.into(), offset, whence.into()).await?)
318    }
319
320    async fn fd_sync(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
321        Snapshot1::fd_sync(self, memory, fd.into()).await?;
322        Ok(())
323    }
324
325    fn fd_tell(
326        &mut self,
327        memory: &mut GuestMemory<'_>,
328        fd: types::Fd,
329    ) -> Result<types::Filesize, Error> {
330        Ok(Snapshot1::fd_tell(self, memory, fd.into())?)
331    }
332
333    async fn fd_readdir(
334        &mut self,
335        memory: &mut GuestMemory<'_>,
336        fd: types::Fd,
337        buf: GuestPtr<u8>,
338        buf_len: types::Size,
339        cookie: types::Dircookie,
340    ) -> Result<types::Size, Error> {
341        Ok(Snapshot1::fd_readdir(self, memory, fd.into(), buf, buf_len, cookie).await?)
342    }
343
344    async fn path_create_directory(
345        &mut self,
346        memory: &mut GuestMemory<'_>,
347        dirfd: types::Fd,
348        path: GuestPtr<str>,
349    ) -> Result<(), Error> {
350        Snapshot1::path_create_directory(self, memory, dirfd.into(), path).await?;
351        Ok(())
352    }
353
354    async fn path_filestat_get(
355        &mut self,
356        memory: &mut GuestMemory<'_>,
357        dirfd: types::Fd,
358        flags: types::Lookupflags,
359        path: GuestPtr<str>,
360    ) -> Result<types::Filestat, Error> {
361        Ok(
362            Snapshot1::path_filestat_get(self, memory, dirfd.into(), flags.into(), path)
363                .await?
364                .into(),
365        )
366    }
367
368    async fn path_filestat_set_times(
369        &mut self,
370        memory: &mut GuestMemory<'_>,
371        dirfd: types::Fd,
372        flags: types::Lookupflags,
373        path: GuestPtr<str>,
374        atim: types::Timestamp,
375        mtim: types::Timestamp,
376        fst_flags: types::Fstflags,
377    ) -> Result<(), Error> {
378        Snapshot1::path_filestat_set_times(
379            self,
380            memory,
381            dirfd.into(),
382            flags.into(),
383            path,
384            atim,
385            mtim,
386            fst_flags.into(),
387        )
388        .await?;
389        Ok(())
390    }
391
392    async fn path_link(
393        &mut self,
394        memory: &mut GuestMemory<'_>,
395        src_fd: types::Fd,
396        src_flags: types::Lookupflags,
397        src_path: GuestPtr<str>,
398        target_fd: types::Fd,
399        target_path: GuestPtr<str>,
400    ) -> Result<(), Error> {
401        Snapshot1::path_link(
402            self,
403            memory,
404            src_fd.into(),
405            src_flags.into(),
406            src_path,
407            target_fd.into(),
408            target_path,
409        )
410        .await?;
411        Ok(())
412    }
413
414    async fn path_open(
415        &mut self,
416        memory: &mut GuestMemory<'_>,
417        dirfd: types::Fd,
418        dirflags: types::Lookupflags,
419        path: GuestPtr<str>,
420        oflags: types::Oflags,
421        fs_rights_base: types::Rights,
422        fs_rights_inheriting: types::Rights,
423        fdflags: types::Fdflags,
424    ) -> Result<types::Fd, Error> {
425        Ok(Snapshot1::path_open(
426            self,
427            memory,
428            dirfd.into(),
429            dirflags.into(),
430            path,
431            oflags.into(),
432            fs_rights_base.into(),
433            fs_rights_inheriting.into(),
434            fdflags.into(),
435        )
436        .await?
437        .into())
438    }
439
440    async fn path_readlink(
441        &mut self,
442        memory: &mut GuestMemory<'_>,
443        dirfd: types::Fd,
444        path: GuestPtr<str>,
445        buf: GuestPtr<u8>,
446        buf_len: types::Size,
447    ) -> Result<types::Size, Error> {
448        Ok(Snapshot1::path_readlink(self, memory, dirfd.into(), path, buf, buf_len).await?)
449    }
450
451    async fn path_remove_directory(
452        &mut self,
453        memory: &mut GuestMemory<'_>,
454        dirfd: types::Fd,
455        path: GuestPtr<str>,
456    ) -> Result<(), Error> {
457        Snapshot1::path_remove_directory(self, memory, dirfd.into(), path).await?;
458        Ok(())
459    }
460
461    async fn path_rename(
462        &mut self,
463        memory: &mut GuestMemory<'_>,
464        src_fd: types::Fd,
465        src_path: GuestPtr<str>,
466        dest_fd: types::Fd,
467        dest_path: GuestPtr<str>,
468    ) -> Result<(), Error> {
469        Snapshot1::path_rename(
470            self,
471            memory,
472            src_fd.into(),
473            src_path,
474            dest_fd.into(),
475            dest_path,
476        )
477        .await?;
478        Ok(())
479    }
480
481    async fn path_symlink(
482        &mut self,
483        memory: &mut GuestMemory<'_>,
484        src_path: GuestPtr<str>,
485        dirfd: types::Fd,
486        dest_path: GuestPtr<str>,
487    ) -> Result<(), Error> {
488        Snapshot1::path_symlink(self, memory, src_path, dirfd.into(), dest_path).await?;
489        Ok(())
490    }
491
492    async fn path_unlink_file(
493        &mut self,
494        memory: &mut GuestMemory<'_>,
495        dirfd: types::Fd,
496        path: GuestPtr<str>,
497    ) -> Result<(), Error> {
498        Snapshot1::path_unlink_file(self, memory, dirfd.into(), path).await?;
499        Ok(())
500    }
501
502    // The representation of `SubscriptionClock` is different in p0 and
503    // p1 so a bit of a hack is employed here. The change was to remove a
504    // field from `SubscriptionClock` so to implement this without copying too
505    // much the `subs` field is overwritten with p1-compatible structures
506    // and then the p1 implementation is used. Before returning though
507    // the old values are restored to pretend like we didn't overwrite them.
508    //
509    // Surely no one would pass overlapping pointers to this API right?
510    async fn poll_oneoff(
511        &mut self,
512        memory: &mut GuestMemory<'_>,
513        subs: GuestPtr<types::Subscription>,
514        events: GuestPtr<types::Event>,
515        nsubscriptions: types::Size,
516    ) -> Result<types::Size, Error> {
517        let subs_array = subs.as_array(nsubscriptions);
518        let mut old_subs = Vec::new();
519        for slot in subs_array.iter() {
520            let slot = slot?;
521            let sub = memory.read(slot)?;
522            old_subs.push(sub.clone());
523            memory.write(
524                slot.cast(),
525                snapshot1_types::Subscription {
526                    userdata: sub.userdata,
527                    u: match sub.u {
528                        types::SubscriptionU::Clock(c) => {
529                            snapshot1_types::SubscriptionU::Clock(c.into())
530                        }
531                        types::SubscriptionU::FdRead(c) => {
532                            snapshot1_types::SubscriptionU::FdRead(c.into())
533                        }
534                        types::SubscriptionU::FdWrite(c) => {
535                            snapshot1_types::SubscriptionU::FdWrite(c.into())
536                        }
537                    },
538                },
539            )?;
540        }
541        let ret = Snapshot1::poll_oneoff(self, memory, subs.cast(), events.cast(), nsubscriptions)
542            .await?;
543        for (sub, slot) in old_subs.into_iter().zip(subs_array.iter()) {
544            memory.write(slot?, sub)?;
545        }
546        Ok(ret)
547    }
548
549    fn proc_exit(
550        &mut self,
551        memory: &mut GuestMemory<'_>,
552        status: types::Exitcode,
553    ) -> wasmtime::Error {
554        Snapshot1::proc_exit(self, memory, status)
555    }
556
557    fn proc_raise(
558        &mut self,
559        memory: &mut GuestMemory<'_>,
560        sig: types::Signal,
561    ) -> Result<(), Error> {
562        Snapshot1::proc_raise(self, memory, sig.into())?;
563        Ok(())
564    }
565
566    fn sched_yield(&mut self, memory: &mut GuestMemory<'_>) -> Result<(), Error> {
567        Snapshot1::sched_yield(self, memory)?;
568        Ok(())
569    }
570
571    fn random_get(
572        &mut self,
573        memory: &mut GuestMemory<'_>,
574        buf: GuestPtr<u8>,
575        buf_len: types::Size,
576    ) -> Result<(), Error> {
577        Snapshot1::random_get(self, memory, buf, buf_len)?;
578        Ok(())
579    }
580
581    fn sock_recv(
582        &mut self,
583        _memory: &mut GuestMemory<'_>,
584        _fd: types::Fd,
585        _ri_data: types::IovecArray,
586        _ri_flags: types::Riflags,
587    ) -> Result<(types::Size, types::Roflags), Error> {
588        Err(Error::trap(wasmtime::Error::msg("sock_recv unsupported")))
589    }
590
591    fn sock_send(
592        &mut self,
593        _memory: &mut GuestMemory<'_>,
594        _fd: types::Fd,
595        _si_data: types::CiovecArray,
596        _si_flags: types::Siflags,
597    ) -> Result<types::Size, Error> {
598        Err(Error::trap(wasmtime::Error::msg("sock_send unsupported")))
599    }
600
601    fn sock_shutdown(
602        &mut self,
603        _memory: &mut GuestMemory<'_>,
604        _fd: types::Fd,
605        _how: types::Sdflags,
606    ) -> Result<(), Error> {
607        Err(Error::trap(wasmtime::Error::msg(
608            "sock_shutdown unsupported",
609        )))
610    }
611}
612
613fn assert_iovec_array_same() {
614    // NB: this isn't enough to assert the types are the same, but it's
615    // something. Additionally p1 and p0 aren't changing any more
616    // and it's been manually verified that these two types are the same, so
617    // it's ok to cast between them.
618    assert_eq!(
619        std::mem::size_of::<types::IovecArray>(),
620        std::mem::size_of::<snapshot1_types::IovecArray>()
621    );
622}
623
624fn assert_ciovec_array_same() {
625    // NB: see above too
626    assert_eq!(
627        std::mem::size_of::<types::CiovecArray>(),
628        std::mem::size_of::<snapshot1_types::CiovecArray>()
629    );
630}
631
632impl From<snapshot1_types::Error> for Error {
633    fn from(error: snapshot1_types::Error) -> Error {
634        match error.downcast() {
635            Ok(errno) => Error::from(types::Errno::from(errno)),
636            Err(trap) => Error::trap(trap),
637        }
638    }
639}
640
641/// Fd is a newtype wrapper around u32. Unwrap and wrap it.
642impl From<types::Fd> for snapshot1_types::Fd {
643    fn from(fd: types::Fd) -> snapshot1_types::Fd {
644        u32::from(fd).into()
645    }
646}
647
648/// Fd is a newtype wrapper around u32. Unwrap and wrap it.
649impl From<snapshot1_types::Fd> for types::Fd {
650    fn from(fd: snapshot1_types::Fd) -> types::Fd {
651        u32::from(fd).into()
652    }
653}
654
655/// Trivial conversion between two c-style enums that have the exact same set of variants.
656/// Could we do something unsafe and not list all these variants out? Probably, but doing
657/// it this way doesn't bother me much. I copy-pasted the list of variants out of the
658/// rendered rustdocs.
659/// LLVM ought to compile these From impls into no-ops, inshallah
660macro_rules! convert_enum {
661    ($from:ty, $to:ty, $($var:ident),+) => {
662        impl From<$from> for $to {
663            fn from(e: $from) -> $to {
664                match e {
665                    $( <$from>::$var => <$to>::$var, )+
666                }
667            }
668        }
669    }
670}
671convert_enum!(
672    snapshot1_types::Errno,
673    types::Errno,
674    Success,
675    TooBig,
676    Acces,
677    Addrinuse,
678    Addrnotavail,
679    Afnosupport,
680    Again,
681    Already,
682    Badf,
683    Badmsg,
684    Busy,
685    Canceled,
686    Child,
687    Connaborted,
688    Connrefused,
689    Connreset,
690    Deadlk,
691    Destaddrreq,
692    Dom,
693    Dquot,
694    Exist,
695    Fault,
696    Fbig,
697    Hostunreach,
698    Idrm,
699    Ilseq,
700    Inprogress,
701    Intr,
702    Inval,
703    Io,
704    Isconn,
705    Isdir,
706    Loop,
707    Mfile,
708    Mlink,
709    Msgsize,
710    Multihop,
711    Nametoolong,
712    Netdown,
713    Netreset,
714    Netunreach,
715    Nfile,
716    Nobufs,
717    Nodev,
718    Noent,
719    Noexec,
720    Nolck,
721    Nolink,
722    Nomem,
723    Nomsg,
724    Noprotoopt,
725    Nospc,
726    Nosys,
727    Notconn,
728    Notdir,
729    Notempty,
730    Notrecoverable,
731    Notsock,
732    Notsup,
733    Notty,
734    Nxio,
735    Overflow,
736    Ownerdead,
737    Perm,
738    Pipe,
739    Proto,
740    Protonosupport,
741    Prototype,
742    Range,
743    Rofs,
744    Spipe,
745    Srch,
746    Stale,
747    Timedout,
748    Txtbsy,
749    Xdev,
750    Notcapable
751);
752convert_enum!(
753    types::Clockid,
754    snapshot1_types::Clockid,
755    Realtime,
756    Monotonic,
757    ProcessCputimeId,
758    ThreadCputimeId
759);
760
761convert_enum!(
762    types::Advice,
763    snapshot1_types::Advice,
764    Normal,
765    Sequential,
766    Random,
767    Willneed,
768    Dontneed,
769    Noreuse
770);
771convert_enum!(
772    snapshot1_types::Filetype,
773    types::Filetype,
774    Directory,
775    BlockDevice,
776    CharacterDevice,
777    RegularFile,
778    SocketDgram,
779    SocketStream,
780    SymbolicLink,
781    Unknown
782);
783convert_enum!(types::Whence, snapshot1_types::Whence, Cur, End, Set);
784
785convert_enum!(
786    types::Signal,
787    snapshot1_types::Signal,
788    None,
789    Hup,
790    Int,
791    Quit,
792    Ill,
793    Trap,
794    Abrt,
795    Bus,
796    Fpe,
797    Kill,
798    Usr1,
799    Segv,
800    Usr2,
801    Pipe,
802    Alrm,
803    Term,
804    Chld,
805    Cont,
806    Stop,
807    Tstp,
808    Ttin,
809    Ttou,
810    Urg,
811    Xcpu,
812    Xfsz,
813    Vtalrm,
814    Prof,
815    Winch,
816    Poll,
817    Pwr,
818    Sys
819);
820
821/// Prestat isn't a c-style enum, its a union where the variant has a payload. Its the only one of
822/// those we need to convert, so write it by hand.
823impl From<snapshot1_types::Prestat> for types::Prestat {
824    fn from(p: snapshot1_types::Prestat) -> types::Prestat {
825        match p {
826            snapshot1_types::Prestat::Dir(d) => types::Prestat::Dir(d.into()),
827        }
828    }
829}
830
831/// Trivial conversion between two structs that have the exact same set of fields,
832/// with recursive descent into the field types.
833macro_rules! convert_struct {
834    ($from:ty, $to:path, $($field:ident),+) => {
835        impl From<$from> for $to {
836            fn from(e: $from) -> $to {
837                $to {
838                    $( $field: e.$field.into(), )+
839                }
840            }
841        }
842    }
843}
844
845convert_struct!(snapshot1_types::PrestatDir, types::PrestatDir, pr_name_len);
846convert_struct!(
847    snapshot1_types::Fdstat,
848    types::Fdstat,
849    fs_filetype,
850    fs_rights_base,
851    fs_rights_inheriting,
852    fs_flags
853);
854convert_struct!(
855    types::SubscriptionClock,
856    snapshot1_types::SubscriptionClock,
857    id,
858    timeout,
859    precision,
860    flags
861);
862convert_struct!(
863    types::SubscriptionFdReadwrite,
864    snapshot1_types::SubscriptionFdReadwrite,
865    file_descriptor
866);
867
868/// Snapshot1 Filestat is incompatible with Snapshot0 Filestat - the nlink
869/// field is u32 on this Filestat, and u64 on theirs. If you've got more than
870/// 2^32 links I don't know what to tell you
871impl From<snapshot1_types::Filestat> for types::Filestat {
872    fn from(f: snapshot1_types::Filestat) -> types::Filestat {
873        types::Filestat {
874            dev: f.dev,
875            ino: f.ino,
876            filetype: f.filetype.into(),
877            nlink: f.nlink.try_into().unwrap_or(u32::MAX),
878            size: f.size,
879            atim: f.atim,
880            mtim: f.mtim,
881            ctim: f.ctim,
882        }
883    }
884}
885
886/// Trivial conversion between two bitflags that have the exact same set of flags.
887macro_rules! convert_flags {
888    ($from:ty, $to:ty, $($flag:ident),+) => {
889        impl From<$from> for $to {
890            fn from(f: $from) -> $to {
891                let mut out = <$to>::empty();
892                $(
893                    if f.contains(<$from>::$flag) {
894                        out |= <$to>::$flag;
895                    }
896                )+
897                out
898            }
899        }
900    }
901}
902
903/// Need to convert in both directions? This saves listing out the flags twice
904macro_rules! convert_flags_bidirectional {
905    ($from:ty, $to:ty, $($flag:tt)*) => {
906        convert_flags!($from, $to, $($flag)*);
907        convert_flags!($to, $from, $($flag)*);
908    }
909}
910
911convert_flags_bidirectional!(
912    snapshot1_types::Fdflags,
913    types::Fdflags,
914    APPEND,
915    DSYNC,
916    NONBLOCK,
917    RSYNC,
918    SYNC
919);
920convert_flags!(
921    types::Lookupflags,
922    snapshot1_types::Lookupflags,
923    SYMLINK_FOLLOW
924);
925convert_flags!(
926    types::Fstflags,
927    snapshot1_types::Fstflags,
928    ATIM,
929    ATIM_NOW,
930    MTIM,
931    MTIM_NOW
932);
933convert_flags!(
934    types::Oflags,
935    snapshot1_types::Oflags,
936    CREAT,
937    DIRECTORY,
938    EXCL,
939    TRUNC
940);
941convert_flags_bidirectional!(
942    types::Rights,
943    snapshot1_types::Rights,
944    FD_DATASYNC,
945    FD_READ,
946    FD_SEEK,
947    FD_FDSTAT_SET_FLAGS,
948    FD_SYNC,
949    FD_TELL,
950    FD_WRITE,
951    FD_ADVISE,
952    FD_ALLOCATE,
953    PATH_CREATE_DIRECTORY,
954    PATH_CREATE_FILE,
955    PATH_LINK_SOURCE,
956    PATH_LINK_TARGET,
957    PATH_OPEN,
958    FD_READDIR,
959    PATH_READLINK,
960    PATH_RENAME_SOURCE,
961    PATH_RENAME_TARGET,
962    PATH_FILESTAT_GET,
963    PATH_FILESTAT_SET_SIZE,
964    PATH_FILESTAT_SET_TIMES,
965    FD_FILESTAT_GET,
966    FD_FILESTAT_SET_SIZE,
967    FD_FILESTAT_SET_TIMES,
968    PATH_SYMLINK,
969    PATH_REMOVE_DIRECTORY,
970    PATH_UNLINK_FILE,
971    POLL_FD_READWRITE,
972    SOCK_SHUTDOWN
973);
974convert_flags!(
975    types::Subclockflags,
976    snapshot1_types::Subclockflags,
977    SUBSCRIPTION_CLOCK_ABSTIME
978);
979
980impl From<GuestError> for types::Error {
981    fn from(err: GuestError) -> Self {
982        snapshot1_types::Error::from(err).into()
983    }
984}