@@ -37,6 +37,19 @@ use wasmer_runtime_core::{debug, vm::Ctx};
37
37
pub const VIRTUAL_ROOT_FD : __wasi_fd_t = 3 ;
38
38
/// all the rights enabled
39
39
pub const ALL_RIGHTS : __wasi_rights_t = 0x1FFFFFFF ;
40
+ const STDIN_DEFAULT_RIGHTS : __wasi_rights_t = __WASI_RIGHT_FD_DATASYNC
41
+ | __WASI_RIGHT_FD_READ
42
+ | __WASI_RIGHT_FD_SYNC
43
+ | __WASI_RIGHT_FD_ADVISE
44
+ | __WASI_RIGHT_FD_FILESTAT_GET
45
+ | __WASI_RIGHT_POLL_FD_READWRITE;
46
+ const STDOUT_DEFAULT_RIGHTS : __wasi_rights_t = __WASI_RIGHT_FD_DATASYNC
47
+ | __WASI_RIGHT_FD_WRITE
48
+ | __WASI_RIGHT_FD_SYNC
49
+ | __WASI_RIGHT_FD_ADVISE
50
+ | __WASI_RIGHT_FD_FILESTAT_GET
51
+ | __WASI_RIGHT_POLL_FD_READWRITE;
52
+ const STDERR_DEFAULT_RIGHTS : __wasi_rights_t = STDOUT_DEFAULT_RIGHTS ;
40
53
41
54
/// Get WasiState from a Ctx
42
55
/// This function is unsafe because it must be called on a WASI Ctx
@@ -109,6 +122,7 @@ pub struct Fd {
109
122
pub rights_inheriting : __wasi_rights_t ,
110
123
pub flags : __wasi_fdflags_t ,
111
124
pub offset : u64 ,
125
+ /// Used when reopening the file on the host system
112
126
pub open_flags : u16 ,
113
127
pub inode : Inode ,
114
128
}
@@ -134,10 +148,6 @@ pub struct WasiFs {
134
148
inode_counter : Cell < u64 > ,
135
149
/// for fds still open after the file has been deleted
136
150
pub orphan_fds : HashMap < Inode , InodeVal > ,
137
-
138
- pub stdout : Box < dyn WasiFile > ,
139
- pub stderr : Box < dyn WasiFile > ,
140
- pub stdin : Box < dyn WasiFile > ,
141
151
}
142
152
143
153
impl WasiFs {
@@ -155,11 +165,11 @@ impl WasiFs {
155
165
next_fd : Cell :: new ( 3 ) ,
156
166
inode_counter : Cell :: new ( 1024 ) ,
157
167
orphan_fds : HashMap :: new ( ) ,
158
-
159
- stdin : Box :: new ( Stdin ) ,
160
- stdout : Box :: new ( Stdout ) ,
161
- stderr : Box :: new ( Stderr ) ,
162
168
} ;
169
+ wasi_fs. create_stdin ( ) ;
170
+ wasi_fs. create_stdout ( ) ;
171
+ wasi_fs. create_stderr ( ) ;
172
+
163
173
// create virtual root
164
174
let root_inode = {
165
175
let all_rights = 0x1FFFFFFF ;
@@ -291,6 +301,67 @@ impl WasiFs {
291
301
Ok ( wasi_fs)
292
302
}
293
303
304
+ /// Get the `WasiFile` object at stdout
305
+ pub fn stdout ( & self ) -> Result < & Option < Box < dyn WasiFile > > , WasiFsError > {
306
+ self . std_dev_get ( __WASI_STDOUT_FILENO)
307
+ }
308
+ /// Get the `WasiFile` object at stdout mutably
309
+ pub fn stdout_mut ( & mut self ) -> Result < & mut Option < Box < dyn WasiFile > > , WasiFsError > {
310
+ self . std_dev_get_mut ( __WASI_STDOUT_FILENO)
311
+ }
312
+
313
+ /// Get the `WasiFile` object at stderr
314
+ pub fn stderr ( & self ) -> Result < & Option < Box < dyn WasiFile > > , WasiFsError > {
315
+ self . std_dev_get ( __WASI_STDERR_FILENO)
316
+ }
317
+ /// Get the `WasiFile` object at stderr mutably
318
+ pub fn stderr_mut ( & mut self ) -> Result < & mut Option < Box < dyn WasiFile > > , WasiFsError > {
319
+ self . std_dev_get_mut ( __WASI_STDERR_FILENO)
320
+ }
321
+
322
+ /// Get the `WasiFile` object at stdin
323
+ pub fn stdin ( & self ) -> Result < & Option < Box < dyn WasiFile > > , WasiFsError > {
324
+ self . std_dev_get ( __WASI_STDIN_FILENO)
325
+ }
326
+ /// Get the `WasiFile` object at stdin mutably
327
+ pub fn stdin_mut ( & mut self ) -> Result < & mut Option < Box < dyn WasiFile > > , WasiFsError > {
328
+ self . std_dev_get_mut ( __WASI_STDIN_FILENO)
329
+ }
330
+
331
+ /// Internal helper function to get a standard device handle.
332
+ /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`.
333
+ fn std_dev_get ( & self , fd : __wasi_fd_t ) -> Result < & Option < Box < dyn WasiFile > > , WasiFsError > {
334
+ if let Some ( fd) = self . fd_map . get ( & fd) {
335
+ if let Kind :: File { ref handle, .. } = self . inodes [ fd. inode ] . kind {
336
+ Ok ( handle)
337
+ } else {
338
+ // Our public API should ensure that this is not possible
339
+ unreachable ! ( "Non-file found in standard device location" )
340
+ }
341
+ } else {
342
+ // this should only trigger if we made a mistake in this crate
343
+ Err ( WasiFsError :: NoDevice )
344
+ }
345
+ }
346
+ /// Internal helper function to mutably get a standard device handle.
347
+ /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`.
348
+ fn std_dev_get_mut (
349
+ & mut self ,
350
+ fd : __wasi_fd_t ,
351
+ ) -> Result < & mut Option < Box < dyn WasiFile > > , WasiFsError > {
352
+ if let Some ( fd) = self . fd_map . get_mut ( & fd) {
353
+ if let Kind :: File { ref mut handle, .. } = self . inodes [ fd. inode ] . kind {
354
+ Ok ( handle)
355
+ } else {
356
+ // Our public API should ensure that this is not possible
357
+ unreachable ! ( "Non-file found in standard device location" )
358
+ }
359
+ } else {
360
+ // this should only trigger if we made a mistake in this crate
361
+ Err ( WasiFsError :: NoDevice )
362
+ }
363
+ }
364
+
294
365
fn get_next_inode_index ( & mut self ) -> u64 {
295
366
let next = self . inode_counter . get ( ) ;
296
367
self . inode_counter . set ( next + 1 ) ;
@@ -358,36 +429,31 @@ impl WasiFs {
358
429
fd : __wasi_fd_t ,
359
430
file : Box < dyn WasiFile > ,
360
431
) -> Result < Option < Box < dyn WasiFile > > , WasiFsError > {
432
+ let mut ret = Some ( file) ;
361
433
match fd {
362
434
__WASI_STDIN_FILENO => {
363
- let mut ret = file;
364
- std:: mem:: swap ( & mut self . stdin , & mut ret) ;
365
- Ok ( Some ( ret) )
435
+ std:: mem:: swap ( self . stdin_mut ( ) ?, & mut ret) ;
366
436
}
367
437
__WASI_STDOUT_FILENO => {
368
- let mut ret = file;
369
- std:: mem:: swap ( & mut self . stdout , & mut ret) ;
370
- Ok ( Some ( ret) )
438
+ std:: mem:: swap ( self . stdout_mut ( ) ?, & mut ret) ;
371
439
}
372
440
__WASI_STDERR_FILENO => {
373
- let mut ret = file;
374
- std:: mem:: swap ( & mut self . stderr , & mut ret) ;
375
- Ok ( Some ( ret) )
441
+ std:: mem:: swap ( self . stderr_mut ( ) ?, & mut ret) ;
376
442
}
377
443
_ => {
378
444
let base_fd = self . get_fd ( fd) . map_err ( WasiFsError :: from_wasi_err) ?;
379
445
let base_inode = base_fd. inode ;
380
446
381
447
match & mut self . inodes [ base_inode] . kind {
382
448
Kind :: File { ref mut handle, .. } => {
383
- let mut ret = Some ( file) ;
384
449
std:: mem:: swap ( handle, & mut ret) ;
385
- Ok ( ret)
386
450
}
387
451
_ => return Err ( WasiFsError :: NotAFile ) ,
388
452
}
389
453
}
390
454
}
455
+
456
+ Ok ( ret)
391
457
}
392
458
393
459
/// refresh size from filesystem
@@ -733,6 +799,17 @@ impl WasiFs {
733
799
}
734
800
735
801
pub fn fdstat ( & self , fd : __wasi_fd_t ) -> Result < __wasi_fdstat_t , __wasi_errno_t > {
802
+ match fd {
803
+ __WASI_STDOUT_FILENO => {
804
+ return Ok ( __wasi_fdstat_t {
805
+ fs_filetype : __WASI_FILETYPE_CHARACTER_DEVICE,
806
+ fs_flags : 0 ,
807
+ fs_rights_base : ALL_RIGHTS ,
808
+ fs_rights_inheriting : ALL_RIGHTS ,
809
+ } )
810
+ }
811
+ _ => ( ) ,
812
+ }
736
813
let fd = self . get_fd ( fd) ?;
737
814
738
815
debug ! ( "fdstat: {:?}" , fd) ;
@@ -773,8 +850,18 @@ impl WasiFs {
773
850
pub fn flush ( & mut self , fd : __wasi_fd_t ) -> Result < ( ) , __wasi_errno_t > {
774
851
match fd {
775
852
__WASI_STDIN_FILENO => ( ) ,
776
- __WASI_STDOUT_FILENO => self . stdout . flush ( ) . map_err ( |_| __WASI_EIO) ?,
777
- __WASI_STDERR_FILENO => self . stderr . flush ( ) . map_err ( |_| __WASI_EIO) ?,
853
+ __WASI_STDOUT_FILENO => self
854
+ . stdout_mut ( )
855
+ . map_err ( WasiFsError :: into_wasi_err) ?
856
+ . as_mut ( )
857
+ . and_then ( |f| f. flush ( ) . ok ( ) )
858
+ . ok_or ( __WASI_EIO) ?,
859
+ __WASI_STDERR_FILENO => self
860
+ . stderr_mut ( )
861
+ . map_err ( WasiFsError :: into_wasi_err) ?
862
+ . as_mut ( )
863
+ . and_then ( |f| f. flush ( ) . ok ( ) )
864
+ . ok_or ( __WASI_EIO) ?,
778
865
_ => {
779
866
let fd = self . fd_map . get ( & fd) . ok_or ( __WASI_EBADF) ?;
780
867
if fd. rights & __WASI_RIGHT_FD_DATASYNC == 0 {
@@ -881,13 +968,78 @@ impl WasiFs {
881
968
} ;
882
969
883
970
self . inodes . insert ( InodeVal {
884
- stat : stat ,
971
+ stat,
885
972
is_preopened : true ,
886
973
name : "/" . to_string ( ) ,
887
974
kind : root_kind,
888
975
} )
889
976
}
890
977
978
+ fn create_stdout ( & mut self ) {
979
+ self . create_std_dev_inner (
980
+ Box :: new ( Stdout ) ,
981
+ "stdout" ,
982
+ __WASI_STDOUT_FILENO,
983
+ STDOUT_DEFAULT_RIGHTS ,
984
+ __WASI_FDFLAG_APPEND,
985
+ ) ;
986
+ }
987
+ fn create_stdin ( & mut self ) {
988
+ self . create_std_dev_inner (
989
+ Box :: new ( Stdin ) ,
990
+ "stdin" ,
991
+ __WASI_STDIN_FILENO,
992
+ STDIN_DEFAULT_RIGHTS ,
993
+ 0 ,
994
+ ) ;
995
+ }
996
+ fn create_stderr ( & mut self ) {
997
+ self . create_std_dev_inner (
998
+ Box :: new ( Stderr ) ,
999
+ "stderr" ,
1000
+ __WASI_STDERR_FILENO,
1001
+ STDERR_DEFAULT_RIGHTS ,
1002
+ __WASI_FDFLAG_APPEND,
1003
+ ) ;
1004
+ }
1005
+
1006
+ fn create_std_dev_inner (
1007
+ & mut self ,
1008
+ handle : Box < dyn WasiFile > ,
1009
+ name : & ' static str ,
1010
+ raw_fd : __wasi_fd_t ,
1011
+ rights : __wasi_rights_t ,
1012
+ fd_flags : __wasi_fdflags_t ,
1013
+ ) {
1014
+ let stat = __wasi_filestat_t {
1015
+ st_filetype : __WASI_FILETYPE_CHARACTER_DEVICE,
1016
+ st_ino : self . get_next_inode_index ( ) ,
1017
+ ..__wasi_filestat_t:: default ( )
1018
+ } ;
1019
+ let kind = Kind :: File {
1020
+ handle : Some ( handle) ,
1021
+ path : "" . into ( ) ,
1022
+ } ;
1023
+ let inode = self . inodes . insert ( InodeVal {
1024
+ stat,
1025
+ is_preopened : true ,
1026
+ name : name. to_string ( ) ,
1027
+ kind,
1028
+ } ) ;
1029
+ self . fd_map . insert (
1030
+ raw_fd,
1031
+ Fd {
1032
+ rights,
1033
+ rights_inheriting : 0 ,
1034
+ flags : fd_flags,
1035
+ // since we're not calling open on this, we don't need open flags
1036
+ open_flags : 0 ,
1037
+ offset : 0 ,
1038
+ inode,
1039
+ } ,
1040
+ ) ;
1041
+ }
1042
+
891
1043
pub fn get_stat_for_kind ( & self , kind : & Kind ) -> Option < __wasi_filestat_t > {
892
1044
let md = match kind {
893
1045
Kind :: File { handle, path } => match handle {
0 commit comments