Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6676605
Import the cap-primitives crate
alexcrichton Aug 27, 2026
8c6d738
Get cap-primitives vendor compiling
alexcrichton Aug 27, 2026
f611129
Run `cargo fmt` over cap-primitives code
alexcrichton Aug 27, 2026
a86e176
Hook up `crate::filesystem::primitives`
alexcrichton Aug 27, 2026
64a701b
Remove code related to cfg(racy_asserts)
alexcrichton Aug 27, 2026
2b6cc09
Remove windows-specific cfgs
alexcrichton Aug 27, 2026
bf5fed7
Remove `arbitrary` integration in primitives
alexcrichton Aug 27, 2026
1cebfe4
Remove more optional usage of nightly features
alexcrichton Aug 27, 2026
657f2f1
Remove a number of dead imports
alexcrichton Aug 27, 2026
3e96333
Allow some preexisting warnings in imported code
alexcrichton Aug 27, 2026
4accdd8
Delete dead code
alexcrichton Aug 27, 2026
237b0a2
Import tests from cap-std
alexcrichton Aug 27, 2026
e7e01c7
Remove some tests we don't need
alexcrichton Aug 27, 2026
1eb7818
Get tests compiling
alexcrichton Aug 27, 2026
414d10b
Fix remaining crate compiler warnings
alexcrichton Aug 27, 2026
aee2a3a
Remove a test testing test-only code
alexcrichton Aug 27, 2026
4b00307
Quash some lints
alexcrichton Aug 27, 2026
98f8f07
Fix a panic on my local filesystem
alexcrichton Aug 27, 2026
1d216fb
Remove ambient-authority dependency
alexcrichton Aug 27, 2026
bee8c2a
Remove fs-set-times dependency
alexcrichton Aug 27, 2026
90662cf
Fixing tests
alexcrichton Aug 27, 2026
518af05
Remove io-extras dependency
alexcrichton Aug 27, 2026
9756392
Remove io-lifetimes dependency
alexcrichton Aug 27, 2026
a3d79a0
Remove the maybe-owned dependency
alexcrichton Aug 27, 2026
01c8596
Update vets
alexcrichton Aug 27, 2026
a57075a
Fix build on freebsd/macos
alexcrichton Aug 27, 2026
3d6dc64
Update wasi crate blurb
alexcrichton Aug 27, 2026
4fc0aa6
Fix android build
alexcrichton Aug 27, 2026
0d1754c
Fix illumos build
alexcrichton Aug 27, 2026
8e210f4
Fix windows build again
alexcrichton Aug 27, 2026
40a9a14
Fix many builds
alexcrichton Aug 27, 2026
d0682a5
Fix clippy lints
alexcrichton Aug 27, 2026
a80c848
Fix some tests on Windows
alexcrichton Aug 27, 2026
d19980b
Try to fix more windows tests
alexcrichton Aug 27, 2026
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
27 changes: 2 additions & 25 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 0 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -364,12 +364,7 @@ regalloc2 = "0.15.2"
wasip1 = { version = "1.0.0", default-features = false }

# cap-std family:
#
# Note that `cap-fs-ext` should be avoided where possible to use
# `cap-primitives` instead.
target-lexicon = "0.13.5"
cap-primitives = "4.0.3"
cap-fs-ext-avoid-using-this = { version = "4.0.3", package = 'cap-fs-ext' }
rustix = "1.1.4"
# wit-bindgen:
wit-bindgen = { version = "0.61.1", default-features = false }
Expand Down
6 changes: 4 additions & 2 deletions crates/wasi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ tokio = { workspace = true, features = ["time", "sync", "io-std", "io-util", "r
bytes = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true, features = ["std", "attributes"] }
cap-primitives = { workspace = true }
cap-fs-ext-avoid-using-this = { workspace = true }
public-cap-primitives = { version = "4.0.3", package = 'cap-primitives' }
bitflags = { workspace = true }
async-trait = { workspace = true }
futures = { workspace = true }
Expand All @@ -46,9 +45,11 @@ env_logger = { workspace = true }

[target.'cfg(unix)'.dependencies]
rustix = { workspace = true, features = ["event", "fs", "net"] }
rustix-linux-procfs = "0.1.1"

[target.'cfg(windows)'.dependencies]
rustix = { workspace = true, features = ["event", "net"] }
winx = "0.36.0"

[target.'cfg(windows)'.dependencies.windows-sys]
workspace = true
Expand All @@ -57,6 +58,7 @@ features = [
"Win32_Foundation",
"Win32_Storage_FileSystem",
"Win32_System_IO",
"Win32_System_Ioctl",
"Win32_System_Performance",
]

Expand Down
3 changes: 1 addition & 2 deletions crates/wasi/src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::filesystem::{Dir, WasiFilesystemCtx};
use crate::random::WasiRandomCtx;
use crate::sockets::{SocketAddrCheck, SocketAddrUse, WasiSocketsCtx};
use crate::{FsPerms, OpenMode};
use cap_primitives::ambient_authority;
use rand::Rng;
use std::future::Future;
use std::mem;
Expand Down Expand Up @@ -300,7 +299,7 @@ impl WasiCtxBuilder {
guest_path: impl AsRef<str>,
perms: FsPerms,
) -> Result<&mut Self> {
let dir = cap_primitives::fs::open_ambient_dir(host_path.as_ref(), ambient_authority())?;
let dir = crate::filesystem::primitives::open_ambient_dir(host_path.as_ref())?;
let open_mode = match perms {
FsPerms::ReadOnly => OpenMode::READ,
FsPerms::ReadWrite => OpenMode::READ | OpenMode::WRITE,
Expand Down
70 changes: 35 additions & 35 deletions crates/wasi/src/filesystem.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::clocks::Datetime;
use crate::filesystem::primitives::{DirOptions, FollowSymlinks, Metadata, OpenOptions};
use crate::runtime::{AbortOnDropJoinHandle, spawn_blocking};
use cap_primitives::fs::{DirOptions, FollowSymlinks, Metadata, OpenOptions, SystemTimeSpec};
use std::collections::hash_map;
use std::sync::Arc;
use std::time::SystemTime;
Expand All @@ -17,6 +17,8 @@ pub(crate) mod windows;
#[cfg(windows)]
pub(crate) use windows as sys;

pub(crate) mod primitives;

/// A helper struct which implements [`HasData`] for the `wasi:filesystem` APIs.
///
/// This can be useful when directly calling `add_to_linker` functions directly,
Expand Down Expand Up @@ -274,8 +276,8 @@ pub(crate) enum DescriptorType {
RegularFile,
}

impl From<cap_primitives::fs::FileType> for DescriptorType {
fn from(ft: cap_primitives::fs::FileType) -> Self {
impl From<crate::filesystem::primitives::FileType> for DescriptorType {
fn from(ft: crate::filesystem::primitives::FileType) -> Self {
if ft.is_dir() {
DescriptorType::Directory
} else if ft.is_symlink() {
Expand Down Expand Up @@ -327,15 +329,12 @@ impl DescriptorStat {
data_access_timestamp: meta
.accessed()
.ok()
.and_then(|t| Datetime::try_from(t.into_std()).ok()),
.and_then(|t| Datetime::try_from(t).ok()),
data_modification_timestamp: meta
.modified()
.ok()
.and_then(|t| Datetime::try_from(t.into_std()).ok()),
status_change_timestamp: meta
.created()
.ok()
.and_then(|t| Datetime::try_from(t.into_std()).ok()),
.and_then(|t| Datetime::try_from(t).ok()),
status_change_timestamp: meta.created().ok().and_then(|t| Datetime::try_from(t).ok()),
}
}
}
Expand Down Expand Up @@ -524,7 +523,7 @@ impl Descriptor {
}
Self::Dir(d) => {
d.run_blocking(|d| {
let d = cap_primitives::fs::open(
let d = crate::filesystem::primitives::open(
d,
std::path::Component::CurDir.as_ref(),
OpenOptions::new().read(true),
Expand Down Expand Up @@ -622,7 +621,7 @@ impl Descriptor {
}
Self::Dir(d) => {
d.run_blocking(|d| {
let d = cap_primitives::fs::open(
let d = crate::filesystem::primitives::open(
d,
std::path::Component::CurDir.as_ref(),
OpenOptions::new().read(true),
Expand Down Expand Up @@ -855,7 +854,7 @@ impl Dir {
return Err(ErrorCode::NotPermitted);
}
self.run_blocking(move |d| {
cap_primitives::fs::create_dir(d, path.as_ref(), &DirOptions::new())
crate::filesystem::primitives::create_dir(d, path.as_ref(), &DirOptions::new())
})
.await?;
Ok(())
Expand Down Expand Up @@ -887,16 +886,14 @@ impl Dir {
if self.perms.write_not_permitted() {
return Err(ErrorCode::NotPermitted);
}
let atim =
atim.map(|t| SystemTimeSpec::Absolute(cap_primitives::time::SystemTime::from_std(t)));
let mtim =
mtim.map(|t| SystemTimeSpec::Absolute(cap_primitives::time::SystemTime::from_std(t)));
if path_flags.contains(PathFlags::SYMLINK_FOLLOW) {
self.run_blocking(move |d| cap_primitives::fs::set_times(d, path.as_ref(), atim, mtim))
.await?;
self.run_blocking(move |d| {
crate::filesystem::primitives::set_times(d, path.as_ref(), atim, mtim)
})
.await?;
} else {
self.run_blocking(move |d| {
cap_primitives::fs::set_times_nofollow(d, path.as_ref(), atim, mtim)
crate::filesystem::primitives::set_times_nofollow(d, path.as_ref(), atim, mtim)
})
.await?;
}
Expand Down Expand Up @@ -924,7 +921,12 @@ impl Dir {
}
let new_dir_handle = Arc::clone(&new_dir.dir);
self.run_blocking(move |d| {
cap_primitives::fs::hard_link(d, old_path.as_ref(), &new_dir_handle, new_path.as_ref())
crate::filesystem::primitives::hard_link(
d,
old_path.as_ref(),
&new_dir_handle,
new_path.as_ref(),
)
})
.await?;
Ok(())
Expand Down Expand Up @@ -975,17 +977,10 @@ impl Dir {
open_mode |= OpenMode::READ;
}

// Note that this is intentionally scoped to a separate block to
// minimize the surface area that is depended on by cap-fs-ext. Ideally
// the underlying functionality in `cap-primitives` would get exposed,
// but that'll require an upstream PR.
{
use cap_fs_ext_avoid_using_this::OpenOptionsFollowExt;
if path_flags.contains(PathFlags::SYMLINK_FOLLOW) {
opts.follow(FollowSymlinks::Yes);
} else {
opts.follow(FollowSymlinks::No);
}
if path_flags.contains(PathFlags::SYMLINK_FOLLOW) {
opts.follow(FollowSymlinks::Yes);
} else {
opts.follow(FollowSymlinks::No);
}

// These flags are not yet supported in cap-primitives:
Expand Down Expand Up @@ -1024,7 +1019,7 @@ impl Dir {

let opened = self
.run_blocking::<_, std::io::Result<OpenResult>>(move |d| {
let opened = cap_primitives::fs::open(d, path.as_ref(), &opts)?;
let opened = crate::filesystem::primitives::open(d, path.as_ref(), &opts)?;
if Metadata::from_file(&opened)?.is_dir() {
Ok(OpenResult::Dir(opened))
} else if oflags.contains(OpenFlags::DIRECTORY) {
Expand Down Expand Up @@ -1064,7 +1059,7 @@ impl Dir {

pub(crate) async fn readlink_at(&self, path: String) -> Result<String, ErrorCode> {
let link = self
.run_blocking(move |d| cap_primitives::fs::read_link(d, path.as_ref()))
.run_blocking(move |d| crate::filesystem::primitives::read_link(d, path.as_ref()))
.await?;
link.into_os_string()
.into_string()
Expand All @@ -1075,7 +1070,7 @@ impl Dir {
if self.perms.write_not_permitted() {
return Err(ErrorCode::NotPermitted);
}
self.run_blocking(move |d| cap_primitives::fs::remove_dir(d, path.as_ref()))
self.run_blocking(move |d| crate::filesystem::primitives::remove_dir(d, path.as_ref()))
.await?;
Ok(())
}
Expand All @@ -1097,7 +1092,12 @@ impl Dir {
}
let new_dir_handle = Arc::clone(&new_dir.dir);
self.run_blocking(move |d| {
cap_primitives::fs::rename(d, old_path.as_ref(), &new_dir_handle, new_path.as_ref())
crate::filesystem::primitives::rename(
d,
old_path.as_ref(),
&new_dir_handle,
new_path.as_ref(),
)
})
.await?;
Ok(())
Expand Down
14 changes: 14 additions & 0 deletions crates/wasi/src/filesystem/primitives/create_dir.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! This defines `create_dir`, the primary entrypoint to sandboxed directory
//! creation.

use crate::filesystem::primitives::{DirOptions, create_dir_impl};
use std::path::Path;
use std::{fs, io};

/// Perform a `mkdirat`-like operation, ensuring that the resolution of the
/// path never escapes the directory tree rooted at `start`.
#[inline]
pub fn create_dir(start: &fs::File, path: &Path, options: &DirOptions) -> io::Result<()> {
// Call the underlying implementation.
create_dir_impl(start, path, options)
}
67 changes: 67 additions & 0 deletions crates/wasi/src/filesystem/primitives/dir_entry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use crate::filesystem::primitives::{DirEntryInner, Metadata};
#[cfg(not(windows))]
use rustix::fs::DirEntryExt;
use std::ffi::OsString;
use std::{fmt, io};

/// Entries returned by the `ReadDir` iterator.
///
/// This corresponds to [`std::fs::DirEntry`].
///
/// Unlike `std::fs::DirEntry`, this API has no `DirEntry::path`, because
/// absolute paths don't interoperate well with the capability model.
///
/// There is a `file_name` function, however there are also `open`,
/// `open_with`, `open_dir`, `remove_file`, and `remove_dir` functions for
/// opening or removing the entry directly, which can be more efficient and
/// convenient.
///
/// There is no `from_std` method, as `std::fs::DirEntry` doesn't provide a way
/// to construct a `DirEntry` without opening directories by ambient paths.
pub struct DirEntry {
pub(crate) inner: DirEntryInner,
}

impl DirEntry {
/// Returns the metadata for the file that this entry points at.
///
/// This corresponds to [`std::fs::DirEntry::metadata`].
///
/// # Platform-specific behavior
///
/// On Windows, this produces a `Metadata` object which does not contain
/// the optional values returned by [`MetadataExt`]. Use
/// [`cap_fs_ext::DirEntryExt::full_metadata`] to obtain a `Metadata` with
/// the values filled in.
///
/// [`MetadataExt`]: https://doc.rust-lang.org/std/os/windows/fs/trait.MetadataExt.html
/// [`cap_fs_ext::DirEntryExt::full_metadata`]: https://docs.rs/cap-fs-ext/latest/cap_fs_ext/trait.DirEntryExt.html#tymethod.full_metadata
#[inline]
pub fn metadata(&self) -> io::Result<Metadata> {
self.inner.metadata()
}

/// Returns the bare file name of this directory entry without any other
/// leading path component.
///
/// This corresponds to [`std::fs::DirEntry::file_name`].
#[inline]
pub fn file_name(&self) -> OsString {
self.inner.file_name()
}
}

#[cfg(not(windows))]
impl DirEntryExt for DirEntry {
#[inline]
fn ino(&self) -> u64 {
self.inner.ino()
}
}

impl fmt::Debug for DirEntry {
// Like libstd's version, but doesn't print the path.
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
Loading
Loading