From 7028ed181365e2a947813124c8057af975d7d0b5 Mon Sep 17 00:00:00 2001 From: Jelle van den Hooff Date: Sat, 23 Nov 2024 13:18:07 -0800 Subject: [PATCH] fs: implement seek and fallocate --- .../golangorg_x_sys_unix_gensyscall_amd64.go | 8 ++ .../golangorg_x_sys_unix_gensyscall_arm64.go | 8 ++ .../hooks/go123/syscall_gensyscall_amd64.go | 8 ++ .../hooks/go123/syscall_gensyscall_arm64.go | 8 ++ internal/simulation/gensyscall/main.go | 2 + internal/simulation/linux_gensyscall_amd64.go | 58 ++++++++ internal/simulation/linux_gensyscall_arm64.go | 58 ++++++++ internal/simulation/os_linux.go | 86 +++++++++++ internal/tests/behavior/disk_linux_test.go | 62 ++++++++ internal/tests/behavior/disk_test.go | 134 ++++++++++++++++++ .../translate/hooks_go123_amd64_gensyscall.go | 4 + .../translate/hooks_go123_arm64_gensyscall.go | 4 + 12 files changed, 440 insertions(+) create mode 100644 internal/tests/behavior/disk_linux_test.go diff --git a/internal/hooks/go123/golangorg_x_sys_unix_gensyscall_amd64.go b/internal/hooks/go123/golangorg_x_sys_unix_gensyscall_amd64.go index 388d4b1..b91d8d4 100644 --- a/internal/hooks/go123/golangorg_x_sys_unix_gensyscall_amd64.go +++ b/internal/hooks/go123/golangorg_x_sys_unix_gensyscall_amd64.go @@ -32,6 +32,10 @@ func GolangOrgXSysUnix_connect(s int, addr unsafe.Pointer, addrlen simulation.So return simulation.SyscallSysConnect(s, addr, addrlen) } +func GolangOrgXSysUnix_Fallocate(fd int, mode uint32, off int64, len int64) (err error) { + return simulation.SyscallSysFallocate(fd, mode, off, len) +} + func GolangOrgXSysUnix_Fdatasync(fd int) (err error) { return simulation.SyscallSysFdatasync(fd) } @@ -124,6 +128,10 @@ func GolangOrgXSysUnix_Renameat(olddirfd int, oldpath string, newdirfd int, newp return simulation.SyscallSysRenameat(olddirfd, oldpath, newdirfd, newpath) } +func GolangOrgXSysUnix_Seek(fd int, offset int64, whence int) (off int64, err error) { + return simulation.SyscallSysLseek(fd, offset, whence) +} + func GolangOrgXSysUnix_setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { return simulation.SyscallSysSetsockopt(s, level, name, val, vallen) } diff --git a/internal/hooks/go123/golangorg_x_sys_unix_gensyscall_arm64.go b/internal/hooks/go123/golangorg_x_sys_unix_gensyscall_arm64.go index 554995a..23eeaa6 100644 --- a/internal/hooks/go123/golangorg_x_sys_unix_gensyscall_arm64.go +++ b/internal/hooks/go123/golangorg_x_sys_unix_gensyscall_arm64.go @@ -32,6 +32,10 @@ func GolangOrgXSysUnix_connect(s int, addr unsafe.Pointer, addrlen simulation.So return simulation.SyscallSysConnect(s, addr, addrlen) } +func GolangOrgXSysUnix_Fallocate(fd int, mode uint32, off int64, len int64) (err error) { + return simulation.SyscallSysFallocate(fd, mode, off, len) +} + func GolangOrgXSysUnix_Fdatasync(fd int) (err error) { return simulation.SyscallSysFdatasync(fd) } @@ -124,6 +128,10 @@ func GolangOrgXSysUnix_Renameat(olddirfd int, oldpath string, newdirfd int, newp return simulation.SyscallSysRenameat(olddirfd, oldpath, newdirfd, newpath) } +func GolangOrgXSysUnix_Seek(fd int, offset int64, whence int) (off int64, err error) { + return simulation.SyscallSysLseek(fd, offset, whence) +} + func GolangOrgXSysUnix_setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { return simulation.SyscallSysSetsockopt(s, level, name, val, vallen) } diff --git a/internal/hooks/go123/syscall_gensyscall_amd64.go b/internal/hooks/go123/syscall_gensyscall_amd64.go index 4652897..766ae5f 100644 --- a/internal/hooks/go123/syscall_gensyscall_amd64.go +++ b/internal/hooks/go123/syscall_gensyscall_amd64.go @@ -32,6 +32,10 @@ func Syscall_connect(s int, addr unsafe.Pointer, addrlen simulation.Socklen) (er return simulation.SyscallSysConnect(s, addr, addrlen) } +func Syscall_Fallocate(fd int, mode uint32, off int64, len int64) (err error) { + return simulation.SyscallSysFallocate(fd, mode, off, len) +} + func Syscall_fcntl(fd int, cmd int, arg int) (val int, err error) { return simulation.SyscallSysFcntl(fd, cmd, arg) } @@ -124,6 +128,10 @@ func Syscall_Renameat(olddirfd int, oldpath string, newdirfd int, newpath string return simulation.SyscallSysRenameat(olddirfd, oldpath, newdirfd, newpath) } +func Syscall_Seek(fd int, offset int64, whence int) (off int64, err error) { + return simulation.SyscallSysLseek(fd, offset, whence) +} + func Syscall_setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { return simulation.SyscallSysSetsockopt(s, level, name, val, vallen) } diff --git a/internal/hooks/go123/syscall_gensyscall_arm64.go b/internal/hooks/go123/syscall_gensyscall_arm64.go index 33262c2..9b49bf3 100644 --- a/internal/hooks/go123/syscall_gensyscall_arm64.go +++ b/internal/hooks/go123/syscall_gensyscall_arm64.go @@ -32,6 +32,10 @@ func Syscall_connect(s int, addr unsafe.Pointer, addrlen simulation.Socklen) (er return simulation.SyscallSysConnect(s, addr, addrlen) } +func Syscall_Fallocate(fd int, mode uint32, off int64, len int64) (err error) { + return simulation.SyscallSysFallocate(fd, mode, off, len) +} + func Syscall_fcntl(fd int, cmd int, arg int) (val int, err error) { return simulation.SyscallSysFcntl(fd, cmd, arg) } @@ -124,6 +128,10 @@ func Syscall_Renameat(olddirfd int, oldpath string, newdirfd int, newpath string return simulation.SyscallSysRenameat(olddirfd, oldpath, newdirfd, newpath) } +func Syscall_Seek(fd int, offset int64, whence int) (off int64, err error) { + return simulation.SyscallSysLseek(fd, offset, whence) +} + func Syscall_setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { return simulation.SyscallSysSetsockopt(s, level, name, val, vallen) } diff --git a/internal/simulation/gensyscall/main.go b/internal/simulation/gensyscall/main.go index 60db305..2816cce 100644 --- a/internal/simulation/gensyscall/main.go +++ b/internal/simulation/gensyscall/main.go @@ -193,6 +193,7 @@ var filterCommon = []string{ "SYS_CHDIR", "SYS_CLOSE", "SYS_CONNECT", + "SYS_FALLOCATE", "SYS_FCNTL", "SYS_FDATASYNC", "SYS_FLOCK", @@ -207,6 +208,7 @@ var filterCommon = []string{ "SYS_GETSOCKNAME", "SYS_GETSOCKOPT", "SYS_LISTEN", + "SYS_LSEEK", "SYS_MADVISE", "SYS_MKDIRAT", "SYS_MMAP", diff --git a/internal/simulation/linux_gensyscall_amd64.go b/internal/simulation/linux_gensyscall_amd64.go index d382e90..6057570 100644 --- a/internal/simulation/linux_gensyscall_amd64.go +++ b/internal/simulation/linux_gensyscall_amd64.go @@ -35,6 +35,7 @@ type linuxOSIface interface { SysChdir(path string) (err error) SysClose(fd int) (err error) SysConnect(s int, addr unsafe.Pointer, addrlen Socklen) (err error) + SysFallocate(fd int, mode uint32, off int64, len int64) (err error) SysFcntl(fd int, cmd int, arg int) (val int, err error) SysFdatasync(fd int) (err error) SysFlock(fd int, how int) (err error) @@ -49,6 +50,7 @@ type linuxOSIface interface { SysGetsockname(fd int, rsa syscallabi.ValueView[RawSockaddrAny], addrlen syscallabi.ValueView[Socklen]) (err error) SysGetsockopt(s int, level int, name int, val unsafe.Pointer, vallen syscallabi.ValueView[Socklen]) (err error) SysListen(s int, n int) (err error) + SysLseek(fd int, offset int64, whence int) (off int64, err error) SysMadvise(b syscallabi.SliceView[byte], advice int) (err error) SysMkdirat(dirfd int, path string, mode uint32) (err error) SysMmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) @@ -140,6 +142,16 @@ func (os *LinuxOS) HandleSyscall(syscall *syscallabi.Syscall) { err := os.SysConnect(s, addr, addrlen) syscall.Errno = syscallabi.ErrErrno(err) syscall.Complete() + case unix.SYS_FALLOCATE: + // called by (for find references): + _ = SyscallSysFallocate + fd := int(syscall.Int0) + mode := uint32(syscall.Int1) + off := int64(syscall.Int2) + len := int64(syscall.Int3) + err := os.SysFallocate(fd, mode, off, len) + syscall.Errno = syscallabi.ErrErrno(err) + syscall.Complete() case unix.SYS_FCNTL: // called by (for find references): _ = SyscallSysFcntl @@ -257,6 +269,16 @@ func (os *LinuxOS) HandleSyscall(syscall *syscallabi.Syscall) { err := os.SysListen(s, n) syscall.Errno = syscallabi.ErrErrno(err) syscall.Complete() + case unix.SYS_LSEEK: + // called by (for find references): + _ = SyscallSysLseek + fd := int(syscall.Int0) + offset := int64(syscall.Int1) + whence := int(syscall.Int2) + off, err := os.SysLseek(fd, offset, whence) + syscall.R0 = uintptr(off) + syscall.Errno = syscallabi.ErrErrno(err) + syscall.Complete() case unix.SYS_MADVISE: // called by (for find references): _ = SyscallSysMadvise @@ -514,6 +536,22 @@ func SyscallSysConnect(s int, addr unsafe.Pointer, addrlen Socklen) (err error) return } +//go:norace +func SyscallSysFallocate(fd int, mode uint32, off int64, len int64) (err error) { + // invokes (for go to definition): + _ = (*LinuxOS).SysFallocate + syscall := syscallabi.GetGoroutineLocalSyscall() + syscall.OS = linuxOS + syscall.Trap = unix.SYS_FALLOCATE + syscall.Int0 = uintptr(fd) + syscall.Int1 = uintptr(mode) + syscall.Int2 = uintptr(off) + syscall.Int3 = uintptr(len) + linuxOS.dispatchSyscall(syscall) + err = syscallabi.ErrnoErr(syscall.Errno) + return +} + //go:norace func SyscallSysFcntl(fd int, cmd int, arg int) (val int, err error) { // invokes (for go to definition): @@ -725,6 +763,22 @@ func SyscallSysListen(s int, n int) (err error) { return } +//go:norace +func SyscallSysLseek(fd int, offset int64, whence int) (off int64, err error) { + // invokes (for go to definition): + _ = (*LinuxOS).SysLseek + syscall := syscallabi.GetGoroutineLocalSyscall() + syscall.OS = linuxOS + syscall.Trap = unix.SYS_LSEEK + syscall.Int0 = uintptr(fd) + syscall.Int1 = uintptr(offset) + syscall.Int2 = uintptr(whence) + linuxOS.dispatchSyscall(syscall) + off = int64(syscall.R0) + err = syscallabi.ErrnoErr(syscall.Errno) + return +} + //go:norace func SyscallSysMadvise(b []byte, advice int) (err error) { // invokes (for go to definition): @@ -985,6 +1039,8 @@ func IsHandledSyscall(trap uintptr) bool { return true case unix.SYS_CONNECT: return true + case unix.SYS_FALLOCATE: + return true case unix.SYS_FCNTL: return true case unix.SYS_FDATASYNC: @@ -1013,6 +1069,8 @@ func IsHandledSyscall(trap uintptr) bool { return true case unix.SYS_LISTEN: return true + case unix.SYS_LSEEK: + return true case unix.SYS_MADVISE: return true case unix.SYS_MKDIRAT: diff --git a/internal/simulation/linux_gensyscall_arm64.go b/internal/simulation/linux_gensyscall_arm64.go index 47d91d8..dccb27a 100644 --- a/internal/simulation/linux_gensyscall_arm64.go +++ b/internal/simulation/linux_gensyscall_arm64.go @@ -35,6 +35,7 @@ type linuxOSIface interface { SysChdir(path string) (err error) SysClose(fd int) (err error) SysConnect(s int, addr unsafe.Pointer, addrlen Socklen) (err error) + SysFallocate(fd int, mode uint32, off int64, len int64) (err error) SysFcntl(fd int, cmd int, arg int) (val int, err error) SysFdatasync(fd int) (err error) SysFlock(fd int, how int) (err error) @@ -50,6 +51,7 @@ type linuxOSIface interface { SysGetsockname(fd int, rsa syscallabi.ValueView[RawSockaddrAny], addrlen syscallabi.ValueView[Socklen]) (err error) SysGetsockopt(s int, level int, name int, val unsafe.Pointer, vallen syscallabi.ValueView[Socklen]) (err error) SysListen(s int, n int) (err error) + SysLseek(fd int, offset int64, whence int) (off int64, err error) SysMadvise(b syscallabi.SliceView[byte], advice int) (err error) SysMkdirat(dirfd int, path string, mode uint32) (err error) SysMmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) @@ -140,6 +142,16 @@ func (os *LinuxOS) HandleSyscall(syscall *syscallabi.Syscall) { err := os.SysConnect(s, addr, addrlen) syscall.Errno = syscallabi.ErrErrno(err) syscall.Complete() + case unix.SYS_FALLOCATE: + // called by (for find references): + _ = SyscallSysFallocate + fd := int(syscall.Int0) + mode := uint32(syscall.Int1) + off := int64(syscall.Int2) + len := int64(syscall.Int3) + err := os.SysFallocate(fd, mode, off, len) + syscall.Errno = syscallabi.ErrErrno(err) + syscall.Complete() case unix.SYS_FCNTL: // called by (for find references): _ = SyscallSysFcntl @@ -267,6 +279,16 @@ func (os *LinuxOS) HandleSyscall(syscall *syscallabi.Syscall) { err := os.SysListen(s, n) syscall.Errno = syscallabi.ErrErrno(err) syscall.Complete() + case unix.SYS_LSEEK: + // called by (for find references): + _ = SyscallSysLseek + fd := int(syscall.Int0) + offset := int64(syscall.Int1) + whence := int(syscall.Int2) + off, err := os.SysLseek(fd, offset, whence) + syscall.R0 = uintptr(off) + syscall.Errno = syscallabi.ErrErrno(err) + syscall.Complete() case unix.SYS_MADVISE: // called by (for find references): _ = SyscallSysMadvise @@ -514,6 +536,22 @@ func SyscallSysConnect(s int, addr unsafe.Pointer, addrlen Socklen) (err error) return } +//go:norace +func SyscallSysFallocate(fd int, mode uint32, off int64, len int64) (err error) { + // invokes (for go to definition): + _ = (*LinuxOS).SysFallocate + syscall := syscallabi.GetGoroutineLocalSyscall() + syscall.OS = linuxOS + syscall.Trap = unix.SYS_FALLOCATE + syscall.Int0 = uintptr(fd) + syscall.Int1 = uintptr(mode) + syscall.Int2 = uintptr(off) + syscall.Int3 = uintptr(len) + linuxOS.dispatchSyscall(syscall) + err = syscallabi.ErrnoErr(syscall.Errno) + return +} + //go:norace func SyscallSysFcntl(fd int, cmd int, arg int) (val int, err error) { // invokes (for go to definition): @@ -743,6 +781,22 @@ func SyscallSysListen(s int, n int) (err error) { return } +//go:norace +func SyscallSysLseek(fd int, offset int64, whence int) (off int64, err error) { + // invokes (for go to definition): + _ = (*LinuxOS).SysLseek + syscall := syscallabi.GetGoroutineLocalSyscall() + syscall.OS = linuxOS + syscall.Trap = unix.SYS_LSEEK + syscall.Int0 = uintptr(fd) + syscall.Int1 = uintptr(offset) + syscall.Int2 = uintptr(whence) + linuxOS.dispatchSyscall(syscall) + off = int64(syscall.R0) + err = syscallabi.ErrnoErr(syscall.Errno) + return +} + //go:norace func SyscallSysMadvise(b []byte, advice int) (err error) { // invokes (for go to definition): @@ -985,6 +1039,8 @@ func IsHandledSyscall(trap uintptr) bool { return true case unix.SYS_CONNECT: return true + case unix.SYS_FALLOCATE: + return true case unix.SYS_FCNTL: return true case unix.SYS_FDATASYNC: @@ -1015,6 +1071,8 @@ func IsHandledSyscall(trap uintptr) bool { return true case unix.SYS_LISTEN: return true + case unix.SYS_LSEEK: + return true case unix.SYS_MADVISE: return true case unix.SYS_MKDIRAT: diff --git a/internal/simulation/os_linux.go b/internal/simulation/os_linux.go index 8918f03..621b6f4 100644 --- a/internal/simulation/os_linux.go +++ b/internal/simulation/os_linux.go @@ -5,6 +5,7 @@ package simulation import ( "encoding/binary" "errors" + "io" "log" "log/slog" "math/rand" @@ -479,6 +480,91 @@ func (l *LinuxOS) SysRead(fd int, data syscallabi.ByteSliceView) (int, error) { } } +func (l *LinuxOS) SysFallocate(fd int, mode uint32, off int64, len int64) (err error) { + l.mu.Lock() + defer l.mu.Unlock() + if l.shutdown { + return syscall.EINVAL + } + + fdInternal, ok := l.files[fd] + if !ok { + return syscall.EBADFD + } + + f, ok := fdInternal.(*OsFile) + if !ok { + return syscall.EBADFD + } + + logf("fallocate %d %d %d %d", fd, mode, off, len) + + if mode != 0 { + return syscall.EINVAL + } + + if off != 0 { + return syscall.EINVAL + } + + stat, err := l.simulation.main.filesystem.Statfd(f.inode) + if err != nil { + // huh + return err + } + + if len > stat.Size { + l.machine.filesystem.Truncate(f.inode, int(len)) + } + + return nil +} + +func (l *LinuxOS) SysLseek(fd int, offset int64, whence int) (off int64, err error) { + l.mu.Lock() + defer l.mu.Unlock() + if l.shutdown { + return 0, syscall.EINVAL + } + + fdInternal, ok := l.files[fd] + if !ok { + return 0, syscall.EBADFD + } + + f, ok := fdInternal.(*OsFile) + if !ok { + return 0, syscall.EBADFD + } + + logf("lseek %d %d %d", fd, offset, whence) + var newPos int64 + + switch whence { + case io.SeekCurrent: + newPos = f.pos + offset + case io.SeekEnd: + stat, err := l.simulation.main.filesystem.Statfd(f.inode) + if err != nil { + // huh + return 0, err + } + newPos = stat.Size + offset + case io.SeekStart: + newPos = offset + default: + return 0, syscall.EINVAL + } + + if newPos < 0 { + return 0, syscall.EINVAL + } + + f.pos = newPos + + return f.pos, nil +} + func (l *LinuxOS) SysPwrite64(fd int, data syscallabi.ByteSliceView, offset int64) (int, error) { l.mu.Lock() defer l.mu.Unlock() diff --git a/internal/tests/behavior/disk_linux_test.go b/internal/tests/behavior/disk_linux_test.go new file mode 100644 index 0000000..6c9e53a --- /dev/null +++ b/internal/tests/behavior/disk_linux_test.go @@ -0,0 +1,62 @@ +package behavior_test + +import ( + "os" + "syscall" + "testing" +) + +func TestDiskFallocate(t *testing.T) { + setupRealDisk(t) + + f, err := os.OpenFile("hello", os.O_CREATE|os.O_WRONLY, 0o644) + if err != nil { + t.Fatal(err) + } + + if _, err := f.Write([]byte("hello")); err != nil { + t.Error(err) + } + + // fallocate less than current file shouldn't change anything + if err := syscall.Fallocate(int(f.Fd()), 0, 0, 3); err != nil { + t.Error(err) + } + + bytes, err := os.ReadFile("hello") + if err != nil || string(bytes) != "hello" { + t.Error(err, string(bytes)) + } + + // fallocate more than current file should add zeroes + if err := syscall.Fallocate(int(f.Fd()), 0, 0, 12); err != nil { + t.Error(err) + } + + bytes, err = os.ReadFile("hello") + if err != nil || string(bytes) != "hello\x00\x00\x00\x00\x00\x00\x00" { + t.Error(err, string(bytes)) + } + + if _, err := f.Write([]byte("world")); err != nil { + t.Error(err) + } + + bytes, err = os.ReadFile("hello") + if err != nil || string(bytes) != "helloworld\x00\x00" { + t.Error(err, string(bytes)) + } + + if _, err := f.Write([]byte("goodbye")); err != nil { + t.Error(err) + } + + bytes, err = os.ReadFile("hello") + if err != nil || string(bytes) != "helloworldgoodbye" { + t.Error(err, string(bytes)) + } + + if err := f.Close(); err != nil { + t.Error(err) + } +} diff --git a/internal/tests/behavior/disk_test.go b/internal/tests/behavior/disk_test.go index 415d78c..9257100 100644 --- a/internal/tests/behavior/disk_test.go +++ b/internal/tests/behavior/disk_test.go @@ -501,6 +501,140 @@ func TestDiskReadAtAfterEndOfFile(t *testing.T) { } } +func TestDiskSeekBasic(t *testing.T) { + setupRealDisk(t) + + f, err := os.OpenFile("hello", os.O_CREATE|os.O_RDWR, 0o644) + if err != nil { + t.Error(err) + return + } + + ok := func(offset int64, whence int, expected int64) { + t.Helper() + + got, err := f.Seek(offset, whence) + if err != nil { + t.Errorf("seek %d %d: %v", offset, whence, err) + } + if got != expected { + t.Errorf("seek %d %d: got %d, expected %d", offset, whence, got, expected) + } + } + + bad := func(offset int64, whence int, expected error) { + t.Helper() + + got, err := f.Seek(offset, whence) + if err == nil || !errors.Is(err, expected) { + t.Errorf("seek %d %d: got err %v, expected %v", offset, whence, err, expected) + } + if got != 0 { + t.Errorf("seek %d %d: expected 0 after failure, got %d", offset, whence, got) + } + } + + // get current pos + pos, err := f.Seek(0, io.SeekCurrent) + if err != nil { + t.Error(err) + } + if pos != 0 { + t.Error(pos) + } + + if _, err := f.Write([]byte("hello")); err != nil { + t.Error(err) + return + } + + // get current pos + ok(0, io.SeekCurrent, 5) + + // seek to start + ok(0, io.SeekStart, 0) + ok(0, io.SeekCurrent, 0) + + // read from current pos + buf := make([]byte, 5) + if n, err := f.Read(buf); err != nil || n != 5 { + t.Error(n, err) + } + if string(buf) != "hello" { + t.Error(string(buf)) + } + ok(0, io.SeekCurrent, 5) + + // seek to start + ok(0, io.SeekStart, 0) + ok(0, io.SeekCurrent, 0) + + // seek to end + ok(0, io.SeekEnd, 5) + ok(0, io.SeekCurrent, 5) + + // seek after end + ok(5, io.SeekEnd, 10) + ok(0, io.SeekCurrent, 10) + + // read in nowhere and stay + if n, err := f.Read(buf); err != io.EOF || n != 0 { + t.Error(n, err) + } + ok(0, io.SeekCurrent, 10) + + // writeat over current and read + if n, err := f.WriteAt([]byte("world"), 8); err != nil || n != 5 { + t.Error(n, err) + } + if n, err := f.Read(buf); err != nil || n != 3 { + t.Error(n, err) + } + if string(buf[0:3]) != "rld" { + t.Error(buf[0:3]) + } + ok(0, io.SeekCurrent, 13) + + // seek from start and read + ok(8, io.SeekStart, 8) + if n, err := f.Read(buf); err != nil || n != 5 { + t.Error(n, err) + } + if string(buf) != "world" { + t.Error(buf) + } + ok(0, io.SeekCurrent, 13) + + // seek after end and write + ok(2, io.SeekEnd, 15) + ok(0, io.SeekCurrent, 15) + if n, err := f.Write([]byte("goodbye")); err != nil || n != 7 { + t.Error(err) + } + ok(0, io.SeekCurrent, 22) + + // invalid seek from start + bad(-2, io.SeekStart, syscall.EINVAL) + ok(0, io.SeekCurrent, 22) + + // invalid seek from current + bad(-23, io.SeekCurrent, syscall.EINVAL) + ok(0, io.SeekCurrent, 22) + + // invalid seek from end + pos, err = f.Seek(-23, io.SeekEnd) + bad(-23, io.SeekEnd, syscall.EINVAL) + ok(0, io.SeekCurrent, 22) + + // ok negative seek + ok(-2, io.SeekCurrent, 20) + ok(0, io.SeekCurrent, 20) + + // ok negative seek + ok(-5, io.SeekEnd, 17) + ok(0, io.SeekCurrent, 17) +} + func TestDiskOpenMissingFile(t *testing.T) { setupRealDisk(t) diff --git a/internal/translate/hooks_go123_amd64_gensyscall.go b/internal/translate/hooks_go123_amd64_gensyscall.go index 9bf3acd..f8ad03d 100644 --- a/internal/translate/hooks_go123_amd64_gensyscall.go +++ b/internal/translate/hooks_go123_amd64_gensyscall.go @@ -8,6 +8,7 @@ func init() { {Pkg: "golang.org/x/sys/unix", Selector: "Chdir"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Close"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "connect"}: {Pkg: hooksGo123Package}, + {Pkg: "golang.org/x/sys/unix", Selector: "Fallocate"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Fdatasync"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Flock"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Fstat"}: {Pkg: hooksGo123Package}, @@ -31,6 +32,7 @@ func init() { {Pkg: "golang.org/x/sys/unix", Selector: "pwrite"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "read"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Renameat"}: {Pkg: hooksGo123Package}, + {Pkg: "golang.org/x/sys/unix", Selector: "Seek"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "setsockopt"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "socket"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Uname"}: {Pkg: hooksGo123Package}, @@ -41,6 +43,7 @@ func init() { {Pkg: "syscall", Selector: "Chdir"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "Close"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "connect"}: {Pkg: hooksGo123Package}, + {Pkg: "syscall", Selector: "Fallocate"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "fcntl"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "Fdatasync"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "Flock"}: {Pkg: hooksGo123Package}, @@ -64,6 +67,7 @@ func init() { {Pkg: "syscall", Selector: "pwrite"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "read"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "Renameat"}: {Pkg: hooksGo123Package}, + {Pkg: "syscall", Selector: "Seek"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "setsockopt"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "socket"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "Uname"}: {Pkg: hooksGo123Package}, diff --git a/internal/translate/hooks_go123_arm64_gensyscall.go b/internal/translate/hooks_go123_arm64_gensyscall.go index 94a1d83..6ab127d 100644 --- a/internal/translate/hooks_go123_arm64_gensyscall.go +++ b/internal/translate/hooks_go123_arm64_gensyscall.go @@ -8,6 +8,7 @@ func init() { {Pkg: "golang.org/x/sys/unix", Selector: "Chdir"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Close"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "connect"}: {Pkg: hooksGo123Package}, + {Pkg: "golang.org/x/sys/unix", Selector: "Fallocate"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Fdatasync"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Flock"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Fstat"}: {Pkg: hooksGo123Package}, @@ -31,6 +32,7 @@ func init() { {Pkg: "golang.org/x/sys/unix", Selector: "pwrite"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "read"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Renameat"}: {Pkg: hooksGo123Package}, + {Pkg: "golang.org/x/sys/unix", Selector: "Seek"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "setsockopt"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "socket"}: {Pkg: hooksGo123Package}, {Pkg: "golang.org/x/sys/unix", Selector: "Uname"}: {Pkg: hooksGo123Package}, @@ -41,6 +43,7 @@ func init() { {Pkg: "syscall", Selector: "Chdir"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "Close"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "connect"}: {Pkg: hooksGo123Package}, + {Pkg: "syscall", Selector: "Fallocate"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "fcntl"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "Fdatasync"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "Flock"}: {Pkg: hooksGo123Package}, @@ -64,6 +67,7 @@ func init() { {Pkg: "syscall", Selector: "pwrite"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "read"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "Renameat"}: {Pkg: hooksGo123Package}, + {Pkg: "syscall", Selector: "Seek"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "setsockopt"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "socket"}: {Pkg: hooksGo123Package}, {Pkg: "syscall", Selector: "Uname"}: {Pkg: hooksGo123Package},