aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/os/os_wasi.odin114
-rw-r--r--core/sys/wasm/wasi/wasi_api.odin4
2 files changed, 115 insertions, 3 deletions
diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin
index 8a1acb194..d38e73c79 100644
--- a/core/os/os_wasi.odin
+++ b/core/os/os_wasi.odin
@@ -38,6 +38,112 @@ _alloc_command_line_arguments :: proc() -> (args: []string) {
return
}
+// WASI works with "preopened" directories, the environment retrieves directories
+// (for example with `wasmtime --dir=. module.wasm`) and those given directories
+// are the only ones accessible by the application.
+//
+// So in order to facilitate the `os` API (absolute paths etc.) we keep a list
+// of the given directories and match them when needed (notably `os.open`).
+
+@(private)
+Preopen :: struct {
+ fd: wasi.fd_t,
+ prefix: string,
+}
+@(private)
+preopens: [dynamic]Preopen
+
+@(private, init)
+init_preopens :: proc() {
+
+ strip_prefixes :: proc(path: string) -> string {
+ path := path
+ loop: for len(path) > 0 {
+ switch {
+ case path[0] == '/':
+ path = path[1:]
+ case len(path) > 2 && path[0] == '.' && path[1] == '/':
+ path = path[2:]
+ case len(path) == 1 && path[0] == '.':
+ path = path[1:]
+ case:
+ break loop
+ }
+ }
+ return path
+ }
+
+ loop: for fd := wasi.fd_t(3); ; fd += 1 {
+ desc, err := wasi.fd_prestat_get(fd)
+ #partial switch err {
+ case .BADF: break loop
+ case: panic("fd_prestat_get returned an unexpected error")
+ case .SUCCESS:
+ }
+
+ switch desc.tag {
+ case .DIR:
+ buf := make([]byte, desc.dir.pr_name_len) or_else panic("could not allocate memory for filesystem preopens")
+ if err = wasi.fd_prestat_dir_name(fd, buf); err != .SUCCESS {
+ panic("could not get filesystem preopen dir name")
+ }
+ append(&preopens, Preopen{fd, strip_prefixes(string(buf))})
+ }
+ }
+}
+
+wasi_match_preopen :: proc(path: string) -> (wasi.fd_t, string, bool) {
+
+ prefix_matches :: proc(prefix, path: string) -> bool {
+ // Empty is valid for any relative path.
+ if len(prefix) == 0 && len(path) > 0 && path[0] == '/' {
+ return true
+ }
+
+ if len(path) < len(prefix) {
+ return false
+ }
+
+ if path[:len(prefix)] != prefix {
+ return false
+ }
+
+ // Only match on full components.
+ i := len(prefix)
+ for i > 0 && prefix[i-1] == '/' {
+ i -= 1
+ }
+ return path[i] == '/'
+ }
+
+ path := path
+ for len(path) > 0 && path[0] == '/' {
+ path = path[1:]
+ }
+
+ match: Preopen
+ #reverse for preopen in preopens {
+ if (match.fd == 0 || len(preopen.prefix) > len(match.prefix)) && prefix_matches(preopen.prefix, path) {
+ match = preopen
+ }
+ }
+
+ if match.fd == 0 {
+ return 0, "", false
+ }
+
+ relative := path[len(match.prefix):]
+ for len(relative) > 0 && relative[0] == '/' {
+ relative = relative[1:]
+ }
+
+ if len(relative) == 0 {
+ relative = "."
+ }
+
+ return match.fd, relative, true
+}
+
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
iovs := wasi.ciovec_t(data)
n, err := wasi.fd_write(wasi.fd_t(fd), {iovs})
@@ -87,7 +193,13 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn
if mode & O_SYNC == O_SYNC {
fdflags += {.SYNC}
}
- fd, err := wasi.path_open(wasi.fd_t(current_dir),{.SYMLINK_FOLLOW},path,oflags,rights,{},fdflags)
+
+ dir_fd, relative, ok := wasi_match_preopen(path)
+ if !ok {
+ return INVALID_HANDLE, Errno(wasi.errno_t.BADF)
+ }
+
+ fd, err := wasi.path_open(dir_fd, {.SYMLINK_FOLLOW}, relative, oflags, rights, {}, fdflags)
return Handle(fd), Errno(err)
}
close :: proc(fd: Handle) -> Errno {
diff --git a/core/sys/wasm/wasi/wasi_api.odin b/core/sys/wasm/wasi/wasi_api.odin
index e9ceb4667..22abd8dc4 100644
--- a/core/sys/wasm/wasi/wasi_api.odin
+++ b/core/sys/wasm/wasi/wasi_api.odin
@@ -962,7 +962,7 @@ prestat_dir_t :: struct {
}
prestat_t :: struct {
- tag: u8,
+ tag: preopentype_t,
using u: struct {
dir: prestat_dir_t,
},
@@ -1158,7 +1158,7 @@ foreign wasi {
/**
* A buffer into which to write the preopened directory name.
*/
- path: string,
+ path: []byte,
) -> errno_t ---
/**
* Create a directory.