Skip to content
This repository has been archived by the owner on Oct 13, 2023. It is now read-only.

Implement file append functionality. #50

Merged
merged 2 commits into from
Jan 9, 2023
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
8 changes: 4 additions & 4 deletions Cargo.lock

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

35 changes: 35 additions & 0 deletions host/tests/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,41 @@ async fn run_file_read(mut store: Store<WasiCtx>, wasi: Wasi) -> Result<()> {
.map_err(|()| anyhow::anyhow!("command returned with failing exit status"))
}

async fn run_file_append(mut store: Store<WasiCtx>, wasi: Wasi) -> Result<()> {
let dir = tempfile::tempdir()?;

std::fs::File::create(dir.path().join("bar.txt"))?
.write_all(b"'Twas brillig, and the slithy toves.\n")?;

let descriptor =
store
.data_mut()
.push_dir(Box::new(wasi_cap_std_sync::dir::Dir::from_cap_std(
Dir::from_std_file(std::fs::File::open(dir.path())?),
)))?;

wasi.command(
&mut store,
0 as host::Descriptor,
1 as host::Descriptor,
&[],
&[],
&[(descriptor, "/")],
)
.await?
.map_err(|()| anyhow::anyhow!("command returned with failing exit status"))?;

let contents = std::fs::read(dir.path().join("bar.txt"))?;
assert_eq!(
std::str::from_utf8(&contents).unwrap(),
"'Twas brillig, and the slithy toves.\n\
Did gyre and gimble in the wabe;\n\
All mimsy were the borogoves,\n\
And the mome raths outgrabe.\n"
);
Ok(())
}

async fn run_exit_success(mut store: Store<WasiCtx>, wasi: Wasi) -> Result<()> {
let r = wasi
.command(
Expand Down
21 changes: 18 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub unsafe extern "C" fn command(
type_: StreamType::File(File {
fd: preopen.descriptor,
position: Cell::new(0),
append: false,
}),
})));
}
Expand Down Expand Up @@ -1091,8 +1092,13 @@ pub unsafe extern "C" fn fd_write(

// If this is a file, keep the current-position pointer up to date.
if let StreamType::File(file) = &streams.type_ {
file.position
.set(file.position.get() + wasi_filesystem::Filesize::from(bytes));
// But don't update if we're in append mode. Strictly speaking,
// we should set the position to the new end of the file, but
// we don't have an API to do that atomically.
if !file.append {
file.position
.set(file.position.get() + wasi_filesystem::Filesize::from(bytes));
}
}

*nwritten = bytes as usize;
Expand Down Expand Up @@ -1245,6 +1251,7 @@ pub unsafe extern "C" fn path_open(
let o_flags = o_flags_from_oflags(oflags);
let flags = descriptor_flags_from_flags(fs_rights_base, fdflags);
let mode = wasi_filesystem::Mode::READABLE | wasi_filesystem::Mode::WRITEABLE;
let append = fdflags & wasi::FDFLAGS_APPEND == wasi::FDFLAGS_APPEND;

State::with_mut(|state| {
let file = state.get_dir(fd)?;
Expand All @@ -1255,6 +1262,7 @@ pub unsafe extern "C" fn path_open(
type_: StreamType::File(File {
fd: result,
position: Cell::new(0),
append,
}),
});

Expand Down Expand Up @@ -1928,7 +1936,11 @@ impl Streams {
// For files, we may have adjusted the position for seeking, so
// create a new stream.
StreamType::File(file) => {
let output = wasi_filesystem::write_via_stream(file.fd, file.position.get())?;
let output = if file.append {
wasi_filesystem::append_via_stream(file.fd)?
} else {
wasi_filesystem::write_via_stream(file.fd, file.position.get())?
};
self.output.set(Some(output));
Ok(output)
}
Expand Down Expand Up @@ -1982,6 +1994,9 @@ struct File {

/// The current-position pointer.
position: Cell<wasi_filesystem::Filesize>,

/// In append mode, all writes append to the file.
append: bool,
}

const PAGE_SIZE: usize = 65536;
Expand Down
17 changes: 17 additions & 0 deletions test-programs/src/bin/file_append.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use std::{
error::Error,
fs::OpenOptions,
io::{Seek, SeekFrom, Write},
};

fn main() -> Result<(), Box<dyn Error>> {
let mut file = OpenOptions::new().append(true).open("bar.txt")?;

file.write_all(b"Did gyre and gimble in the wabe;\n")
.unwrap();
file.seek(SeekFrom::Start(0)).unwrap();
file.write_all(b"All mimsy were the borogoves,\n").unwrap();
file.write_all(b"And the mome raths outgrabe.\n").unwrap();

Ok(())
}
11 changes: 11 additions & 0 deletions wasi-common/cap-std-sync/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,17 @@ impl WasiFile for File {
fn is_write_vectored_at(&self) -> bool {
self.0.is_write_vectored_at()
}
async fn append<'a>(&mut self, buf: &[u8]) -> Result<u64, Error> {
let n = self.0.append(buf)?;
Ok(n.try_into()?)
}
async fn append_vectored<'a>(&mut self, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
let n = self.0.append_vectored(bufs)?;
Ok(n.try_into()?)
}
fn is_append_vectored(&self) -> bool {
self.0.is_append_vectored()
}
fn isatty(&mut self) -> bool {
self.0.is_terminal()
}
Expand Down
Loading