Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wasi-common/src/snapshots/preview_0.rs
1692 views
1
use crate::file::TableFileExt;
2
use crate::sched::{
3
Poll, Userdata,
4
subscription::{RwEventFlags, SubscriptionResult},
5
};
6
use crate::snapshots::preview_1::types as snapshot1_types;
7
use crate::snapshots::preview_1::wasi_snapshot_preview1::WasiSnapshotPreview1 as Snapshot1;
8
use crate::{ErrorExt, WasiCtx};
9
use cap_std::time::Duration;
10
use std::collections::HashSet;
11
use wiggle::{GuestMemory, GuestPtr};
12
13
wiggle::from_witx!({
14
witx: ["witx/preview0/wasi_unstable.witx"],
15
errors: { errno => trappable Error },
16
async: *,
17
wasmtime: false,
18
});
19
20
use types::Error;
21
22
impl 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
67
impl wiggle::GuestErrorType for types::Errno {
68
fn success() -> Self {
69
Self::Success
70
}
71
}
72
73
impl From<wiggle::GuestError> for Error {
74
fn from(err: wiggle::GuestError) -> Error {
75
snapshot1_types::Error::from(err).into()
76
}
77
}
78
79
impl 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
88
impl 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.
101
impl 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.
107
impl 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
118
macro_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
}
129
convert_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
);
210
convert_enum!(
211
types::Clockid,
212
snapshot1_types::Clockid,
213
Realtime,
214
Monotonic,
215
ProcessCputimeId,
216
ThreadCputimeId
217
);
218
219
convert_enum!(
220
types::Advice,
221
snapshot1_types::Advice,
222
Normal,
223
Sequential,
224
Random,
225
Willneed,
226
Dontneed,
227
Noreuse
228
);
229
convert_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
);
241
convert_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.
245
impl 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.
255
macro_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
267
convert_struct!(snapshot1_types::PrestatDir, types::PrestatDir, pr_name_len);
268
convert_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
280
impl 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.
296
macro_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
313
macro_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
320
convert_flags_bidirectional!(
321
snapshot1_types::Fdflags,
322
types::Fdflags,
323
APPEND,
324
DSYNC,
325
NONBLOCK,
326
RSYNC,
327
SYNC
328
);
329
convert_flags!(
330
types::Lookupflags,
331
snapshot1_types::Lookupflags,
332
SYMLINK_FOLLOW
333
);
334
convert_flags!(
335
types::Fstflags,
336
snapshot1_types::Fstflags,
337
ATIM,
338
ATIM_NOW,
339
MTIM,
340
MTIM_NOW
341
);
342
convert_flags!(
343
types::Oflags,
344
snapshot1_types::Oflags,
345
CREAT,
346
DIRECTORY,
347
EXCL,
348
TRUNC
349
);
350
convert_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.
386
#[wiggle::async_trait]
387
impl wasi_unstable::WasiUnstable for WasiCtx {
388
async fn args_get(
389
&mut self,
390
memory: &mut GuestMemory<'_>,
391
argv: GuestPtr<GuestPtr<u8>>,
392
argv_buf: GuestPtr<u8>,
393
) -> Result<(), Error> {
394
Snapshot1::args_get(self, memory, argv, argv_buf).await?;
395
Ok(())
396
}
397
398
async fn args_sizes_get(
399
&mut self,
400
memory: &mut GuestMemory<'_>,
401
) -> Result<(types::Size, types::Size), Error> {
402
let s = Snapshot1::args_sizes_get(self, memory).await?;
403
Ok(s)
404
}
405
406
async fn environ_get(
407
&mut self,
408
memory: &mut GuestMemory<'_>,
409
environ: GuestPtr<GuestPtr<u8>>,
410
environ_buf: GuestPtr<u8>,
411
) -> Result<(), Error> {
412
Snapshot1::environ_get(self, memory, environ, environ_buf).await?;
413
Ok(())
414
}
415
416
async fn environ_sizes_get(
417
&mut self,
418
memory: &mut GuestMemory<'_>,
419
) -> Result<(types::Size, types::Size), Error> {
420
let s = Snapshot1::environ_sizes_get(self, memory).await?;
421
Ok(s)
422
}
423
424
async fn clock_res_get(
425
&mut self,
426
memory: &mut GuestMemory<'_>,
427
id: types::Clockid,
428
) -> Result<types::Timestamp, Error> {
429
let t = Snapshot1::clock_res_get(self, memory, id.into()).await?;
430
Ok(t)
431
}
432
433
async fn clock_time_get(
434
&mut self,
435
memory: &mut GuestMemory<'_>,
436
id: types::Clockid,
437
precision: types::Timestamp,
438
) -> Result<types::Timestamp, Error> {
439
let t = Snapshot1::clock_time_get(self, memory, id.into(), precision).await?;
440
Ok(t)
441
}
442
443
async fn fd_advise(
444
&mut self,
445
memory: &mut GuestMemory<'_>,
446
fd: types::Fd,
447
offset: types::Filesize,
448
len: types::Filesize,
449
advice: types::Advice,
450
) -> Result<(), Error> {
451
Snapshot1::fd_advise(self, memory, fd.into(), offset, len, advice.into()).await?;
452
Ok(())
453
}
454
455
async fn fd_allocate(
456
&mut self,
457
memory: &mut GuestMemory<'_>,
458
fd: types::Fd,
459
offset: types::Filesize,
460
len: types::Filesize,
461
) -> Result<(), Error> {
462
Snapshot1::fd_allocate(self, memory, fd.into(), offset, len).await?;
463
Ok(())
464
}
465
466
async fn fd_close(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
467
Snapshot1::fd_close(self, memory, fd.into()).await?;
468
Ok(())
469
}
470
471
async fn fd_datasync(
472
&mut self,
473
memory: &mut GuestMemory<'_>,
474
fd: types::Fd,
475
) -> Result<(), Error> {
476
Snapshot1::fd_datasync(self, memory, fd.into()).await?;
477
Ok(())
478
}
479
480
async fn fd_fdstat_get(
481
&mut self,
482
memory: &mut GuestMemory<'_>,
483
fd: types::Fd,
484
) -> Result<types::Fdstat, Error> {
485
Ok(Snapshot1::fd_fdstat_get(self, memory, fd.into())
486
.await?
487
.into())
488
}
489
490
async fn fd_fdstat_set_flags(
491
&mut self,
492
memory: &mut GuestMemory<'_>,
493
fd: types::Fd,
494
flags: types::Fdflags,
495
) -> Result<(), Error> {
496
Snapshot1::fd_fdstat_set_flags(self, memory, fd.into(), flags.into()).await?;
497
Ok(())
498
}
499
500
async fn fd_fdstat_set_rights(
501
&mut self,
502
memory: &mut GuestMemory<'_>,
503
fd: types::Fd,
504
fs_rights_base: types::Rights,
505
fs_rights_inheriting: types::Rights,
506
) -> Result<(), Error> {
507
Snapshot1::fd_fdstat_set_rights(
508
self,
509
memory,
510
fd.into(),
511
fs_rights_base.into(),
512
fs_rights_inheriting.into(),
513
)
514
.await?;
515
Ok(())
516
}
517
518
async fn fd_filestat_get(
519
&mut self,
520
memory: &mut GuestMemory<'_>,
521
fd: types::Fd,
522
) -> Result<types::Filestat, Error> {
523
Ok(Snapshot1::fd_filestat_get(self, memory, fd.into())
524
.await?
525
.into())
526
}
527
528
async fn fd_filestat_set_size(
529
&mut self,
530
memory: &mut GuestMemory<'_>,
531
fd: types::Fd,
532
size: types::Filesize,
533
) -> Result<(), Error> {
534
Snapshot1::fd_filestat_set_size(self, memory, fd.into(), size).await?;
535
Ok(())
536
}
537
538
async fn fd_filestat_set_times(
539
&mut self,
540
memory: &mut GuestMemory<'_>,
541
fd: types::Fd,
542
atim: types::Timestamp,
543
mtim: types::Timestamp,
544
fst_flags: types::Fstflags,
545
) -> Result<(), Error> {
546
Snapshot1::fd_filestat_set_times(self, memory, fd.into(), atim, mtim, fst_flags.into())
547
.await?;
548
Ok(())
549
}
550
551
// NOTE on fd_read, fd_pread, fd_write, fd_pwrite implementations:
552
// these cast their pointers from preview0 vectors to preview1 vectors and
553
// this only works because the representation didn't change between preview0
554
// and preview1.
555
556
async fn fd_read(
557
&mut self,
558
memory: &mut GuestMemory<'_>,
559
fd: types::Fd,
560
iovs: types::IovecArray,
561
) -> Result<types::Size, Error> {
562
Ok(Snapshot1::fd_read(self, memory, fd.into(), iovs.cast()).await?)
563
}
564
565
async fn fd_pread(
566
&mut self,
567
memory: &mut GuestMemory<'_>,
568
fd: types::Fd,
569
iovs: types::IovecArray,
570
offset: types::Filesize,
571
) -> Result<types::Size, Error> {
572
Ok(Snapshot1::fd_pread(self, memory, fd.into(), iovs.cast(), offset).await?)
573
}
574
575
async fn fd_write(
576
&mut self,
577
memory: &mut GuestMemory<'_>,
578
fd: types::Fd,
579
ciovs: types::CiovecArray,
580
) -> Result<types::Size, Error> {
581
Ok(Snapshot1::fd_write(self, memory, fd.into(), ciovs.cast()).await?)
582
}
583
584
async fn fd_pwrite(
585
&mut self,
586
memory: &mut GuestMemory<'_>,
587
fd: types::Fd,
588
ciovs: types::CiovecArray,
589
offset: types::Filesize,
590
) -> Result<types::Size, Error> {
591
Ok(Snapshot1::fd_pwrite(self, memory, fd.into(), ciovs.cast(), offset).await?)
592
}
593
594
async fn fd_prestat_get(
595
&mut self,
596
memory: &mut GuestMemory<'_>,
597
fd: types::Fd,
598
) -> Result<types::Prestat, Error> {
599
Ok(Snapshot1::fd_prestat_get(self, memory, fd.into())
600
.await?
601
.into())
602
}
603
604
async fn fd_prestat_dir_name(
605
&mut self,
606
memory: &mut GuestMemory<'_>,
607
fd: types::Fd,
608
path: GuestPtr<u8>,
609
path_max_len: types::Size,
610
) -> Result<(), Error> {
611
Snapshot1::fd_prestat_dir_name(self, memory, fd.into(), path, path_max_len).await?;
612
Ok(())
613
}
614
615
async fn fd_renumber(
616
&mut self,
617
memory: &mut GuestMemory<'_>,
618
from: types::Fd,
619
to: types::Fd,
620
) -> Result<(), Error> {
621
Snapshot1::fd_renumber(self, memory, from.into(), to.into()).await?;
622
Ok(())
623
}
624
625
async fn fd_seek(
626
&mut self,
627
memory: &mut GuestMemory<'_>,
628
fd: types::Fd,
629
offset: types::Filedelta,
630
whence: types::Whence,
631
) -> Result<types::Filesize, Error> {
632
Ok(Snapshot1::fd_seek(self, memory, fd.into(), offset, whence.into()).await?)
633
}
634
635
async fn fd_sync(&mut self, memory: &mut GuestMemory<'_>, fd: types::Fd) -> Result<(), Error> {
636
Snapshot1::fd_sync(self, memory, fd.into()).await?;
637
Ok(())
638
}
639
640
async fn fd_tell(
641
&mut self,
642
memory: &mut GuestMemory<'_>,
643
fd: types::Fd,
644
) -> Result<types::Filesize, Error> {
645
Ok(Snapshot1::fd_tell(self, memory, fd.into()).await?)
646
}
647
648
async fn fd_readdir(
649
&mut self,
650
memory: &mut GuestMemory<'_>,
651
fd: types::Fd,
652
buf: GuestPtr<u8>,
653
buf_len: types::Size,
654
cookie: types::Dircookie,
655
) -> Result<types::Size, Error> {
656
Ok(Snapshot1::fd_readdir(self, memory, fd.into(), buf, buf_len, cookie).await?)
657
}
658
659
async fn path_create_directory(
660
&mut self,
661
memory: &mut GuestMemory<'_>,
662
dirfd: types::Fd,
663
path: GuestPtr<str>,
664
) -> Result<(), Error> {
665
Snapshot1::path_create_directory(self, memory, dirfd.into(), path).await?;
666
Ok(())
667
}
668
669
async fn path_filestat_get(
670
&mut self,
671
memory: &mut GuestMemory<'_>,
672
dirfd: types::Fd,
673
flags: types::Lookupflags,
674
path: GuestPtr<str>,
675
) -> Result<types::Filestat, Error> {
676
Ok(
677
Snapshot1::path_filestat_get(self, memory, dirfd.into(), flags.into(), path)
678
.await?
679
.into(),
680
)
681
}
682
683
async fn path_filestat_set_times(
684
&mut self,
685
memory: &mut GuestMemory<'_>,
686
dirfd: types::Fd,
687
flags: types::Lookupflags,
688
path: GuestPtr<str>,
689
atim: types::Timestamp,
690
mtim: types::Timestamp,
691
fst_flags: types::Fstflags,
692
) -> Result<(), Error> {
693
Snapshot1::path_filestat_set_times(
694
self,
695
memory,
696
dirfd.into(),
697
flags.into(),
698
path,
699
atim,
700
mtim,
701
fst_flags.into(),
702
)
703
.await?;
704
Ok(())
705
}
706
707
async fn path_link(
708
&mut self,
709
memory: &mut GuestMemory<'_>,
710
src_fd: types::Fd,
711
src_flags: types::Lookupflags,
712
src_path: GuestPtr<str>,
713
target_fd: types::Fd,
714
target_path: GuestPtr<str>,
715
) -> Result<(), Error> {
716
Snapshot1::path_link(
717
self,
718
memory,
719
src_fd.into(),
720
src_flags.into(),
721
src_path,
722
target_fd.into(),
723
target_path,
724
)
725
.await?;
726
Ok(())
727
}
728
729
async fn path_open(
730
&mut self,
731
memory: &mut GuestMemory<'_>,
732
dirfd: types::Fd,
733
dirflags: types::Lookupflags,
734
path: GuestPtr<str>,
735
oflags: types::Oflags,
736
fs_rights_base: types::Rights,
737
fs_rights_inheriting: types::Rights,
738
fdflags: types::Fdflags,
739
) -> Result<types::Fd, Error> {
740
Ok(Snapshot1::path_open(
741
self,
742
memory,
743
dirfd.into(),
744
dirflags.into(),
745
path,
746
oflags.into(),
747
fs_rights_base.into(),
748
fs_rights_inheriting.into(),
749
fdflags.into(),
750
)
751
.await?
752
.into())
753
}
754
755
async fn path_readlink(
756
&mut self,
757
memory: &mut GuestMemory<'_>,
758
dirfd: types::Fd,
759
path: GuestPtr<str>,
760
buf: GuestPtr<u8>,
761
buf_len: types::Size,
762
) -> Result<types::Size, Error> {
763
Ok(Snapshot1::path_readlink(self, memory, dirfd.into(), path, buf, buf_len).await?)
764
}
765
766
async fn path_remove_directory(
767
&mut self,
768
memory: &mut GuestMemory<'_>,
769
dirfd: types::Fd,
770
path: GuestPtr<str>,
771
) -> Result<(), Error> {
772
Snapshot1::path_remove_directory(self, memory, dirfd.into(), path).await?;
773
Ok(())
774
}
775
776
async fn path_rename(
777
&mut self,
778
memory: &mut GuestMemory<'_>,
779
src_fd: types::Fd,
780
src_path: GuestPtr<str>,
781
dest_fd: types::Fd,
782
dest_path: GuestPtr<str>,
783
) -> Result<(), Error> {
784
Snapshot1::path_rename(
785
self,
786
memory,
787
src_fd.into(),
788
src_path,
789
dest_fd.into(),
790
dest_path,
791
)
792
.await?;
793
Ok(())
794
}
795
796
async fn path_symlink(
797
&mut self,
798
memory: &mut GuestMemory<'_>,
799
src_path: GuestPtr<str>,
800
dirfd: types::Fd,
801
dest_path: GuestPtr<str>,
802
) -> Result<(), Error> {
803
Snapshot1::path_symlink(self, memory, src_path, dirfd.into(), dest_path).await?;
804
Ok(())
805
}
806
807
async fn path_unlink_file(
808
&mut self,
809
memory: &mut GuestMemory<'_>,
810
dirfd: types::Fd,
811
path: GuestPtr<str>,
812
) -> Result<(), Error> {
813
Snapshot1::path_unlink_file(self, memory, dirfd.into(), path).await?;
814
Ok(())
815
}
816
817
// NOTE on poll_oneoff implementation:
818
// Like fd_write and friends, the arguments and return values are behind GuestPtrs,
819
// so they are not values we can convert and pass to the poll_oneoff in Snapshot1.
820
// Instead, we have copied the implementation of these functions from the Snapshot1 code.
821
// The implementations are identical, but the `types::` in scope locally is different.
822
// The bodies of these functions is mostly about converting the GuestPtr and types::-based
823
// representation to use the Poll abstraction.
824
async fn poll_oneoff(
825
&mut self,
826
memory: &mut GuestMemory<'_>,
827
subs: GuestPtr<types::Subscription>,
828
events: GuestPtr<types::Event>,
829
nsubscriptions: types::Size,
830
) -> Result<types::Size, Error> {
831
if nsubscriptions == 0 {
832
return Err(Error::invalid_argument().context("nsubscriptions must be nonzero"));
833
}
834
835
// Special-case a `poll_oneoff` which is just sleeping on a single
836
// relative timer event, such as what WASI libc uses to implement sleep
837
// functions. This supports all clock IDs, because POSIX says that
838
// `clock_settime` doesn't effect relative sleeps.
839
if nsubscriptions == 1 {
840
let sub = memory.read(subs)?;
841
if let types::SubscriptionU::Clock(clocksub) = sub.u {
842
if !clocksub
843
.flags
844
.contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)
845
{
846
self.sched
847
.sleep(Duration::from_nanos(clocksub.timeout))
848
.await?;
849
memory.write(
850
events,
851
types::Event {
852
userdata: sub.userdata,
853
error: types::Errno::Success,
854
type_: types::Eventtype::Clock,
855
fd_readwrite: fd_readwrite_empty(),
856
},
857
)?;
858
return Ok(1);
859
}
860
}
861
}
862
863
let table = &self.table;
864
let mut sub_fds: HashSet<types::Fd> = HashSet::new();
865
// We need these refmuts to outlive Poll, which will hold the &mut dyn WasiFile inside
866
let mut reads: Vec<(u32, Userdata)> = Vec::new();
867
let mut writes: Vec<(u32, Userdata)> = Vec::new();
868
let mut poll = Poll::new();
869
870
let subs = subs.as_array(nsubscriptions);
871
for sub_elem in subs.iter() {
872
let sub_ptr = sub_elem?;
873
let sub = memory.read(sub_ptr)?;
874
match sub.u {
875
types::SubscriptionU::Clock(clocksub) => match clocksub.id {
876
types::Clockid::Monotonic => {
877
let clock = self.clocks.monotonic()?;
878
let precision = Duration::from_nanos(clocksub.precision);
879
let duration = Duration::from_nanos(clocksub.timeout);
880
let start = if clocksub
881
.flags
882
.contains(types::Subclockflags::SUBSCRIPTION_CLOCK_ABSTIME)
883
{
884
clock.creation_time
885
} else {
886
clock.abs_clock.now(precision)
887
};
888
let deadline = start
889
.checked_add(duration)
890
.ok_or_else(|| Error::overflow().context("deadline"))?;
891
poll.subscribe_monotonic_clock(
892
&*clock.abs_clock,
893
deadline,
894
precision,
895
sub.userdata.into(),
896
)
897
}
898
_ => Err(Error::invalid_argument()
899
.context("timer subscriptions only support monotonic timer"))?,
900
},
901
types::SubscriptionU::FdRead(readsub) => {
902
let fd = readsub.file_descriptor;
903
if sub_fds.contains(&fd) {
904
return Err(Error::invalid_argument()
905
.context("Fd can be subscribed to at most once per poll"));
906
} else {
907
sub_fds.insert(fd);
908
}
909
table.get_file(u32::from(fd))?;
910
reads.push((u32::from(fd), sub.userdata.into()));
911
}
912
types::SubscriptionU::FdWrite(writesub) => {
913
let fd = writesub.file_descriptor;
914
if sub_fds.contains(&fd) {
915
return Err(Error::invalid_argument()
916
.context("Fd can be subscribed to at most once per poll"));
917
} else {
918
sub_fds.insert(fd);
919
}
920
table.get_file(u32::from(fd))?;
921
writes.push((u32::from(fd), sub.userdata.into()));
922
}
923
}
924
}
925
926
self.sched.poll_oneoff(&mut poll).await?;
927
928
let results = poll.results();
929
let num_results = results.len();
930
assert!(
931
num_results <= nsubscriptions as usize,
932
"results exceeds subscriptions"
933
);
934
let events = events.as_array(
935
num_results
936
.try_into()
937
.expect("not greater than nsubscriptions"),
938
);
939
for ((result, userdata), event_elem) in results.into_iter().zip(events.iter()) {
940
let event_ptr = event_elem?;
941
let userdata: types::Userdata = userdata.into();
942
memory.write(
943
event_ptr,
944
match result {
945
SubscriptionResult::Read(r) => {
946
let type_ = types::Eventtype::FdRead;
947
match r {
948
Ok((nbytes, flags)) => types::Event {
949
userdata,
950
error: types::Errno::Success,
951
type_,
952
fd_readwrite: types::EventFdReadwrite {
953
nbytes,
954
flags: types::Eventrwflags::from(&flags),
955
},
956
},
957
Err(e) => types::Event {
958
userdata,
959
error: types::Errno::from(e.downcast().map_err(Error::trap)?),
960
type_,
961
fd_readwrite: fd_readwrite_empty(),
962
},
963
}
964
}
965
SubscriptionResult::Write(r) => {
966
let type_ = types::Eventtype::FdWrite;
967
match r {
968
Ok((nbytes, flags)) => types::Event {
969
userdata,
970
error: types::Errno::Success,
971
type_,
972
fd_readwrite: types::EventFdReadwrite {
973
nbytes,
974
flags: types::Eventrwflags::from(&flags),
975
},
976
},
977
Err(e) => types::Event {
978
userdata,
979
error: types::Errno::from(e.downcast().map_err(Error::trap)?),
980
type_,
981
fd_readwrite: fd_readwrite_empty(),
982
},
983
}
984
}
985
SubscriptionResult::MonotonicClock(r) => {
986
let type_ = types::Eventtype::Clock;
987
types::Event {
988
userdata,
989
error: match r {
990
Ok(()) => types::Errno::Success,
991
Err(e) => types::Errno::from(e.downcast().map_err(Error::trap)?),
992
},
993
type_,
994
fd_readwrite: fd_readwrite_empty(),
995
}
996
}
997
},
998
)?;
999
}
1000
1001
Ok(num_results.try_into().expect("results fit into memory"))
1002
}
1003
1004
async fn proc_exit(
1005
&mut self,
1006
memory: &mut GuestMemory<'_>,
1007
status: types::Exitcode,
1008
) -> anyhow::Error {
1009
Snapshot1::proc_exit(self, memory, status).await
1010
}
1011
1012
async fn proc_raise(
1013
&mut self,
1014
_memory: &mut GuestMemory<'_>,
1015
_sig: types::Signal,
1016
) -> Result<(), Error> {
1017
Err(Error::trap(anyhow::Error::msg("proc_raise unsupported")))
1018
}
1019
1020
async fn sched_yield(&mut self, memory: &mut GuestMemory<'_>) -> Result<(), Error> {
1021
Snapshot1::sched_yield(self, memory).await?;
1022
Ok(())
1023
}
1024
1025
async fn random_get(
1026
&mut self,
1027
memory: &mut GuestMemory<'_>,
1028
buf: GuestPtr<u8>,
1029
buf_len: types::Size,
1030
) -> Result<(), Error> {
1031
Snapshot1::random_get(self, memory, buf, buf_len).await?;
1032
Ok(())
1033
}
1034
1035
async fn sock_recv(
1036
&mut self,
1037
_memory: &mut GuestMemory<'_>,
1038
_fd: types::Fd,
1039
_ri_data: types::IovecArray,
1040
_ri_flags: types::Riflags,
1041
) -> Result<(types::Size, types::Roflags), Error> {
1042
Err(Error::trap(anyhow::Error::msg("sock_recv unsupported")))
1043
}
1044
1045
async fn sock_send(
1046
&mut self,
1047
_memory: &mut GuestMemory<'_>,
1048
_fd: types::Fd,
1049
_si_data: types::CiovecArray,
1050
_si_flags: types::Siflags,
1051
) -> Result<types::Size, Error> {
1052
Err(Error::trap(anyhow::Error::msg("sock_send unsupported")))
1053
}
1054
1055
async fn sock_shutdown(
1056
&mut self,
1057
_memory: &mut GuestMemory<'_>,
1058
_fd: types::Fd,
1059
_how: types::Sdflags,
1060
) -> Result<(), Error> {
1061
Err(Error::trap(anyhow::Error::msg("sock_shutdown unsupported")))
1062
}
1063
}
1064
1065
impl From<&RwEventFlags> for types::Eventrwflags {
1066
fn from(flags: &RwEventFlags) -> types::Eventrwflags {
1067
let mut out = types::Eventrwflags::empty();
1068
if flags.contains(RwEventFlags::HANGUP) {
1069
out = out | types::Eventrwflags::FD_READWRITE_HANGUP;
1070
}
1071
out
1072
}
1073
}
1074
1075
fn fd_readwrite_empty() -> types::EventFdReadwrite {
1076
types::EventFdReadwrite {
1077
nbytes: 0,
1078
flags: types::Eventrwflags::empty(),
1079
}
1080
}
1081
1082