fs: implement fd_tell host function in terms of fd_seek (#1043)

Signed-off-by: Edoardo Vacchi <evacchi@users.noreply.github.com>
This commit is contained in:
Edoardo Vacchi
2023-01-17 17:11:30 +01:00
committed by GitHub
parent 3cf29f9f76
commit 15889085a5
2 changed files with 96 additions and 7 deletions

View File

@@ -945,7 +945,17 @@ func fdSyncFn(_ context.Context, mod api.Module, params []uint64) Errno {
// offset of a file descriptor.
//
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_tellfd-fd---errno-filesize
var fdTell = stubFunction(FdTellName, []wasm.ValueType{i32, i32}, "fd", "result.offset")
var fdTell = newHostFunc(FdTellName, fdTellFn, []api.ValueType{i32, i32}, "fd", "result.offset")
func fdTellFn(ctx context.Context, mod api.Module, params []uint64) Errno {
fd := params[0]
offset := uint64(0)
whence := uint64(io.SeekCurrent)
resultNewoffset := params[1]
fdSeekParams := []uint64{fd, offset, whence, resultNewoffset}
return fdSeekFn(ctx, mod, fdSeekParams)
}
// fdWrite is the WASI function named FdWriteName which writes to a file
// descriptor.

View File

@@ -2006,13 +2006,92 @@ func Test_fdSync(t *testing.T) {
}
}
// Test_fdTell only tests it is stubbed for GrainLang per #271
func Test_fdTell(t *testing.T) {
log := requireErrnoNosys(t, FdTellName, 0, 0)
require.Equal(t, `
--> wasi_snapshot_preview1.fd_tell(fd=0,result.offset=0)
<-- errno=ENOSYS
`, log)
mod, fd, log, r := requireOpenFile(t, t.TempDir(), "test_path", []byte("wazero"), true)
defer r.Close(testCtx)
defer log.Reset()
resultNewoffset := uint32(1) // arbitrary offset in api.Memory for the new offset value
expectedOffset := int64(1) // = offset
expectedMemory := []byte{
'?', // resultNewoffset is after this
1, 0, 0, 0, 0, 0, 0, 0, // = expectedOffset
'?',
}
expectedLog := `
==> wasi_snapshot_preview1.fd_tell(fd=4,result.offset=1)
<== errno=ESUCCESS
`
maskMemory(t, mod, len(expectedMemory))
// Since we initialized this file, we know it is a seeker (because it is a MapFile)
fsc := mod.(*wasm.CallContext).Sys.FS()
f, ok := fsc.LookupFile(fd)
require.True(t, ok)
seeker := f.File.(io.Seeker)
// set the initial offset of the file to 1
offset, err := seeker.Seek(1, io.SeekStart)
require.NoError(t, err)
require.Equal(t, int64(1), offset)
requireErrno(t, ErrnoSuccess, mod, FdTellName, uint64(fd), uint64(resultNewoffset))
require.Equal(t, expectedLog, "\n"+log.String())
actual, ok := mod.Memory().Read(0, uint32(len(expectedMemory)))
require.True(t, ok)
require.Equal(t, expectedMemory, actual)
offset, err = seeker.Seek(0, io.SeekCurrent)
require.NoError(t, err)
require.Equal(t, expectedOffset, offset) // test that the offset of file is actually updated.
}
func Test_fdTell_Errors(t *testing.T) {
mod, fd, log, r := requireOpenFile(t, t.TempDir(), "test_path", []byte("wazero"), true)
defer r.Close(testCtx)
memorySize := mod.Memory().Size()
tests := []struct {
name string
fd uint32
resultNewoffset uint32
expectedErrno Errno
expectedLog string
}{
{
name: "invalid fd",
fd: 42, // arbitrary invalid fd
expectedErrno: ErrnoBadf,
expectedLog: `
==> wasi_snapshot_preview1.fd_tell(fd=42,result.offset=0)
<== errno=EBADF
`,
},
{
name: "out-of-memory writing resultNewoffset",
fd: fd,
resultNewoffset: memorySize,
expectedErrno: ErrnoFault,
expectedLog: `
==> wasi_snapshot_preview1.fd_tell(fd=4,result.offset=65536)
<== errno=EFAULT
`,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
defer log.Reset()
requireErrno(t, tc.expectedErrno, mod, FdTellName, uint64(tc.fd), uint64(tc.resultNewoffset))
require.Equal(t, tc.expectedLog, "\n"+log.String())
})
}
}
func Test_fdWrite(t *testing.T) {