Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit cf88a7c

Browse files
authored
feat(wasip3): implement wasi:filesystem (#11406)
* refactor: move `File` and `Dir` to top-level Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * refactor: extract filesystem utilities to top-level Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * chore: update `wasi:filesystem@0.3` WIT Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * chore: port p2 filesystem test Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * feat(wasip3): add filesystem stubs Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * chore(wasip3): use trapping errors is fs for consistency with refactors for sockets Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * feat(wasip3): implement `wasi:filesystem` without reads Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * chore: remove unused enums Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * refactor: remove `NewTimestamp` enum Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * refactor(p2): check FD types before permissions Previously, `wasi:filesystem` functions taking two directory FDs as arguments, would check permissions on the source directory before ensuring that target FD is also a directory. This order has now been changed and first implementations ensure that both FDs are directories and only then check permissions. This should not have any functional differences in guest applications Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * refactor(fs): remove `Advice` enum Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * refactor(sockets): remove `ResultWriteTask` Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * feat(wasip3): implement `wasi:filesystem` reads Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * chore(p3): ignore FS test due to runtime panic Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * fix: make `filesystem` module public Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * feat(wasip3): abort filesystem tasks on descriptor drop Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * Revert "feat(wasip3): abort filesystem tasks on descriptor drop" This reverts commit 40415b52f79a33c376a2a875ffecb1d0a01c7903. Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * fix: avoid double `Accessor` entry Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * fix(p3): correctly handle FS I/O Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * fix(fs-p3): expect unreachable enums on Windows prtest:full Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * fix(p3): correctly handle Windows read_dir Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> * refactor: reorder read_dir conditional Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net> --------- Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
1 parent c42ed27 commit cf88a7c

23 files changed

Lines changed: 2452 additions & 792 deletions

File tree

ci/vendor-wit.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ make_vendor "wasi-keyvalue" "keyvalue@219ea36"
7171
make_vendor "wasi/src/p3" "
7272
cli@939bd6d@wit-0.3.0-draft
7373
clocks@13d1c82@wit-0.3.0-draft
74-
filesystem@e2a2ddc@wit-0.3.0-draft
74+
filesystem@2007d36@wit-0.3.0-draft
7575
random@4e94663@wit-0.3.0-draft
7676
sockets@e863ee2@wit-0.3.0-draft
7777
"
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use futures::join;
2+
use test_programs::p3::wasi::filesystem::types::{DescriptorFlags, OpenFlags, PathFlags};
3+
use test_programs::p3::{wasi, wit_stream};
4+
5+
struct Component;
6+
7+
test_programs::p3::export!(Component);
8+
9+
impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
10+
async fn run() -> Result<(), ()> {
11+
let preopens = wasi::filesystem::preopens::get_directories();
12+
let (dir, _) = &preopens[0];
13+
14+
let filename = "test.txt";
15+
let file = dir
16+
.open_at(
17+
PathFlags::empty(),
18+
filename.to_string(),
19+
OpenFlags::CREATE,
20+
DescriptorFlags::READ | DescriptorFlags::WRITE,
21+
)
22+
.await
23+
.unwrap();
24+
let (mut data_tx, data_rx) = wit_stream::new();
25+
join!(
26+
async {
27+
file.write_via_stream(data_rx, 5).await.unwrap();
28+
},
29+
async {
30+
let remaining = data_tx.write_all(b"Hello, ".to_vec()).await;
31+
assert!(remaining.is_empty());
32+
let remaining = data_tx.write_all(b"World!".to_vec()).await;
33+
assert!(remaining.is_empty());
34+
drop(data_tx);
35+
},
36+
);
37+
let (data_rx, data_fut) = file.read_via_stream(0);
38+
let contents = data_rx.collect().await;
39+
data_fut.await.unwrap();
40+
assert_eq!(
41+
String::from_utf8_lossy(&contents),
42+
"\0\0\0\0\0Hello, World!"
43+
);
44+
45+
// Test that file read streams behave like other read streams.
46+
let (data_rx, data_fut) = file.read_via_stream(5);
47+
let contents = data_rx.collect().await;
48+
data_fut.await.unwrap();
49+
assert_eq!(String::from_utf8_lossy(&contents), "Hello, World!");
50+
51+
dir.unlink_file_at(filename.to_string()).await.unwrap();
52+
Ok(())
53+
}
54+
}
55+
56+
fn main() {}

crates/wasi/src/clocks.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use cap_std::time::{Duration, Instant, SystemClock};
1+
use cap_std::time::{Duration, Instant, SystemClock, SystemTime};
22
use cap_std::{AmbientAuthority, ambient_authority};
33
use cap_time_ext::{MonotonicClockExt as _, SystemClockExt as _};
44
use wasmtime::component::{HasData, ResourceTable};
@@ -122,3 +122,22 @@ pub fn monotonic_clock() -> Box<dyn HostMonotonicClock + Send> {
122122
pub fn wall_clock() -> Box<dyn HostWallClock + Send> {
123123
Box::new(WallClock::default())
124124
}
125+
126+
pub(crate) struct Datetime {
127+
pub seconds: u64,
128+
pub nanoseconds: u32,
129+
}
130+
131+
impl TryFrom<SystemTime> for Datetime {
132+
type Error = wasmtime::Error;
133+
134+
fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
135+
let duration =
136+
time.duration_since(SystemTime::from_std(std::time::SystemTime::UNIX_EPOCH))?;
137+
138+
Ok(Self {
139+
seconds: duration.as_secs(),
140+
nanoseconds: duration.subsec_nanos(),
141+
})
142+
}
143+
}

crates/wasi/src/ctx.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use crate::cli::{StdinStream, StdoutStream, WasiCliCtx};
22
use crate::clocks::{HostMonotonicClock, HostWallClock, WasiClocksCtx};
3-
use crate::filesystem::WasiFilesystemCtx;
4-
use crate::p2::filesystem::Dir;
3+
use crate::filesystem::{Dir, WasiFilesystemCtx};
54
use crate::random::WasiRandomCtx;
65
use crate::sockets::{SocketAddrCheck, SocketAddrUse, WasiSocketsCtx};
76
use crate::{DirPerms, FilePerms, OpenMode};

0 commit comments

Comments
 (0)