Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/c-api/src/wasm_c_api/wasi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ fn prepare_webc_env(
package_name: &str,
) -> Option<(WasiFunctionEnv, Imports)> {
use virtual_fs::static_fs::StaticFileSystem;
use wasmer_wasix::virtual_fs::FileSystem;
use webc::v1::{FsEntryType, WebC};

let store_mut = store.as_store_mut();
Expand Down Expand Up @@ -298,7 +299,8 @@ fn prepare_webc_env(
})
.collect::<Vec<_>>();

let filesystem = Box::new(StaticFileSystem::init(slice, package_name)?);
let filesystem =
Arc::new(StaticFileSystem::init(slice, package_name)?) as Arc<dyn FileSystem + Send + Sync>;
let mut builder = config.builder.runtime(Arc::new(rt));

if !config.inherit_stdout {
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/src/commands/run/wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ impl Wasi {
if !mapped_dirs.is_empty() {
// TODO: should we expose the common ancestor instead of root?
let fs_backing: Arc<dyn FileSystem + Send + Sync> =
Arc::new(PassthruFileSystem::new(default_fs_backing()));
Arc::new(PassthruFileSystem::new_arc(default_fs_backing()));
for MappedDirectory { host, guest } in self.mapped_dirs.clone() {
let host = if !host.is_absolute() {
Path::new("/").join(host)
Expand Down
15 changes: 12 additions & 3 deletions lib/virtual-fs/src/passthru_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,24 @@
//! needed so that a `Box<dyn VirtualFileSystem>` can be wrapped in an Arc and
//! shared - some of the interfaces pass around a `Box<dyn VirtualFileSystem>`

use std::path::Path;
use std::{path::Path, sync::Arc};

use crate::*;

#[derive(Debug)]
pub struct PassthruFileSystem {
fs: Box<dyn FileSystem + Send + Sync + 'static>,
fs: Arc<dyn FileSystem + Send + Sync + 'static>,
}

impl PassthruFileSystem {
/// Creates a new PassthruFileSystem that wraps the given FileSystem.
// NOTE: only kept for backwards compatibility.
// TODO: change to only accept Arc, and remove Self::new_arc in the next breaking API change!
pub fn new(inner: Box<dyn FileSystem + Send + Sync + 'static>) -> Self {
Self { fs: inner.into() }
}

pub fn new_arc(inner: Arc<dyn FileSystem + Send + Sync + 'static>) -> Self {
Self { fs: inner }
}
}
Expand Down Expand Up @@ -66,6 +73,8 @@ impl FileSystem for PassthruFileSystem {

#[cfg(test)]
mod test_builder {
use std::sync::Arc;

use tokio::io::{AsyncReadExt, AsyncWriteExt};

use crate::{FileSystem, PassthruFileSystem};
Expand Down Expand Up @@ -96,7 +105,7 @@ mod test_builder {
.unwrap();
assert_eq!(buf, b"hello");

let passthru_fs = PassthruFileSystem::new(Box::new(mem_fs.clone()));
let passthru_fs = PassthruFileSystem::new_arc(Arc::new(mem_fs.clone()));
let mut buf = Vec::new();
passthru_fs
.new_open_options()
Expand Down
54 changes: 53 additions & 1 deletion lib/virtual-fs/src/union_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::*;

use std::{path::Path, sync::Arc};

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct MountPoint {
pub path: PathBuf,
pub name: String,
Expand Down Expand Up @@ -36,6 +36,17 @@ pub struct UnionFileSystem {
pub mounts: DashMap<PathBuf, MountPoint>,
}

/// Defines how to handle conflicts when merging two UnionFileSystems
#[derive(Clone, Copy, Debug)]
pub enum UnionMergeMode {
/// Replace existing nodes with the new ones.
Replace,
/// Skip conflicting nodes, and keep the existing ones.
Skip,
/// Return an error if a conflict is found.
Fail,
}

impl UnionFileSystem {
pub fn new() -> Self {
Self::default()
Expand All @@ -58,6 +69,47 @@ impl UnionFileSystem {
.to_owned()
}
}

/// Merge another UnionFileSystem into this one.
pub fn merge(&self, other: &UnionFileSystem, mode: UnionMergeMode) -> Result<()> {
for item in other.mounts.iter() {
if self.mounts.contains_key(item.key()) {
match mode {
UnionMergeMode::Replace => {
self.mounts.insert(item.key().clone(), item.value().clone());
}
UnionMergeMode::Skip => {
tracing::debug!(
path = %item.key().display(),
"skipping existing mount point while merging two union file systems"
);
}
UnionMergeMode::Fail => {
return Err(FsError::AlreadyExists);
}
}
} else {
self.mounts.insert(item.key().clone(), item.value().clone());
}
}

Ok(())
}

/// Duplicate this UnionFileSystem.
///
/// This differs from the Clone implementation in that it creates a new
/// underlying shared map.
/// Clone just does a shallow copy.
pub fn duplicate(&self) -> Self {
let mounts = DashMap::new();

for item in self.mounts.iter() {
mounts.insert(item.key().clone(), item.value().clone());
}

Self { mounts }
}
}

impl UnionFileSystem {
Expand Down
15 changes: 10 additions & 5 deletions lib/wasix/src/bin_factory/binary_package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{path::Path, sync::Arc};
use anyhow::Context;
use once_cell::sync::OnceCell;
use sha2::Digest;
use virtual_fs::FileSystem;
use virtual_fs::UnionFileSystem;
use wasmer_config::package::{
PackageHash, PackageId, PackageSource, SuggestedCompilerOptimizations,
};
Expand Down Expand Up @@ -90,7 +90,10 @@ pub struct BinaryPackage {
/// entrypoint.
pub entrypoint_cmd: Option<String>,
pub hash: OnceCell<ModuleHash>,
pub webc_fs: Arc<dyn FileSystem + Send + Sync>,
// TODO: using a UnionFileSystem here directly is suboptimal, since cloning
// it is expensive. Should instead store an immutable map that can easily
// be converted into a dashmap.
pub webc_fs: Option<Arc<UnionFileSystem>>,
pub commands: Vec<BinaryPackageCommand>,
pub uses: Vec<String>,
pub file_system_memory_footprint: u64,
Expand Down Expand Up @@ -264,7 +267,7 @@ impl BinaryPackage {
mod tests {
use sha2::Digest;
use tempfile::TempDir;
use virtual_fs::AsyncReadExt;
use virtual_fs::{AsyncReadExt, FileSystem as _};
use wasmer_package::utils::from_disk;

use crate::{
Expand Down Expand Up @@ -326,6 +329,8 @@ mod tests {
// "/public/file.txt" on the guest.
let mut f = pkg
.webc_fs
.as_ref()
.expect("no webc fs")
.new_open_options()
.read(true)
.open("/public/file.txt")
Expand All @@ -352,10 +357,10 @@ mod tests {
name = "foo"
source = "foo.wasm"
abi = "wasi"

[[command]]
name = "cmd"
module = "foo"
module = "foo"
"#;
let manifest = temp.path().join("wasmer.toml");
std::fs::write(&manifest, wasmer_toml).unwrap();
Expand Down
Loading
Loading