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