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