wasmtime_c_api/
wasi.rs

1//! The WASI embedding API definitions for Wasmtime.
2
3use crate::wasm_byte_vec_t;
4use anyhow::Result;
5use std::ffi::{c_char, CStr};
6use std::fs::File;
7use std::path::Path;
8use std::slice;
9use wasmtime_wasi::{preview1::WasiP1Ctx, WasiCtxBuilder};
10
11unsafe fn cstr_to_path<'a>(path: *const c_char) -> Option<&'a Path> {
12    CStr::from_ptr(path).to_str().map(Path::new).ok()
13}
14
15unsafe fn cstr_to_str<'a>(s: *const c_char) -> Option<&'a str> {
16    CStr::from_ptr(s).to_str().ok()
17}
18
19unsafe fn open_file(path: *const c_char) -> Option<File> {
20    File::open(cstr_to_path(path)?).ok()
21}
22
23unsafe fn create_file(path: *const c_char) -> Option<File> {
24    File::create(cstr_to_path(path)?).ok()
25}
26
27#[repr(C)]
28pub struct wasi_config_t {
29    builder: WasiCtxBuilder,
30}
31
32wasmtime_c_api_macros::declare_own!(wasi_config_t);
33
34impl wasi_config_t {
35    pub fn into_wasi_ctx(mut self) -> Result<WasiP1Ctx> {
36        Ok(self.builder.build_p1())
37    }
38}
39
40#[unsafe(no_mangle)]
41pub extern "C" fn wasi_config_new() -> Box<wasi_config_t> {
42    Box::new(wasi_config_t {
43        builder: WasiCtxBuilder::new(),
44    })
45}
46
47#[unsafe(no_mangle)]
48pub unsafe extern "C" fn wasi_config_set_argv(
49    config: &mut wasi_config_t,
50    argc: usize,
51    argv: *const *const c_char,
52) -> bool {
53    for arg in slice::from_raw_parts(argv, argc) {
54        let arg = match CStr::from_ptr(*arg).to_str() {
55            Ok(s) => s,
56            Err(_) => return false,
57        };
58        config.builder.arg(arg);
59    }
60    true
61}
62
63#[unsafe(no_mangle)]
64pub extern "C" fn wasi_config_inherit_argv(config: &mut wasi_config_t) {
65    config.builder.inherit_args();
66}
67
68#[unsafe(no_mangle)]
69pub unsafe extern "C" fn wasi_config_set_env(
70    config: &mut wasi_config_t,
71    envc: usize,
72    names: *const *const c_char,
73    values: *const *const c_char,
74) -> bool {
75    let names = slice::from_raw_parts(names, envc);
76    let values = slice::from_raw_parts(values, envc);
77
78    for (k, v) in names.iter().zip(values) {
79        let k = match cstr_to_str(*k) {
80            Some(s) => s,
81            None => return false,
82        };
83        let v = match cstr_to_str(*v) {
84            Some(s) => s,
85            None => return false,
86        };
87        config.builder.env(k, v);
88    }
89    true
90}
91
92#[unsafe(no_mangle)]
93pub extern "C" fn wasi_config_inherit_env(config: &mut wasi_config_t) {
94    config.builder.inherit_env();
95}
96
97#[unsafe(no_mangle)]
98pub unsafe extern "C" fn wasi_config_set_stdin_file(
99    config: &mut wasi_config_t,
100    path: *const c_char,
101) -> bool {
102    let file = match open_file(path) {
103        Some(f) => f,
104        None => return false,
105    };
106
107    let file = tokio::fs::File::from_std(file);
108    let stdin_stream =
109        wasmtime_wasi::AsyncStdinStream::new(wasmtime_wasi::pipe::AsyncReadStream::new(file));
110    config.builder.stdin(stdin_stream);
111
112    true
113}
114
115#[unsafe(no_mangle)]
116pub unsafe extern "C" fn wasi_config_set_stdin_bytes(
117    config: &mut wasi_config_t,
118    binary: &mut wasm_byte_vec_t,
119) {
120    let binary = binary.take();
121    let binary = wasmtime_wasi::pipe::MemoryInputPipe::new(binary);
122    config.builder.stdin(binary);
123}
124
125#[unsafe(no_mangle)]
126pub extern "C" fn wasi_config_inherit_stdin(config: &mut wasi_config_t) {
127    config.builder.inherit_stdin();
128}
129
130#[unsafe(no_mangle)]
131pub unsafe extern "C" fn wasi_config_set_stdout_file(
132    config: &mut wasi_config_t,
133    path: *const c_char,
134) -> bool {
135    let file = match create_file(path) {
136        Some(f) => f,
137        None => return false,
138    };
139
140    config.builder.stdout(wasmtime_wasi::OutputFile::new(file));
141
142    true
143}
144
145#[unsafe(no_mangle)]
146pub extern "C" fn wasi_config_inherit_stdout(config: &mut wasi_config_t) {
147    config.builder.inherit_stdout();
148}
149
150#[unsafe(no_mangle)]
151pub unsafe extern "C" fn wasi_config_set_stderr_file(
152    config: &mut wasi_config_t,
153    path: *const c_char,
154) -> bool {
155    let file = match create_file(path) {
156        Some(f) => f,
157        None => return false,
158    };
159
160    config.builder.stderr(wasmtime_wasi::OutputFile::new(file));
161
162    true
163}
164
165#[unsafe(no_mangle)]
166pub extern "C" fn wasi_config_inherit_stderr(config: &mut wasi_config_t) {
167    config.builder.inherit_stderr();
168}
169
170#[unsafe(no_mangle)]
171pub unsafe extern "C" fn wasi_config_preopen_dir(
172    config: &mut wasi_config_t,
173    path: *const c_char,
174    guest_path: *const c_char,
175    dir_perms: usize,
176    file_perms: usize,
177) -> bool {
178    let guest_path = match cstr_to_str(guest_path) {
179        Some(p) => p,
180        None => return false,
181    };
182
183    let host_path = match cstr_to_path(path) {
184        Some(p) => p,
185        None => return false,
186    };
187
188    let dir_perms = match wasmtime_wasi::DirPerms::from_bits(dir_perms) {
189        Some(p) => p,
190        None => return false,
191    };
192
193    let file_perms = match wasmtime_wasi::FilePerms::from_bits(file_perms) {
194        Some(p) => p,
195        None => return false,
196    };
197
198    config
199        .builder
200        .preopened_dir(host_path, guest_path, dir_perms, file_perms)
201        .is_ok()
202}