Repository: tetratelabs/wazero
Pull request #1866 (2023-12-12 19:50:13)

wasi: resets offsets in reopen
This commit fixes `fd_fdstat_set_flags` resetting the fd offset due to it reopening the file every time.  This fix gets the current offset before reopening and restore the offset with seek. This addresses https://github.com/tetratelabs/wazero/issues/1865.

NB: A couple of existing tests are actually spec'd wrong. To fix, I introduced addition `Seek` calls before checking removing append flag.

yagehu: > as you can see, unfortunately this is failing on Windows

Fixed!
evacchi: thanks!
evacchi: I see you force-pushed new changes, let me know when the PR is in a stable state @yagehu ! :)
yagehu: > I see you force-pushed new changes, let me know when the PR is in a stable state @yagehu ! :)

I'm done. Just a quick fix to avoid double `IsDir` calls. Thanks!

Patch:
diff --git a/internal/sysfs/osfile.go b/internal/sysfs/osfile.go
index cecab8cb..952a0ca9 100644
--- a/internal/sysfs/osfile.go
+++ b/internal/sysfs/osfile.go
@@ -98,9 +98,38 @@ func (f *osFile) reopen() (errno experimentalsys.Errno) {
 	// Clear any create flag, as we are re-opening, not re-creating.
 	f.flag &= ^experimentalsys.O_CREAT
 
+	var (
+		isDir  bool
+		offset int64
+		err    error
+	)
+
+	isDir, errno = f.IsDir()
+	if errno != 0 {
+		return errno
+	}
+
+	if !isDir {
+		offset, err = f.file.Seek(0, 1)
+		if err != nil {
+			return experimentalsys.UnwrapOSError(err)
+		}
+	}
+
 	_ = f.close()
 	f.file, errno = OpenFile(f.path, f.flag, f.perm)
-	return
+	if errno != 0 {
+		return errno
+	}
+
+	if !isDir {
+		_, err = f.file.Seek(offset, 0)
+		if err != nil {
+			return experimentalsys.UnwrapOSError(err)
+		}
+	}
+
+	return 0
 }
 
 // IsNonblock implements the same method as documented on fsapi.File


Test patch:
diff --git a/imports/wasi_snapshot_preview1/fs_test.go b/imports/wasi_snapshot_preview1/fs_test.go
index c17c6d9d..6cae4d0d 100644
--- a/imports/wasi_snapshot_preview1/fs_test.go
+++ b/imports/wasi_snapshot_preview1/fs_test.go
@@ -597,6 +597,13 @@ func Test_fdFdstatSetFlags(t *testing.T) {
 `, "\n"+log.String()) // FIXME? flags==0 prints 'flags='
 	log.Reset()
 
+	requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.FdSeekName, uint64(fd), uint64(0), uint64(0), uint64(1024))
+	require.Equal(t, `
+==> wasi_snapshot_preview1.fd_seek(fd=4,offset=0,whence=0)
+<== (newoffset=0,errno=ESUCCESS)
+`, "\n"+log.String())
+	log.Reset()
+
 	// Without O_APPEND flag, the data is written at the beginning.
 	writeWazero()
 	requireFileContent("wazero6789" + "wazero")
@@ -609,6 +616,16 @@ func Test_fdFdstatSetFlags(t *testing.T) {
 `, "\n"+log.String()) // FIXME? flags==1 prints 'flags=APPEND'
 	log.Reset()
 
+	// Restoring the O_APPEND flag should not reset fd offset.
+	requireErrnoResult(t, wasip1.ErrnoSuccess, mod, wasip1.FdTellName, uint64(fd), uint64(1024))
+	require.Equal(t, `
+==> wasi_snapshot_preview1.fd_tell(fd=4,result.offset=1024)
+<== errno=ESUCCESS
+`, "\n"+log.String())
+	log.Reset()
+	offset, _ := mod.Memory().Read(1024, 4)
+	require.Equal(t, offset, []byte{6, 0, 0, 0})
+
 	// with O_APPEND flag, the data is appended to buffer.
 	writeWazero()
 	requireFileContent("wazero6789" + "wazero" + "wazero")
diff --git a/internal/sysfs/file_test.go b/internal/sysfs/file_test.go
index b27b2bc4..44e7eb54 100644
--- a/internal/sysfs/file_test.go
+++ b/internal/sysfs/file_test.go
@@ -147,6 +147,9 @@ func TestFileSetAppend(t *testing.T) {
 	require.EqualErrno(t, 0, f.SetAppend(false))
 	require.False(t, f.IsAppend())
 
+	_, errno = f.Seek(0, 0)
+	require.EqualErrno(t, 0, errno)
+
 	// without O_APPEND flag, the data writes at offset zero
 	_, errno = f.Write([]byte("wazero"))
 	require.EqualErrno(t, 0, errno)