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

Commit

Permalink
Implement file append functionality. (#50)
Browse files Browse the repository at this point in the history
* Implement file append functionality.

 - In the preview1-to-preview2 polyfill, using `append_via_stream`.
 - In the host implementation, using a new system-interface `FileIoExt::append` function.

* Add a basic testcase.
  • Loading branch information
sunfishcode committed Jan 9, 2023
1 parent b6d24aa commit d56b897
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 86 deletions.
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

0 comments on commit d56b897

Please sign in to comment.