1use 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}