Skip to content

Commit

Permalink
Merge pull request #4698 from wasmerio/fix/fstat_size_with_seek
Browse files Browse the repository at this point in the history
Fix calculation of stat.st_size in the presence of combined seeks and writes
  • Loading branch information
Arshia001 authored May 15, 2024
2 parents 9573519 + 8ecdf59 commit f410690
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 7 deletions.
2 changes: 1 addition & 1 deletion lib/wasix/src/syscalls/wasi/fd_filestat_get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub(crate) fn fd_filestat_get_internal(
fd: WasiFd,
) -> Result<Filestat, Errno> {
let env = ctx.data();
let (_, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
let (_, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
let fd_entry = state.fs.get_fd(fd)?;
if !fd_entry.rights.contains(Rights::FD_FILESTAT_GET) {
return Err(Errno::Access);
Expand Down
25 changes: 19 additions & 6 deletions lib/wasix/src/syscalls/wasi/fd_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ pub(crate) fn fd_write_internal<M: MemorySize>(
let fd_flags = fd_entry.flags;
let mut memory = unsafe { env.memory_view(&ctx) };

let (bytes_written, can_update_cursor, can_snapshot) = {
let (bytes_written, is_file, can_snapshot) = {
let (mut memory, _) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };
let mut guard = fd_entry.inode.write();
match guard.deref_mut() {
Expand Down Expand Up @@ -414,20 +414,33 @@ pub(crate) fn fd_write_internal<M: MemorySize>(

// reborrow and update the size
if !is_stdio {
if can_update_cursor && should_update_cursor {
let offset = if is_file && should_update_cursor {
let bytes_written = bytes_written as u64;
let mut fd_map = state.fs.fd_map.write().unwrap();
let fd_entry = wasi_try_ok_ok!(fd_map.get_mut(&fd).ok_or(Errno::Badf));
fd_entry
.offset
.fetch_add(bytes_written as u64, Ordering::AcqRel);
}
.fetch_add(bytes_written, Ordering::AcqRel)
// fetch_add returns the previous value, we have to add bytes_written again here
+ bytes_written
} else {
fd_entry.offset.load(Ordering::Acquire)
};

// we set the size but we don't return any errors if it fails as
// pipes and sockets will not do anything with this
let (mut memory, _, inodes) =
unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
// Cast is valid because we don't support 128 bit systems...
fd_entry.inode.stat.write().unwrap().st_size += bytes_written as u64;
if is_file {
let mut stat = fd_entry.inode.stat.write().unwrap();
// If we wrote before the end, the current size is still correct.
// Otherwise, we only got as far as the current cursor. So, the
// max of the two is the correct new size.
stat.st_size = stat.st_size.max(offset);
} else {
// Cast is valid because we don't support 128 bit systems...
fd_entry.inode.stat.write().unwrap().st_size += bytes_written as u64;
}
}
bytes_written
};
Expand Down
39 changes: 39 additions & 0 deletions tests/wasi-fyi/fs_write-and-seek.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::fs::{metadata, OpenOptions};
use std::io::{Seek, SeekFrom, Write};

fn main() {
let mut file = OpenOptions::new()
.write(true)
.read(true)
.create(true)
.open("file")
.unwrap();

write!(file, "hell").unwrap();

// We wrote 4 bytes
let md = metadata("file").unwrap();
assert_eq!(md.len(), 4);

assert_eq!(file.seek(SeekFrom::Start(0)).unwrap(), 0);

write!(file, "eh").unwrap();

// We overwrote the first 2 bytes, should still have 4 bytes
let md = metadata("file").unwrap();
assert_eq!(md.len(), 4);

assert_eq!(file.seek(SeekFrom::Start(0)).unwrap(), 0);

write!(file, "hello").unwrap();

// Now we wrote past the end, should have 5 bytes
let md = metadata("file").unwrap();
assert_eq!(md.len(), 5);

write!(file, " world!").unwrap();

// We wrote past the end entirely, should have 5 + 7 = 12 bytes
let md = metadata("file").unwrap();
assert_eq!(md.len(), 12);
}

0 comments on commit f410690

Please sign in to comment.