Fix fd with append flag can't seek correctly

This commit fixes an incompatible behavior (with other runtimes, and
POSIX) when an fd that was opened with `fdflags::append` cannot seek to
the right offset with `fd_seek`.  The append flag should not "lock" the
offset at the end, as it's possible to seek to another offset and read
from it.

Signed-off-by: Yage Hu <me@huyage.dev>
This commit is contained in:
Yage Hu
2024-10-18 20:34:02 -04:00
parent 8b97cfe399
commit 00a1a539a6
5 changed files with 42 additions and 5 deletions

View File

@ -62,9 +62,6 @@ pub(crate) fn fd_seek_internal(
if !fd_entry.rights.contains(Rights::FD_SEEK) {
return Ok(Err(Errno::Access));
}
if fd_entry.flags.contains(Fdflags::APPEND) {
return Ok(Ok(fd_entry.offset.load(Ordering::Acquire)));
}
// TODO: handle case if fd is a dir?
let new_offset = match whence {

View File

@ -127,6 +127,7 @@ pub(crate) fn fd_write_internal<M: MemorySize>(
should_update_cursor: bool,
should_snapshot: bool,
) -> Result<Result<usize, Errno>, WasiError> {
let mut offset = offset;
let mut env = ctx.data();
let state = env.state.clone();
@ -160,6 +161,12 @@ pub(crate) fn fd_write_internal<M: MemorySize>(
async {
let mut handle = handle.write().unwrap();
if !is_stdio {
if fd_entry.flags.contains(Fdflags::APPEND) {
// `fdflags::append` means we need to seek to the end before writing.
offset = handle.size();
fd_entry.offset.store(offset, Ordering::Release);
}
handle
.seek(std::io::SeekFrom::Start(offset))
.await

View File

@ -0,0 +1,32 @@
use std::os::fd::AsRawFd;
#[link(wasm_import_module = "wasi_snapshot_preview1")]
extern "C" {
pub fn fd_seek(fd: i32, offset: i64, whence: i32, filesize: i32) -> i32;
}
const ERRNO_SUCCESS: i32 = 0;
const WHENCE_SET: i32 = 0;
fn main() {
unsafe {
let offset = 100u64;
let mut new_offset = 0u64;
let f = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.append(true)
.open("/fyi/fs_seek_append.dir/file")
.unwrap();
let errno = fd_seek(
f.as_raw_fd(),
offset as i64,
WHENCE_SET,
&mut new_offset as *mut u64 as usize as i32,
);
assert_eq!(errno, ERRNO_SUCCESS);
assert_eq!(offset, new_offset);
}
}

View File

@ -13,8 +13,9 @@ fn main() {
// file offset must be 1 now
write!(file, "{}", "a").unwrap();
// rewind should not work on file in append mode
// since the offset must always be at the end of the file
// rewind should not work on file in append mode.
// It changes the offset, which is immediately set to the end of the file
// with a write.
let _ = file.rewind();
// file offset must be 2 now