From 59076bccf58a491ab6a5df2bfb834e37602bfc73 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Fri, 13 Jan 2023 23:16:14 +0000 Subject: [PATCH] fs: Adds fd_sync (#1026) Signed-off-by: Nuno Cruces --- imports/wasi_snapshot_preview1/fs.go | 19 ++++++++- imports/wasi_snapshot_preview1/fs_test.go | 47 ++++++++++++++++++++--- internal/syscallfs/syscall_windows.go | 3 +- internal/syscallfs/syscallfs.go | 3 ++ 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/imports/wasi_snapshot_preview1/fs.go b/imports/wasi_snapshot_preview1/fs.go index 2313efa9..c966aaa5 100644 --- a/imports/wasi_snapshot_preview1/fs.go +++ b/imports/wasi_snapshot_preview1/fs.go @@ -950,7 +950,24 @@ func fdSeekFn(_ context.Context, mod api.Module, params []uint64) Errno { // and metadata of a file to disk. // // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_syncfd-fd---errno -var fdSync = stubFunction(FdSyncName, []api.ValueType{i32}, "fd") +var fdSync = newHostFunc(FdSyncName, fdSyncFn, []api.ValueType{i32}, "fd") + +func fdSyncFn(_ context.Context, mod api.Module, params []uint64) Errno { + fsc := mod.(*wasm.CallContext).Sys.FS() + fd := uint32(params[0]) + + type syncer interface{ Sync() error } + // Check to see if the file descriptor is available + if f, ok := fsc.LookupFile(fd); !ok { + return ErrnoBadf + // fs.FS doesn't declare Sync, but implementations such as os.File implement it. + } else if syncer, ok := f.File.(syncer); !ok { + return ErrnoBadf + } else if err := syncer.Sync(); err != nil { + return ErrnoIo + } + return ErrnoSuccess +} // fdTell is the WASI function named FdTellName which returns the current // offset of a file descriptor. diff --git a/imports/wasi_snapshot_preview1/fs_test.go b/imports/wasi_snapshot_preview1/fs_test.go index bfc46387..41e5518d 100644 --- a/imports/wasi_snapshot_preview1/fs_test.go +++ b/imports/wasi_snapshot_preview1/fs_test.go @@ -1666,13 +1666,48 @@ func Test_fdSeek_Errors(t *testing.T) { } } -// Test_fdSync only tests it is stubbed for GrainLang per #271 +// Test_fdSync only tests that the call succeeds; it's hard to test its effectiveness. func Test_fdSync(t *testing.T) { - log := requireErrnoNosys(t, FdSyncName, 0) - require.Equal(t, ` ---> wasi_snapshot_preview1.fd_sync(fd=0) -<-- errno=ENOSYS -`, log) + tmpDir := t.TempDir() // open before loop to ensure no locking problems. + pathName := "test_path" + mod, fd, log, r := requireOpenFile(t, tmpDir, pathName, []byte{}, false) + defer r.Close(testCtx) + + tests := []struct { + name string + fd uint32 + expectedErrno Errno + expectedLog string + }{ + { + name: "invalid fd", + fd: 42, // arbitrary invalid fd + expectedErrno: ErrnoBadf, + expectedLog: ` +==> wasi_snapshot_preview1.fd_sync(fd=42) +<== errno=EBADF +`, + }, + { + name: "valid fd", + fd: fd, + expectedErrno: ErrnoSuccess, + expectedLog: ` +==> wasi_snapshot_preview1.fd_sync(fd=4) +<== errno=ESUCCESS +`, + }, + } + + for _, tt := range tests { + tc := tt + t.Run(tc.name, func(t *testing.T) { + defer log.Reset() + + requireErrno(t, tc.expectedErrno, mod, FdSyncName, uint64(tc.fd)) + require.Equal(t, tc.expectedLog, "\n"+log.String()) + }) + } } // Test_fdTell only tests it is stubbed for GrainLang per #271 diff --git a/internal/syscallfs/syscall_windows.go b/internal/syscallfs/syscall_windows.go index ecfb3edb..52a46751 100644 --- a/internal/syscallfs/syscall_windows.go +++ b/internal/syscallfs/syscall_windows.go @@ -97,7 +97,8 @@ func maybeWrapFile(f file) file { return struct { readFile io.Writer - }{f, &windowsWriter{f}} + syncer + }{f, &windowsWriter{f}, f} } // windowsWriter translates error codes not mapped properly by Go. diff --git a/internal/syscallfs/syscallfs.go b/internal/syscallfs/syscallfs.go index 13e40a66..195ff697 100644 --- a/internal/syscallfs/syscallfs.go +++ b/internal/syscallfs/syscallfs.go @@ -142,4 +142,7 @@ type readFile interface { type file interface { readFile io.Writer + syncer } + +type syncer interface{ Sync() error }