diff --git a/fs/bridge.go b/fs/bridge.go index eeaac5acd..6c180725b 100644 --- a/fs/bridge.go +++ b/fs/bridge.go @@ -1175,18 +1175,22 @@ func (b *rawBridge) Lseek(cancel <-chan struct{}, in *fuse.LseekIn, out *fuse.Ls out.Offset = off return errnoToStatus(errno) } - + var attr fuse.AttrOut + if s := b.getattr(ctx, n, nil, &attr); s != 0 { + return errnoToStatus(s) + } if in.Whence == _SEEK_DATA { + if in.Offset >= attr.Size { + return errnoToStatus(syscall.ENXIO) + } out.Offset = in.Offset return fuse.OK } if in.Whence == _SEEK_HOLE { - var attr fuse.AttrOut - if s := b.getattr(ctx, n, nil, &attr); s != 0 { - return errnoToStatus(s) + if in.Offset > attr.Size { + return errnoToStatus(syscall.ENXIO) } - out.Offset = attr.Size return fuse.OK } diff --git a/posixtest/test.go b/posixtest/test.go index 8fc03ba7b..10b06a498 100644 --- a/posixtest/test.go +++ b/posixtest/test.go @@ -7,6 +7,7 @@ package posixtest import ( "bytes" + "errors" "fmt" "io/ioutil" "os" @@ -34,6 +35,7 @@ var All = map[string]func(*testing.T, string){ "Link": Link, "LinkUnlinkRename": LinkUnlinkRename, "LseekHoleSeeksToEOF": LseekHoleSeeksToEOF, + "LseekEnxioCheck": LseekEnxioCheck, "RenameOverwriteDestNoExist": RenameOverwriteDestNoExist, "RenameOverwriteDestExist": RenameOverwriteDestExist, "RenameOpenDir": RenameOpenDir, @@ -720,3 +722,48 @@ func LseekHoleSeeksToEOF(t *testing.T, mnt string) { t.Errorf("got offset %d, want %d", off, len(content)) } } + +func LseekEnxioCheck(t *testing.T, mnt string) { + fn := filepath.Join(mnt, "file.bin") + content := bytes.Repeat([]byte("abcxyz\n"), 1024) + if err := ioutil.WriteFile(fn, content, 0644); err != nil { + t.Fatalf("WriteFile: %v", err) + } + + fd, err := syscall.Open(fn, syscall.O_RDONLY, 0644) + if err != nil { + t.Fatalf("Open: %v", err) + } + defer syscall.Close(fd) + + testCases := []struct { + name string + offset int64 + whence int + }{ + { + name: "Lseek SEEK_DATA where offset is at EOF returns ENXIO", + offset: int64(len(content)), + whence: unix.SEEK_DATA, + }, + { + name: "Lseek SEEK_DATA where offset greater than EOF returns ENXIO", + offset: int64(len(content)) + 1, + whence: unix.SEEK_DATA, + }, + { + name: "Lseek SEEK_HOLE where offset is greater than EOF returns ENXIO", + offset: int64(len(content)) + 1, + whence: unix.SEEK_HOLE, + }, + } + + for _, tc := range testCases { + _, err := unix.Seek(fd, tc.offset, tc.whence) + if err != nil { + if !errors.Is(err, syscall.ENXIO) { + t.Errorf("Failed test case: %s; got %v, want %v", tc.name, err, syscall.ENXIO) + } + } + } +}