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::WasiCtxBuilder;
10use wasmtime_wasi::p1::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::cli::AsyncStdinStream::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::p2::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
141        .builder
142        .stdout(wasmtime_wasi::cli::OutputFile::new(file));
143
144    true
145}
146
147#[unsafe(no_mangle)]
148pub extern "C" fn wasi_config_inherit_stdout(config: &mut wasi_config_t) {
149    config.builder.inherit_stdout();
150}
151
152#[unsafe(no_mangle)]
153pub unsafe extern "C" fn wasi_config_set_stderr_file(
154    config: &mut wasi_config_t,
155    path: *const c_char,
156) -> bool {
157    let file = match create_file(path) {
158        Some(f) => f,
159        None => return false,
160    };
161
162    config
163        .builder
164        .stderr(wasmtime_wasi::cli::OutputFile::new(file));
165
166    true
167}
168
169#[unsafe(no_mangle)]
170pub extern "C" fn wasi_config_inherit_stderr(config: &mut wasi_config_t) {
171    config.builder.inherit_stderr();
172}
173
174#[unsafe(no_mangle)]
175pub unsafe extern "C" fn wasi_config_preopen_dir(
176    config: &mut wasi_config_t,
177    path: *const c_char,
178    guest_path: *const c_char,
179    dir_perms: usize,
180    file_perms: usize,
181) -> bool {
182    let guest_path = match cstr_to_str(guest_path) {
183        Some(p) => p,
184        None => return false,
185    };
186
187    let host_path = match cstr_to_path(path) {
188        Some(p) => p,
189        None => return false,
190    };
191
192    let dir_perms = match wasmtime_wasi::DirPerms::from_bits(dir_perms) {
193        Some(p) => p,
194        None => return false,
195    };
196
197    let file_perms = match wasmtime_wasi::FilePerms::from_bits(file_perms) {
198        Some(p) => p,
199        None => return false,
200    };
201
202    config
203        .builder
204        .preopened_dir(host_path, guest_path, dir_perms, file_perms)
205        .is_ok()
206}