Skip to content

Commit 6f09565

Browse files
alhafoudhwilliam-stacken
authored andcommitted
Implement preopened_dir using set_mapped_directory setting
Add support for directory and file permissions
1 parent a36c0a5 commit 6f09565

File tree

1 file changed

+101
-1
lines changed

1 file changed

+101
-1
lines changed

ext/src/ruby_api/wasi_config.rs

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ use crate::error;
33
use crate::helpers::OutputLimitedBuffer;
44
use magnus::{
55
class, function, gc::Marker, method, typed_data::Obj, value::Opaque, DataTypeFunctions, Error,
6-
Module, Object, RArray, RHash, RString, Ruby, TryConvert, TypedData,
6+
Module, Object, RArray, RHash, RString, Ruby, Symbol, TryConvert, TypedData,
77
};
8+
use rb_sys::ruby_rarray_flags::RARRAY_EMBED_FLAG;
89
use std::cell::RefCell;
910
use std::fs;
11+
use std::path::Path;
1012
use std::{fs::File, path::PathBuf};
1113
use wasmtime_wasi::p2::pipe::MemoryInputPipe;
1214
use wasmtime_wasi::p2::{OutputFile, WasiCtx, WasiCtxBuilder};
1315
use wasmtime_wasi::preview1::WasiP1Ctx;
16+
use wasmtime_wasi::{DirPerms, FilePerms};
1417

1518
enum ReadStream {
1619
Inherit,
@@ -51,6 +54,7 @@ struct WasiConfigInner {
5154
env: Option<Opaque<RHash>>,
5255
args: Option<Opaque<RArray>>,
5356
deterministic: bool,
57+
mapped_directories: Option<Opaque<RArray>>,
5458
}
5559

5660
impl WasiConfigInner {
@@ -70,6 +74,9 @@ impl WasiConfigInner {
7074
if let Some(v) = self.args.as_ref() {
7175
marker.mark(*v);
7276
}
77+
if let Some(v) = self.mapped_directories.as_ref() {
78+
marker.mark(*v);
79+
}
7380
}
7481
}
7582

@@ -233,6 +240,37 @@ impl WasiConfig {
233240
rb_self
234241
}
235242

243+
/// @yard
244+
/// Set mapped directory for host path and guest path.
245+
/// @param host_path [String]
246+
/// @param guest_path [String]
247+
/// @param dir_perms [Symbol] Directory permissions, one of :read, :mutate, or :all
248+
/// @param file_perms [Symbol] File permissions, one of :read, :write, or :all
249+
/// @def set_mapped_directory(host_path, guest_path, dir_perms, file_perms)
250+
/// @return [WasiConfig] +self+
251+
pub fn set_mapped_directory(
252+
rb_self: RbSelf,
253+
host_path: RString,
254+
guest_path: RString,
255+
dir_perms: Symbol,
256+
file_perms: Symbol,
257+
) -> RbSelf {
258+
let mut inner = rb_self.inner.borrow_mut();
259+
if inner.mapped_directories.is_none() {
260+
inner.mapped_directories = Some(RArray::new().into());
261+
}
262+
let mapped_directory = RArray::new();
263+
mapped_directory.push(host_path).unwrap();
264+
mapped_directory.push(guest_path).unwrap();
265+
mapped_directory.push(dir_perms).unwrap();
266+
mapped_directory.push(file_perms).unwrap();
267+
268+
let ruby = Ruby::get().unwrap();
269+
let mapped_directories = ruby.get_inner(inner.mapped_directories.unwrap());
270+
mapped_directories.push(mapped_directory).unwrap();
271+
rb_self
272+
}
273+
236274
pub fn build_p1(&self, ruby: &Ruby) -> Result<WasiP1Ctx, Error> {
237275
let mut builder = self.build_impl(ruby)?;
238276
let ctx = builder.build_p1();
@@ -317,6 +355,63 @@ impl WasiConfig {
317355
deterministic_wasi_ctx::add_determinism_to_wasi_ctx_builder(&mut builder);
318356
}
319357

358+
if let Some(mapped_directories) = inner.mapped_directories.as_ref() {
359+
for item in unsafe { ruby.get_inner(*mapped_directories).as_slice() } {
360+
let mapped_directory = RArray::try_convert(*item)?;
361+
if mapped_directory.len() == 4 {
362+
let host_path =
363+
RString::try_convert(mapped_directory.entry(0)?)?.to_string()?;
364+
let guest_path =
365+
RString::try_convert(mapped_directory.entry(1)?)?.to_string()?;
366+
let dir_perms = Symbol::from_value(mapped_directory.entry(2)?)
367+
.unwrap()
368+
.name()?;
369+
let file_perms = Symbol::from_value(mapped_directory.entry(3)?)
370+
.unwrap()
371+
.name()?;
372+
373+
let host_path_dir = Path::new(&host_path);
374+
let guest_path_path = guest_path.as_str();
375+
376+
// Convert to FilePerms and DirPerms enums
377+
let dir_perms_flags;
378+
match dir_perms {
379+
std::borrow::Cow::Borrowed("read") => dir_perms_flags = DirPerms::READ,
380+
std::borrow::Cow::Borrowed("mutate") => dir_perms_flags = DirPerms::MUTATE,
381+
std::borrow::Cow::Borrowed("all") => dir_perms_flags = DirPerms::all(),
382+
_ => {
383+
return Err(error!(
384+
"Invalid dir_perms: {}. Use one of :read, :mutate, or :all",
385+
dir_perms
386+
))
387+
}
388+
}
389+
390+
let file_perms_flags;
391+
match file_perms {
392+
std::borrow::Cow::Borrowed("read") => file_perms_flags = FilePerms::READ,
393+
std::borrow::Cow::Borrowed("write") => file_perms_flags = FilePerms::WRITE,
394+
std::borrow::Cow::Borrowed("all") => file_perms_flags = FilePerms::all(),
395+
_ => {
396+
return Err(error!(
397+
"Invalid file_perms: {}. Use one of :read, :write, or :all",
398+
file_perms
399+
))
400+
}
401+
}
402+
403+
builder
404+
.preopened_dir(
405+
host_path_dir,
406+
guest_path_path,
407+
dir_perms_flags,
408+
file_perms_flags,
409+
)
410+
.map_err(|e| error!("{}", e))?;
411+
}
412+
}
413+
}
414+
320415
Ok(builder)
321416
}
322417
}
@@ -355,5 +450,10 @@ pub fn init() -> Result<(), Error> {
355450

356451
class.define_method("set_argv", method!(WasiConfig::set_argv, 1))?;
357452

453+
class.define_method(
454+
"set_mapped_directory",
455+
method!(WasiConfig::set_mapped_directory, 4),
456+
)?;
457+
358458
Ok(())
359459
}

0 commit comments

Comments
 (0)