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::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}