Skip to content

Commit 165cf11

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 165cf11

File tree

1 file changed

+92
-1
lines changed

1 file changed

+92
-1
lines changed

ext/src/ruby_api/wasi_config.rs

Lines changed: 92 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, Symbol, Ruby, 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,54 @@ 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)?).unwrap().name()?;
367+
let file_perms = Symbol::from_value(mapped_directory.entry(3)?).unwrap().name()?;
368+
369+
let host_path_dir = Path::new(&host_path);
370+
let guest_path_path = guest_path.as_str();
371+
372+
// Convert to FilePerms and DirPerms enums
373+
let dir_perms_flags;
374+
match dir_perms {
375+
std::borrow::Cow::Borrowed("read") => dir_perms_flags = DirPerms::READ,
376+
std::borrow::Cow::Borrowed("mutate") => dir_perms_flags = DirPerms::MUTATE,
377+
std::borrow::Cow::Borrowed("all") => dir_perms_flags = DirPerms::all(),
378+
_ => {
379+
return Err(error!(
380+
"Invalid dir_perms: {}. Use one of :read, :mutate, or :all",
381+
dir_perms
382+
))
383+
}
384+
}
385+
386+
let file_perms_flags;
387+
match file_perms {
388+
std::borrow::Cow::Borrowed("read") => file_perms_flags = FilePerms::READ,
389+
std::borrow::Cow::Borrowed("write") => file_perms_flags = FilePerms::WRITE,
390+
std::borrow::Cow::Borrowed("all") => file_perms_flags = FilePerms::all(),
391+
_ => {
392+
return Err(error!(
393+
"Invalid file_perms: {}. Use one of :read, :write, or :all",
394+
file_perms
395+
))
396+
}
397+
}
398+
399+
builder
400+
.preopened_dir(host_path_dir, guest_path_path, dir_perms_flags, file_perms_flags)
401+
.map_err(|e| error!("{}", e))?;
402+
}
403+
}
404+
}
405+
320406
Ok(builder)
321407
}
322408
}
@@ -355,5 +441,10 @@ pub fn init() -> Result<(), Error> {
355441

356442
class.define_method("set_argv", method!(WasiConfig::set_argv, 1))?;
357443

444+
class.define_method(
445+
"set_mapped_directory",
446+
method!(WasiConfig::set_mapped_directory, 4),
447+
)?;
448+
358449
Ok(())
359450
}

0 commit comments

Comments
 (0)