Skip to content

Commit 509d5f6

Browse files
committed
internal/poll: don't call Seek for overlapped Windows handles
Overlapped handles don't have the file pointer updated when performing I/O operations, so there is no need to call FD.Seek to reset the file pointer. Also, some overlapped file handles don't support seeking. See golang#74951. Fixes golang#74951. Change-Id: I0edd53beed7d3862730f3b2ed5fe9ba490e66c06 Reviewed-on: https://go-review.googlesource.com/c/go/+/697295 Reviewed-by: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
1 parent 853fc12 commit 509d5f6

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

src/internal/poll/fd_windows.go

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -622,12 +622,22 @@ func (fd *FD) Pread(b []byte, off int64) (int, error) {
622622

623623
fd.l.Lock()
624624
defer fd.l.Unlock()
625-
curoffset, err := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
626-
if err != nil {
627-
return 0, err
625+
if fd.isBlocking {
626+
curoffset, err := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
627+
if err != nil {
628+
return 0, err
629+
}
630+
defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
631+
defer fd.setOffset(curoffset)
632+
} else {
633+
// Overlapped handles don't have the file pointer updated
634+
// when performing I/O operations, so there is no need to
635+
// call Seek to reset the file pointer.
636+
// Also, some overlapped file handles don't support seeking.
637+
// See https://go.dev/issues/74951.
638+
curoffset := fd.offset
639+
defer fd.setOffset(curoffset)
628640
}
629-
defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
630-
defer fd.setOffset(curoffset)
631641
o := &fd.rop
632642
o.InitBuf(b)
633643
fd.setOffset(off)
@@ -847,12 +857,22 @@ func (fd *FD) Pwrite(buf []byte, off int64) (int, error) {
847857

848858
fd.l.Lock()
849859
defer fd.l.Unlock()
850-
curoffset, err := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
851-
if err != nil {
852-
return 0, err
860+
if fd.isBlocking {
861+
curoffset, err := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
862+
if err != nil {
863+
return 0, err
864+
}
865+
defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
866+
defer fd.setOffset(curoffset)
867+
} else {
868+
// Overlapped handles don't have the file pointer updated
869+
// when performing I/O operations, so there is no need to
870+
// call Seek to reset the file pointer.
871+
// Also, some overlapped file handles don't support seeking.
872+
// See https://go.dev/issues/74951.
873+
curoffset := fd.offset
874+
defer fd.setOffset(curoffset)
853875
}
854-
defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
855-
defer fd.setOffset(curoffset)
856876

857877
var ntotal int
858878
for {

src/os/os_windows_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,6 +1883,34 @@ func TestFileOverlappedSeek(t *testing.T) {
18831883
}
18841884
}
18851885

1886+
func TestFileOverlappedReadAtVolume(t *testing.T) {
1887+
// Test that we can use File.ReadAt with an overlapped volume handle.
1888+
// See https://go.dev/issues/74951.
1889+
t.Parallel()
1890+
name := `\\.\` + filepath.VolumeName(t.TempDir())
1891+
namep, err := syscall.UTF16PtrFromString(name)
1892+
if err != nil {
1893+
t.Fatal(err)
1894+
}
1895+
h, err := syscall.CreateFile(namep,
1896+
syscall.GENERIC_READ|syscall.GENERIC_WRITE,
1897+
syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_READ,
1898+
nil, syscall.OPEN_ALWAYS, syscall.FILE_FLAG_OVERLAPPED, 0)
1899+
if err != nil {
1900+
if errors.Is(err, syscall.ERROR_ACCESS_DENIED) {
1901+
t.Skip("skipping test: access denied")
1902+
}
1903+
t.Fatal(err)
1904+
}
1905+
f := os.NewFile(uintptr(h), name)
1906+
defer f.Close()
1907+
1908+
var buf [0]byte
1909+
if _, err := f.ReadAt(buf[:], 0); err != nil {
1910+
t.Fatal(err)
1911+
}
1912+
}
1913+
18861914
func TestPipe(t *testing.T) {
18871915
t.Parallel()
18881916
r, w, err := os.Pipe()

0 commit comments

Comments
 (0)