src/internal/poll/fd_windows.go | 6 ++++++ src/os/os_windows_test.go | 38 ++++++++++++++++++++++++++++++++++++++ diff --git a/src/internal/poll/fd_windows.go b/src/internal/poll/fd_windows.go index acc2ab0c6e1eaf471f8aee67f5fe6eee8d1d0c68..74188c057277ed8e921f3a40c9af8d753cf80633 100644 --- a/src/internal/poll/fd_windows.go +++ b/src/internal/poll/fd_windows.go @@ -1106,6 +1106,12 @@ fd.l.Lock() defer fd.l.Unlock() + if !fd.isBlocking && whence == io.SeekCurrent { + // Windows doesn't keep the file pointer for overlapped file handles. + // We do it ourselves in case to account for any read or write + // operations that may have occurred. + offset += fd.offset + } n, err := syscall.Seek(fd.Sysfd, offset, whence) fd.setOffset(n) return n, err diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go index 515d1c135901e0114119d3563fe2a08035340d26..d9af25d4085c17b94f9ca0e3d7ff28ba3480bcd8 100644 --- a/src/os/os_windows_test.go +++ b/src/os/os_windows_test.go @@ -1845,6 +1845,44 @@ }) } } +func TestFileOverlappedSeek(t *testing.T) { + t.Parallel() + name := filepath.Join(t.TempDir(), "foo") + f := newFileOverlapped(t, name, true) + content := []byte("foo") + if _, err := f.Write(content); err != nil { + t.Fatal(err) + } + // Check that the file pointer is at the expected offset. + n, err := f.Seek(0, io.SeekCurrent) + if err != nil { + t.Fatal(err) + } + if n != int64(len(content)) { + t.Errorf("expected file pointer to be at offset %d, got %d", len(content), n) + } + // Set the file pointer to the start of the file. + if _, err := f.Seek(0, io.SeekStart); err != nil { + t.Fatal(err) + } + // Read the first byte. + var buf [1]byte + if _, err := f.Read(buf[:]); err != nil { + t.Fatal(err) + } + if !bytes.Equal(buf[:], content[:len(buf)]) { + t.Errorf("expected %q, got %q", content[:len(buf)], buf[:]) + } + // Check that the file pointer is at the expected offset. + n, err = f.Seek(0, io.SeekCurrent) + if err != nil { + t.Fatal(err) + } + if n != int64(len(buf)) { + t.Errorf("expected file pointer to be at offset %d, got %d", len(buf), n) + } +} + func TestPipe(t *testing.T) { t.Parallel() r, w, err := os.Pipe()