Closed yagehu closed 4 years ago
You need to pick from the pre-opened directories.
Sorry if these are dumb questions... But how do I access pre-opened directories? Is there a convention for how they get passed to a Wasm module by the runtimes? Can you provide a minimal example?
Iterate over fd_prestat_get until it returns BADFD. Its up to the runtime how the preopen table is managed, for wasmtime it's via the --mapdir and --dir flags.
fd_prestat_get
is exactly what I'm looking for! Thanks.
For posterity, a short text format program that uses fd_prestat_get
:
;; Exit status codes:
;;
;; - 8: Could not find a preopened fd.
(module
(type (;0;) (func (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
(type (;1;) (func))
(type (;2;) (func (param i32 i32) (result i32)))
(type (;3;) (func (param i32)))
(type (;4;) (func (param i32) (result i32)))
(import "wasi_snapshot_preview1" "fd_prestat_get"
(func $__wasi_fd_prestat_get (type 2))
)
(import "wasi_snapshot_preview1" "path_open"
(func $__wasi_path_open (type 0))
)
(import "wasi_snapshot_preview1" "proc_exit"
(func $__wasi_proc_exit (type 3))
)
(func $_start (type 1)
(local $dirfd i32)
(local $errno i32)
(call $getFirstGoodDirfd (i32.const 0))
(if
(i32.ne (local.tee $errno) (i32.const 0))
(then
(call $__wasi_proc_exit (i32.const 8))
)
(else)
)
(local.set $dirfd (i32.load (i32.const 0)))
(call $__wasi_proc_exit (i32.const 0))
)
(func $getFirstGoodDirfd (type 4) (param $fd i32) (result i32)
(local $dirfd i32)
(local $errno i32)
;; Start with the lowest fd after stdin, stdout, and stderr.
(local.set $dirfd (i32.const 3))
(block ;; label = @1
(block ;; label = @2
(loop $loop ;; label = @3
(call $__wasi_fd_prestat_get
(local.get $dirfd)
(i32.const 0)
)
;; If errno is 0, we found a good dirfd. Break the loop.
(br_if 2 (;@1;) (i32.eq (local.tee $errno) (i32.const 0)))
;; If errno is 8, we encountered `badf`. Return 8 indicating failure.
(br_if 1 (;@2;) (i32.eq (local.get $errno) (i32.const 8)))
;; Increment dirfd.
(local.set $dirfd (i32.add (local.get $dirfd) (i32.const 1)))
(br $loop)
)
)
(return (i32.const 8))
)
(i32.store (local.get $fd) (local.get $dirfd))
i32.const 0
)
(memory (;0;) (export "memory") 1)
(export "_start" (func $_start))
)
Thank you so much for asking this question and the example @yagehu, and thank you for answering @caspervonb!
Is this documented anywhere? I looked at the API spec and was pretty confused.
I felt like there must be some sort of function which returns the preopened file descriptors, something like args/environ_sizes_get
. It seems odd that repeated syscalls are necessary to iterate.
I'm writing small WASI programs in text format to test the syscall support in various Wasm runtimes like Wasmtime and Wasmer. I'm trying to call
path_open
which I've imported as$__wasi_path_open
. According to the docs and this, the first argument to thepath_open
syscall is an fd for "the working directory at which the resolution of the path starts." How can I obtain such an fd?