@@ -12,9 +12,11 @@ module Wasmtime
1212 # Compile module only once for speed
1313 @compiled_wasi_module = @engine . precompile_module ( IO . binread ( "spec/fixtures/wasi-debug.wasm" ) )
1414 @compiled_wasi_deterministic_module = @engine . precompile_module ( IO . binread ( "spec/fixtures/wasi-deterministic.wasm" ) )
15+ @compiled_wasi_fs_module = @engine . precompile_module ( IO . binread ( "spec/fixtures/wasi-fs.wasm" ) )
1516
1617 @compiled_wasi_component = @engine . precompile_component ( IO . binread ( "spec/fixtures/wasi-debug-p2.wasm" ) )
1718 @compiled_wasi_deterministic_component = @engine . precompile_component ( IO . binread ( "spec/fixtures/wasi-deterministic-p2.wasm" ) )
19+ @compiled_wasi_fs_component = @engine . precompile_component ( IO . binread ( "spec/fixtures/wasi-fs-p2.wasm" ) )
1820 end
1921
2022 describe "Linker.new" do
@@ -233,13 +235,103 @@ module Wasmtime
233235 end
234236 end
235237 end
238+
239+ it "writes to mapped directory" do
240+ Dir . mkdir ( tempfile_path ( "tmp" ) )
241+ File . write ( tempfile_path ( File . join ( "tmp" , "counter" ) ) , "0" )
242+
243+ wasi_config = WasiConfig . new
244+ . set_argv ( [ "wasi-fs" , "/tmp/counter" ] )
245+ . set_mapped_directory ( tempfile_path ( "tmp" ) , "/tmp" , :all , :all )
246+
247+ expect { run_fs . call ( wasi_config ) } . not_to raise_error
248+
249+ expect ( File . read ( tempfile_path ( File . join ( "tmp" , "counter" ) ) ) ) . to eq ( "1" )
250+ end
251+
252+ it "fails to write to mapped directory if not permitted" do
253+ Dir . mkdir ( tempfile_path ( "tmp" ) )
254+ File . write ( tempfile_path ( File . join ( "tmp" , "counter" ) ) , "0" )
255+
256+ stderr_str = ""
257+ wasi_config = WasiConfig . new
258+ . set_argv ( [ "wasi-fs" , "/tmp/counter" ] )
259+ . set_stderr_buffer ( stderr_str , 40000 )
260+ . set_mapped_directory ( tempfile_path ( "tmp" ) , "/tmp" , :read , :read )
261+
262+ expect { run_fs . call ( wasi_config ) } . to raise_error do |error |
263+ expect ( error ) . to be_a ( Wasmtime ::Error )
264+ end
265+
266+ expect ( stderr_str ) . to match ( /failed to create counter file/ )
267+
268+ expect ( File . read ( tempfile_path ( File . join ( "tmp" , "counter" ) ) ) ) . to eq ( "0" )
269+ end
270+
271+ it "fails to read from mapped directory if not permitted" do
272+ Dir . mkdir ( tempfile_path ( "tmp" ) )
273+ File . write ( tempfile_path ( File . join ( "tmp" , "counter" ) ) , "0" )
274+
275+ stderr_str = ""
276+ wasi_config = WasiConfig . new
277+ . set_argv ( [ "wasi-fs" , "/tmp/counter" ] )
278+ . set_stderr_buffer ( stderr_str , 40000 )
279+ . set_mapped_directory ( tempfile_path ( "tmp" ) , "/tmp" , :mutate , :write )
280+
281+ expect { run_fs . call ( wasi_config ) } . to raise_error do |error |
282+ expect ( error ) . to be_a ( Wasmtime ::Error )
283+ end
284+
285+ expect ( stderr_str ) . to match ( /failed to open counter file/ )
286+
287+ expect ( File . read ( tempfile_path ( File . join ( "tmp" , "counter" ) ) ) ) . to eq ( "0" )
288+ end
289+
290+ it "fails to access non-mapped directories" do
291+ Dir . mkdir ( tempfile_path ( "tmp" ) )
292+ File . write ( tempfile_path ( File . join ( "tmp" , "counter" ) ) , "0" )
293+
294+ stderr_str = ""
295+ wasi_config = WasiConfig . new
296+ . set_argv ( [ "wasi-fs" , File . join ( tempfile_path ( "tmp" ) , "counter" ) ] )
297+ . set_stderr_buffer ( stderr_str , 40000 )
298+
299+ expect { run_fs . call ( wasi_config ) } . to raise_error do |error |
300+ expect ( error ) . to be_a ( Wasmtime ::Error )
301+ end
302+
303+ expect ( stderr_str ) . to match ( /failed to find a pre-opened file descriptor/ )
304+
305+ expect ( File . read ( tempfile_path ( File . join ( "tmp" , "counter" ) ) ) ) . to eq ( "0" )
306+ end
307+
308+ it "does not accept an invalid host path" do
309+ wasi_config = WasiConfig . new
310+ . set_mapped_directory ( tempfile_path ( "tmp" ) , "/tmp" , :all , :all )
311+
312+ expect { run_fs . call ( wasi_config ) } . to raise_error do |error |
313+ expect ( error ) . to be_a ( Wasmtime ::Error )
314+ # error message is os-specific
315+ end
316+ end
317+
318+ it "does not accept invalid permissions" do
319+ wasi_config = WasiConfig . new
320+ . set_mapped_directory ( tempfile_path ( "tmp" ) , "/tmp" , :mutate , :invalid_permission )
321+
322+ expect { run_fs . call ( wasi_config ) } . to raise_error do |error |
323+ expect ( error ) . to be_a ( Wasmtime ::Error )
324+ expect ( error . message ) . to match ( /Invalid file_perms: invalid_permission. Use one of :read, :write, or :all/ )
325+ end
326+ end
236327 end
237328
238329 describe "WasiConfig preview 1" do
239330 it_behaves_like WasiConfig do
240331 let ( :run ) { method ( :run_wasi_module ) }
241332 let ( :wasi_env ) { method ( :wasi_module_env ) }
242333 let ( :run_deterministic ) { method ( :run_wasi_module_deterministic ) }
334+ let ( :run_fs ) { method ( :run_wasi_module_fs ) }
243335 end
244336 end
245337
@@ -248,6 +340,7 @@ module Wasmtime
248340 let ( :run ) { method ( :run_wasi_component ) }
249341 let ( :wasi_env ) { method ( :wasi_component_env ) }
250342 let ( :run_deterministic ) { method ( :run_wasi_component_deterministic ) }
343+ let ( :run_fs ) { method ( :run_wasi_component_fs ) }
251344 end
252345 end
253346
@@ -272,6 +365,13 @@ def run_wasi_module_deterministic(wasi_config)
272365 . invoke ( "_start" )
273366 end
274367
368+ def run_wasi_module_fs ( wasi_config )
369+ linker = Linker . new ( @engine )
370+ WASI ::P1 . add_to_linker_sync ( linker )
371+ store = Store . new ( @engine , wasi_p1_config : wasi_config )
372+ linker . instantiate ( store , Module . deserialize ( @engine , @compiled_wasi_fs_module ) ) . invoke ( "_start" )
373+ end
374+
275375 def wasi_module_env
276376 stdout_file = tempfile_path ( "stdout" )
277377
@@ -318,6 +418,17 @@ def run_wasi_component_deterministic(wasi_config)
318418 ) . call_run ( store )
319419 end
320420
421+ def run_wasi_component_fs ( wasi_config )
422+ linker = Component ::Linker . new ( @engine )
423+ WASI ::P2 . add_to_linker_sync ( linker )
424+ store = Store . new ( @engine , wasi_config : wasi_config )
425+ Component ::WasiCommand . new (
426+ store ,
427+ Component ::Component . deserialize ( @engine , @compiled_wasi_fs_component ) ,
428+ linker
429+ ) . call_run ( store )
430+ end
431+
321432 def tempfile_path ( name )
322433 File . join ( tmpdir , name )
323434 end
0 commit comments