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