Skip to content

Commit 0400633

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 0400633

File tree

1 file changed

+104
-1
lines changed

1 file changed

+104
-1
lines changed

ext/src/ruby_api/wasi_config.rs

Lines changed: 104 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,40 @@ 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 mapped_directory = RArray::new();
259+
mapped_directory.push(host_path).unwrap();
260+
mapped_directory.push(guest_path).unwrap();
261+
mapped_directory.push(dir_perms).unwrap();
262+
mapped_directory.push(file_perms).unwrap();
263+
264+
let init_directory = RArray::new();
265+
266+
let mut inner = rb_self.inner.borrow_mut();
267+
if inner.mapped_directories.is_none() {
268+
inner.mapped_directories = Some(init_directory.into());
269+
}
270+
271+
let ruby = Ruby::get().unwrap();
272+
let mapped_directories = ruby.get_inner(inner.mapped_directories.unwrap());
273+
mapped_directories.push(mapped_directory).unwrap();
274+
rb_self
275+
}
276+
236277
pub fn build_p1(&self, ruby: &Ruby) -> Result<WasiP1Ctx, Error> {
237278
let mut builder = self.build_impl(ruby)?;
238279
let ctx = builder.build_p1();
@@ -317,6 +358,63 @@ impl WasiConfig {
317358
deterministic_wasi_ctx::add_determinism_to_wasi_ctx_builder(&mut builder);
318359
}
319360

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

356454
class.define_method("set_argv", method!(WasiConfig::set_argv, 1))?;
357455

456+
class.define_method(
457+
"set_mapped_directory",
458+
method!(WasiConfig::set_mapped_directory, 4),
459+
)?;
460+
358461
Ok(())
359462
}

0 commit comments

Comments
 (0)