From 781aca4421a31651ac73d8540d033191815e0f0f Mon Sep 17 00:00:00 2001
From: Pat Hickey
Date: Tue, 31 Mar 2026 18:08:54 -0700
Subject: [PATCH 1/2] wasmtime-wasi p1: get_seekable fails with Errno SPIPE for
Fifo or CharacterDevice
---
crates/wasi/src/p0.rs | 8 ++++----
crates/wasi/src/p1.rs | 23 ++++++++++++++++-------
2 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/crates/wasi/src/p0.rs b/crates/wasi/src/p0.rs
index 5d610f0ae557..f9a4d0fcc439 100644
--- a/crates/wasi/src/p0.rs
+++ b/crates/wasi/src/p0.rs
@@ -31,7 +31,7 @@ wiggle::from_witx!({
fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write,
fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get,
path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory,
- path_rename, path_symlink, path_unlink_file
+ path_rename, path_symlink, path_unlink_file, fd_tell,
}
},
errors: { errno => trappable Error },
@@ -50,7 +50,7 @@ mod sync {
fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write,
fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get,
path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory,
- path_rename, path_symlink, path_unlink_file
+ path_rename, path_symlink, path_unlink_file, fd_tell,
}
},
errors: { errno => trappable Error },
@@ -325,12 +325,12 @@ impl wasi_unstable::WasiUnstable for T {
Ok(())
}
- fn fd_tell(
+ async fn fd_tell(
&mut self,
memory: &mut GuestMemory<'_>,
fd: types::Fd,
) -> Result {
- Ok(Snapshot1::fd_tell(self, memory, fd.into())?)
+ Ok(Snapshot1::fd_tell(self, memory, fd.into()).await?)
}
async fn fd_readdir(
diff --git a/crates/wasi/src/p1.rs b/crates/wasi/src/p1.rs
index b063aa7a9aae..7fef7700c650 100644
--- a/crates/wasi/src/p1.rs
+++ b/crates/wasi/src/p1.rs
@@ -532,10 +532,18 @@ impl Transaction<'_> {
/// # Errors
///
/// Returns [`types::Errno::Spipe`] if the descriptor corresponds to stdio
- fn get_seekable(&self, fd: types::Fd) -> Result<&File> {
+ async fn get_seekable(&mut self, fd: types::Fd) -> Result<&File> {
let fd = fd.into();
match self.descriptors.used.get(&fd) {
- Some(Descriptor::File(file)) => Ok(file),
+ Some(Descriptor::File(file)) => {
+ if matches!(
+ self.view.filesystem().get_type(file.fd.borrowed()).await?,
+ filesystem::DescriptorType::CharacterDevice | filesystem::DescriptorType::Fifo
+ ) {
+ return Err(types::Errno::Spipe.into());
+ }
+ Ok(file)
+ }
Some(
Descriptor::Stdin { .. } | Descriptor::Stdout { .. } | Descriptor::Stderr { .. },
) => {
@@ -863,7 +871,7 @@ wiggle::from_witx!({
fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write,
fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get,
path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory,
- path_rename, path_symlink, path_unlink_file
+ path_rename, path_symlink, path_unlink_file, fd_tell,
}
},
errors: { errno => trappable Error },
@@ -882,7 +890,7 @@ pub(crate) mod sync {
fd_filestat_set_times, fd_read, fd_pread, fd_seek, fd_sync, fd_readdir, fd_write,
fd_pwrite, poll_oneoff, path_create_directory, path_filestat_get,
path_filestat_set_times, path_link, path_open, path_readlink, path_remove_directory,
- path_rename, path_symlink, path_unlink_file
+ path_rename, path_symlink, path_unlink_file, fd_tell,
}
},
errors: { errno => trappable Error },
@@ -1888,8 +1896,8 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiP1Ctx {
offset: types::Filedelta,
whence: types::Whence,
) -> Result {
- let t = self.transact()?;
- let File { fd, position, .. } = t.get_seekable(fd)?;
+ let mut t = self.transact()?;
+ let File { fd, position, .. } = t.get_seekable(fd).await?;
let fd = fd.borrowed();
let position = position.clone();
drop(t);
@@ -1927,7 +1935,7 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiP1Ctx {
/// Return the current offset of a file descriptor.
/// NOTE: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX.
#[instrument(skip(self, _memory))]
- fn fd_tell(
+ async fn fd_tell(
&mut self,
_memory: &mut GuestMemory<'_>,
fd: types::Fd,
@@ -1935,6 +1943,7 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiP1Ctx {
let pos = self
.transact()?
.get_seekable(fd)
+ .await
.map(|File { position, .. }| position.load(Ordering::Relaxed))?;
Ok(pos)
}
From 27956bf8692cec5eca6e3f7760b510a6a35e4416 Mon Sep 17 00:00:00 2001
From: Pat Hickey
Date: Tue, 31 Mar 2026 18:41:05 -0700
Subject: [PATCH 2/2] wasmtime-wasi: plumb through cap_std FileTypeExt::is_fifo
to DescriptorType::Fifo
---
crates/wasi/src/filesystem.rs | 4 ++++
crates/wasi/src/p1.rs | 3 ++-
crates/wasi/src/p2/host/filesystem.rs | 1 +
crates/wasi/src/p3/filesystem/mod.rs | 3 +++
4 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/crates/wasi/src/filesystem.rs b/crates/wasi/src/filesystem.rs
index 917defac77e0..af08a154f0cb 100644
--- a/crates/wasi/src/filesystem.rs
+++ b/crates/wasi/src/filesystem.rs
@@ -254,6 +254,8 @@ pub(crate) enum DescriptorType {
SymbolicLink,
/// The descriptor refers to a regular file inode.
RegularFile,
+ /// The descriptor refers to a FIFO
+ Fifo,
}
impl From for DescriptorType {
@@ -268,6 +270,8 @@ impl From for DescriptorType {
DescriptorType::CharacterDevice
} else if ft.is_file() {
DescriptorType::RegularFile
+ } else if ft.is_fifo() {
+ DescriptorType::Fifo
} else {
DescriptorType::Unknown
}
diff --git a/crates/wasi/src/p1.rs b/crates/wasi/src/p1.rs
index 7fef7700c650..c48f96e4daf2 100644
--- a/crates/wasi/src/p1.rs
+++ b/crates/wasi/src/p1.rs
@@ -536,8 +536,9 @@ impl Transaction<'_> {
let fd = fd.into();
match self.descriptors.used.get(&fd) {
Some(Descriptor::File(file)) => {
+ let descriptor_type = self.view.filesystem().get_type(file.fd.borrowed()).await?;
if matches!(
- self.view.filesystem().get_type(file.fd.borrowed()).await?,
+ descriptor_type,
filesystem::DescriptorType::CharacterDevice | filesystem::DescriptorType::Fifo
) {
return Err(types::Errno::Spipe.into());
diff --git a/crates/wasi/src/p2/host/filesystem.rs b/crates/wasi/src/p2/host/filesystem.rs
index 02f2b0322a41..dc967974a59d 100644
--- a/crates/wasi/src/p2/host/filesystem.rs
+++ b/crates/wasi/src/p2/host/filesystem.rs
@@ -616,6 +616,7 @@ impl From for types::DescriptorType {
crate::filesystem::DescriptorType::Directory => Self::Directory,
crate::filesystem::DescriptorType::SymbolicLink => Self::SymbolicLink,
crate::filesystem::DescriptorType::RegularFile => Self::RegularFile,
+ crate::filesystem::DescriptorType::Fifo => Self::Fifo,
}
}
}
diff --git a/crates/wasi/src/p3/filesystem/mod.rs b/crates/wasi/src/p3/filesystem/mod.rs
index 0ef9c3166c7f..72f3efc130d2 100644
--- a/crates/wasi/src/p3/filesystem/mod.rs
+++ b/crates/wasi/src/p3/filesystem/mod.rs
@@ -261,6 +261,7 @@ impl From for types::DescriptorType {
crate::filesystem::DescriptorType::Directory => Self::Directory,
crate::filesystem::DescriptorType::SymbolicLink => Self::SymbolicLink,
crate::filesystem::DescriptorType::RegularFile => Self::RegularFile,
+ crate::filesystem::DescriptorType::Fifo => Self::Fifo,
}
}
}
@@ -278,6 +279,8 @@ impl From for types::DescriptorType {
Self::CharacterDevice
} else if ft.is_file() {
Self::RegularFile
+ } else if ft.is_fifo() {
+ Self::Fifo
} else {
Self::Other(None)
}