11use super :: root;
22use crate :: error;
33use crate :: helpers:: OutputLimitedBuffer ;
4+ use crate :: ruby_api:: convert:: ToValType ;
5+ use crate :: { define_rb_intern, helpers:: SymbolEnum } ;
6+ use lazy_static:: lazy_static;
47use magnus:: {
58 class, function, gc:: Marker , method, typed_data:: Obj , value:: Opaque , DataTypeFunctions , Error ,
6- Module , Object , RArray , RHash , RString , Ruby , TryConvert , TypedData ,
9+ IntoValue , Module , Object , RArray , RHash , RString , Ruby , Symbol , TryConvert , TypedData , Value ,
710} ;
11+ use rb_sys:: ruby_rarray_flags:: RARRAY_EMBED_FLAG ;
812use std:: cell:: RefCell ;
13+ use std:: convert:: TryFrom ;
914use std:: fs;
15+ use std:: path:: Path ;
1016use std:: { fs:: File , path:: PathBuf } ;
1117use wasmtime_wasi:: p2:: pipe:: MemoryInputPipe ;
1218use wasmtime_wasi:: p2:: { OutputFile , WasiCtx , WasiCtxBuilder } ;
1319use wasmtime_wasi:: preview1:: WasiP1Ctx ;
20+ use wasmtime_wasi:: { DirPerms , FilePerms } ;
21+
22+ define_rb_intern ! (
23+ READ => "read" ,
24+ WRITE => "write" ,
25+ MUTATE => "mutate" ,
26+ ALL => "all" ,
27+ ) ;
28+
29+ lazy_static ! {
30+ static ref FILE_PERMS_MAPPING : SymbolEnum <' static , FilePerms > = {
31+ let mapping = vec![
32+ ( * READ , FilePerms :: READ ) ,
33+ ( * WRITE , FilePerms :: WRITE ) ,
34+ ( * ALL , FilePerms :: all( ) ) ,
35+ ] ;
36+
37+ SymbolEnum :: new( ":file_perms" , mapping)
38+ } ;
39+ static ref DIR_PERMS_MAPPING : SymbolEnum <' static , DirPerms > = {
40+ let mapping = vec![
41+ ( * READ , DirPerms :: READ ) ,
42+ ( * MUTATE , DirPerms :: MUTATE ) ,
43+ ( * ALL , DirPerms :: all( ) ) ,
44+ ] ;
45+
46+ SymbolEnum :: new( ":dir_perms" , mapping)
47+ } ;
48+ }
1449
1550enum ReadStream {
1651 Inherit ,
@@ -43,6 +78,24 @@ impl WriteStream {
4378 }
4479}
4580
81+ struct PermsSymbolEnum ( Symbol ) ;
82+
83+ #[ derive( Clone ) ]
84+ struct MappedDirectory {
85+ host_path : Opaque < RString > ,
86+ guest_path : Opaque < RString > ,
87+ dir_perms : Opaque < Symbol > ,
88+ file_perms : Opaque < Symbol > ,
89+ }
90+ impl MappedDirectory {
91+ pub fn mark ( & self , marker : & Marker ) {
92+ marker. mark ( self . host_path ) ;
93+ marker. mark ( self . guest_path ) ;
94+ marker. mark ( self . dir_perms ) ;
95+ marker. mark ( self . file_perms ) ;
96+ }
97+ }
98+
4699#[ derive( Default ) ]
47100struct WasiConfigInner {
48101 stdin : Option < ReadStream > ,
@@ -51,6 +104,7 @@ struct WasiConfigInner {
51104 env : Option < Opaque < RHash > > ,
52105 args : Option < Opaque < RArray > > ,
53106 deterministic : bool ,
107+ mapped_directories : Vec < MappedDirectory > ,
54108}
55109
56110impl WasiConfigInner {
@@ -70,6 +124,23 @@ impl WasiConfigInner {
70124 if let Some ( v) = self . args . as_ref ( ) {
71125 marker. mark ( * v) ;
72126 }
127+ for v in & self . mapped_directories {
128+ v. mark ( marker) ;
129+ }
130+ }
131+ }
132+
133+ impl TryFrom < PermsSymbolEnum > for DirPerms {
134+ type Error = magnus:: Error ;
135+ fn try_from ( value : PermsSymbolEnum ) -> Result < Self , Error > {
136+ DIR_PERMS_MAPPING . get ( value. 0 . into_value ( ) )
137+ }
138+ }
139+
140+ impl TryFrom < PermsSymbolEnum > for FilePerms {
141+ type Error = magnus:: Error ;
142+ fn try_from ( value : PermsSymbolEnum ) -> Result < Self , Error > {
143+ FILE_PERMS_MAPPING . get ( value. 0 . into_value ( ) )
73144 }
74145}
75146
@@ -233,6 +304,34 @@ impl WasiConfig {
233304 rb_self
234305 }
235306
307+ /// @yard
308+ /// Set mapped directory for host path and guest path.
309+ /// @param host_path [String]
310+ /// @param guest_path [String]
311+ /// @param dir_perms [Symbol] Directory permissions, one of :read, :mutate, or :all
312+ /// @param file_perms [Symbol] File permissions, one of :read, :write, or :all
313+ /// @def set_mapped_directory(host_path, guest_path, dir_perms, file_perms)
314+ /// @return [WasiConfig] +self+
315+ pub fn set_mapped_directory (
316+ rb_self : RbSelf ,
317+ host_path : RString ,
318+ guest_path : RString ,
319+ dir_perms : Symbol ,
320+ file_perms : Symbol ,
321+ ) -> RbSelf {
322+ let mapped_dir = MappedDirectory {
323+ host_path : host_path. into ( ) ,
324+ guest_path : guest_path. into ( ) ,
325+ dir_perms : dir_perms. into ( ) ,
326+ file_perms : file_perms. into ( ) ,
327+ } ;
328+
329+ let mut inner = rb_self. inner . borrow_mut ( ) ;
330+ inner. mapped_directories . push ( mapped_dir) ;
331+
332+ rb_self
333+ }
334+
236335 pub fn build_p1 ( & self , ruby : & Ruby ) -> Result < WasiP1Ctx , Error > {
237336 let mut builder = self . build_impl ( ruby) ?;
238337 let ctx = builder. build_p1 ( ) ;
@@ -317,6 +416,22 @@ impl WasiConfig {
317416 deterministic_wasi_ctx:: add_determinism_to_wasi_ctx_builder ( & mut builder) ;
318417 }
319418
419+ for mapped_dir in & inner. mapped_directories {
420+ let host_path = ruby. get_inner ( mapped_dir. host_path ) . to_string ( ) ?;
421+ let guest_path = ruby. get_inner ( mapped_dir. guest_path ) . to_string ( ) ?;
422+ let dir_perms = ruby. get_inner ( mapped_dir. dir_perms ) ;
423+ let file_perms = ruby. get_inner ( mapped_dir. file_perms ) ;
424+
425+ builder
426+ . preopened_dir (
427+ Path :: new ( & host_path) ,
428+ & guest_path,
429+ PermsSymbolEnum ( dir_perms) . try_into ( ) ?,
430+ PermsSymbolEnum ( file_perms) . try_into ( ) ?,
431+ )
432+ . map_err ( |e| error ! ( "{}" , e) ) ?;
433+ }
434+
320435 Ok ( builder)
321436 }
322437}
@@ -355,5 +470,10 @@ pub fn init() -> Result<(), Error> {
355470
356471 class. define_method ( "set_argv" , method ! ( WasiConfig :: set_argv, 1 ) ) ?;
357472
473+ class. define_method (
474+ "set_mapped_directory" ,
475+ method ! ( WasiConfig :: set_mapped_directory, 4 ) ,
476+ ) ?;
477+
358478 Ok ( ( ) )
359479}
0 commit comments