Repository: wasmerio/wasmer (language: rust)

Issue:
Cannot `fd_seek` with `fdflags::append`
### Describe the bug

If an fd was opened with `fdflags::append`, `fd_seek` with it does not work properly.

```sh
wasmer -vV; rustc -vV
wasmer 4.4.0 (8b97cfe 2024-10-18)
binary: wasmer-cli
commit-hash: 8b97cfe3992ae3c2f0002f9955fcb23057f666a9
commit-date: 2024-10-18
host: x86_64-unknown-linux-gnu
compiler: singlepass,cranelift
c_api backend: 
rustc 1.81.0 (eeb90cda1 2024-09-04)
binary: rustc
commit-hash: eeb90cda1969383f56a2637cbd3037bdf598841c
commit-date: 2024-09-04
host: x86_64-unknown-linux-gnu
release: 1.81.0
LLVM version: 18.1.7
```


### Steps to reproduce

Compile the snippet with crate `wasi` v0.11, and run:

```
cargo build --target wasm32-wasip1
mkdir dir
wasmer run --mapdir /dir:dir target/wasm32-wasip1/debug/repro.wasm
```

```rust
fn main() {
    unsafe {
        let base_fd = 5;
        let rights = wasi::RIGHTS_FD_WRITE | wasi::RIGHTS_FD_TELL | wasi::RIGHTS_FD_SEEK;
        let fd = wasi::path_open(
            base_fd,
            0,
            "dir/file",
            wasi::OFLAGS_CREAT | wasi::OFLAGS_EXCL,
            rights,
            rights,
            0,
        )
        .unwrap();
        let fd_append = wasi::path_open(
            base_fd,
            0,
            "dir/file",
            wasi::OFLAGS_CREAT,
            rights,
            rights,
            wasi::FDFLAGS_APPEND,
        )
        .unwrap();

        assert_eq!(wasi::fd_seek(fd, 100, wasi::WHENCE_SET).unwrap(), 100);
        assert_eq!(
            wasi::fd_seek(fd_append, 100, wasi::WHENCE_SET).unwrap(),
            100
        );
    }
}
```

### Expected behavior

The snippet should run successfully. The two seeks should return the same offset.

### Actual behavior

Wasmer fails when running the snippet because the second `fd_seek` returns 0 as the offset.




Discussion / hints:

Fix patch:
diff --git a/lib/wasix/src/syscalls/wasi/fd_seek.rs b/lib/wasix/src/syscalls/wasi/fd_seek.rs
index 527ed185dcd..65d60514933 100644
--- a/lib/wasix/src/syscalls/wasi/fd_seek.rs
+++ b/lib/wasix/src/syscalls/wasi/fd_seek.rs
@@ -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 {
diff --git a/lib/wasix/src/syscalls/wasi/fd_write.rs b/lib/wasix/src/syscalls/wasi/fd_write.rs
index b5f0d648a82..04954d6770e 100644
--- a/lib/wasix/src/syscalls/wasi/fd_write.rs
+++ b/lib/wasix/src/syscalls/wasi/fd_write.rs
@@ -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


Test patch:
diff --git a/tests/wasi-fyi/fd_seek_append.rs b/tests/wasi-fyi/fd_seek_append.rs
new file mode 100644
index 00000000000..d8babd5a5a0
--- /dev/null
+++ b/tests/wasi-fyi/fd_seek_append.rs
@@ -0,0 +1,15 @@
+use std::io::{Seek as _, SeekFrom};
+
+fn main() {
+    let offset = 100u64;
+    let mut f = std::fs::OpenOptions::new()
+        .read(true)
+        .write(true)
+        .create(true)
+        .append(true)
+        .open("/fyi/fs_seek_append.dir/file")
+        .unwrap();
+    let new_offset = f.seek(SeekFrom::Start(offset)).unwrap();
+
+    assert_eq!(offset, new_offset);
+}
diff --git a/tests/wasi-fyi/fs_seek_append_mode.rs b/tests/wasi-fyi/fs_seek_append_mode.rs
index 7e1d54321f0..74bb0698c67 100644
--- a/tests/wasi-fyi/fs_seek_append_mode.rs
+++ b/tests/wasi-fyi/fs_seek_append_mode.rs
@@ -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
diff --git a/tests/wasi-fyi/test_fs/fyi/fs_seek_append.dir/file b/tests/wasi-fyi/test_fs/fyi/fs_seek_append.dir/file
new file mode 100644
index 00000000000..e69de29bb2d