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