Skip to content

Commit

Permalink
Merge pull request #4355 from wasmerio/fix-static-file
Browse files Browse the repository at this point in the history
Fix the `virtual_fs::StaticFile` implementation
  • Loading branch information
Michael Bryan authored Dec 14, 2023
2 parents 32e1537 + 4a33c45 commit 88ac1b2
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 83 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ enumset = "1.1.0"
memoffset = "0.9.0"
wasmer-toml = "0.9.2"
webc = { version = "5.8.0", default-features = false, features = ["package"] }
shared-buffer = "0.1.4"

[build-dependencies]
test-generator = { path = "tests/lib/test-generator" }
Expand Down
2 changes: 1 addition & 1 deletion lib/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ bytes = "1"
wat = { version = "=1.0.71", optional = true }
tracing = { version = "0.1", optional = true }
rustc-demangle = "0.1"
shared-buffer = "0.1"
shared-buffer = { workspace = true }

# Dependencies and Development Dependencies for `sys`.
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ enum-iterator = "0.7.0"
bytes = "1.0"
self_cell = "1.0"
rkyv = { version = "0.7.40", features = ["indexmap", "validation", "strict"] }
shared-buffer = "0.1"
shared-buffer = { workspace = true }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
wasmer-vm = { path = "../vm", version = "=4.2.4" }
Expand Down
27 changes: 14 additions & 13 deletions lib/virtual-fs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,25 @@ repository.workspace = true
rust-version.workspace = true

[dependencies]
libc = { version = "^0.2", default-features = false, optional = true }
thiserror = "1"
futures = { version = "0.3" }
tracing = { version = "0.1" }
typetag = { version = "0.1", optional = true }
webc = { version = "5.0", optional = true }
slab = { version = "0.4" }
derivative = "2.2.0"
anyhow = { version = "1.0.66", optional = true }
async-trait = { version = "^0.1" }
lazy_static = "1.4"
fs_extra = { version = "1.2.0", optional = true }
filetime = { version = "0.2.18", optional = true }
bytes = "1"
tokio = { version = "1", features = ["io-util", "sync", "macros"], default_features = false }
pin-project-lite = "0.2.9"
derivative = "2.2.0"
filetime = { version = "0.2.18", optional = true }
fs_extra = { version = "1.2.0", optional = true }
futures = { version = "0.3" }
indexmap = "1.9.2"
lazy_static = "1.4"
libc = { version = "^0.2", default-features = false, optional = true }
pin-project-lite = "0.2.9"
replace_with = "0.1.7"
shared-buffer = { workspace = true }
slab = { version = "0.4" }
thiserror = "1"
tokio = { version = "1", features = ["io-util", "sync", "macros"], default_features = false }
tracing = { version = "0.1" }
typetag = { version = "0.1", optional = true }
webc = { version = "5.0", optional = true }

[target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dependencies]
getrandom = { version = "0.2" }
Expand Down
141 changes: 76 additions & 65 deletions lib/virtual-fs/src/static_file.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
use std::{
convert::TryInto,
io::{self, Cursor},
pin::Pin,
task::{Context, Poll},
};

use futures::future::BoxFuture;
use shared_buffer::OwnedBuffer;
use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};

use std::borrow::Cow;
use std::convert::TryInto;
use std::io::{self, SeekFrom};
use std::pin::Pin;
use std::task::{Context, Poll};

use crate::{FsError, VirtualFile};

#[derive(Debug)]
pub struct StaticFile {
bytes: Cow<'static, [u8]>,
cursor: u64,
len: u64,
}
/// An immutable file backed by an [`OwnedBuffer`].
#[derive(Debug, Clone, PartialEq)]
pub struct StaticFile(Cursor<OwnedBuffer>);

impl StaticFile {
pub fn new(bytes: Cow<'static, [u8]>) -> Self {
Self {
len: bytes.len() as u64,
bytes,
cursor: 0,
}
pub fn new(bytes: impl Into<OwnedBuffer>) -> Self {
StaticFile(Cursor::new(bytes.into()))
}

/// Access the underlying buffer.
pub fn contents(&self) -> &OwnedBuffer {
self.0.get_ref()
}
}

Expand All @@ -30,49 +31,44 @@ impl VirtualFile for StaticFile {
fn last_accessed(&self) -> u64 {
0
}

fn last_modified(&self) -> u64 {
0
}

fn created_time(&self) -> u64 {
0
}

fn size(&self) -> u64 {
self.len
self.0.get_ref().len().try_into().unwrap()
}
fn set_len(&mut self, _new_size: u64) -> crate::Result<()> {
Ok(())

fn set_len(&mut self, _new_size: u64) -> Result<(), FsError> {
Err(FsError::PermissionDenied)
}

fn unlink(&mut self) -> BoxFuture<'static, Result<(), FsError>> {
Box::pin(async { Ok(()) })
Box::pin(async { Err(FsError::PermissionDenied) })
}

fn poll_read_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
let remaining = self.len - self.cursor;
Poll::Ready(Ok(remaining as usize))
let remaining = self.0.position() - self.size();
Poll::Ready(Ok(remaining.try_into().unwrap()))
}

fn poll_write_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
Poll::Ready(Ok(0))
Poll::Ready(Err(std::io::ErrorKind::PermissionDenied.into()))
}
}

impl AsyncRead for StaticFile {
fn poll_read(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
) -> Poll<io::Result<()>> {
let bytes = self.bytes.as_ref();

let cursor: usize = self.cursor.try_into().unwrap_or(u32::MAX as usize);
let _start = cursor.min(bytes.len());
let bytes = &bytes[cursor..];

if bytes.len() > buf.remaining() {
let remaining = buf.remaining();
buf.put_slice(&bytes[..remaining]);
} else {
buf.put_slice(bytes);
}
Poll::Ready(Ok(()))
Pin::new(&mut self.0).poll_read(cx, buf)
}
}

Expand All @@ -82,9 +78,9 @@ impl AsyncWrite for StaticFile {
fn poll_write(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &[u8],
_buf: &[u8],
) -> Poll<io::Result<usize>> {
Poll::Ready(Ok(buf.len()))
Poll::Ready(Err(std::io::ErrorKind::PermissionDenied.into()))
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
Expand All @@ -96,28 +92,43 @@ impl AsyncWrite for StaticFile {

impl AsyncSeek for StaticFile {
fn start_seek(mut self: Pin<&mut Self>, pos: io::SeekFrom) -> io::Result<()> {
let self_size = self.size();
match pos {
SeekFrom::Start(s) => {
self.cursor = s.min(self_size);
}
SeekFrom::End(e) => {
let self_size_i64 = self_size.try_into().unwrap_or(i64::MAX);
self.cursor = ((self_size_i64).saturating_add(e))
.min(self_size_i64)
.try_into()
.unwrap_or(i64::MAX as u64);
}
SeekFrom::Current(c) => {
self.cursor = (self
.cursor
.saturating_add(c.try_into().unwrap_or(i64::MAX as u64)))
.min(self_size);
}
}
Ok(())
}
fn poll_complete(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
Poll::Ready(Ok(self.cursor))
Pin::new(&mut self.0).start_seek(pos)
}

fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
Pin::new(&mut self.0).poll_complete(cx)
}
}

#[cfg(test)]
mod tests {
use tokio::io::AsyncReadExt;

use super::*;

#[tokio::test]
async fn read_a_static_file_to_end() {
let mut file = StaticFile::new(OwnedBuffer::from_static(b"Hello, World!"));
let mut buffer = [0; 5];

let bytes_read = file.read(&mut buffer).await.unwrap();
assert_eq!(bytes_read, 5);
assert_eq!(&buffer[..bytes_read], b"Hello");
assert_eq!(file.0.position(), 5);

let bytes_read = file.read(&mut buffer).await.unwrap();
assert_eq!(bytes_read, 5);
assert_eq!(&buffer[..bytes_read], b", Wor");
assert_eq!(file.0.position(), 10);

let bytes_read = file.read(&mut buffer).await.unwrap();
assert_eq!(bytes_read, 3);
assert_eq!(&buffer[..bytes_read], b"ld!");
assert_eq!(file.0.position(), 13);

let bytes_read = file.read(&mut buffer).await.unwrap();
assert_eq!(bytes_read, 0);
assert_eq!(&buffer[..bytes_read], b"");
assert_eq!(file.0.position(), 13);
}
}
2 changes: 1 addition & 1 deletion lib/wasix/src/state/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,7 @@ impl WasiEnv {
}
WasiFsRoot::Backing(fs) => {
let mut f = fs.new_open_options().create(true).write(true).open(path)?;
f.copy_reference(Box::new(StaticFile::new(atom.into())));
f.copy_reference(Box::new(StaticFile::new(atom)));
}
}

Expand Down

0 comments on commit 88ac1b2

Please sign in to comment.