Skip to content

Commit 7d7cd6e

Browse files
committed
internal/poll: don't call SetFilePointerEx in Seek for overlapped handles
Overlapped handles don't have the file pointer updated when performing I/O operations, so there is no need to call syscall.SetFilePointerEx in FD.Seek. Updating the in-memory offset is sufficient. Updates golang#74951 (provides a more complete fix) Change-Id: Ibede6625cdbd501fc92cfdf8ce2782ec291af2b6 Reviewed-on: https://go-review.googlesource.com/c/go/+/698035 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Damien Neil <[email protected]>
1 parent 41cba31 commit 7d7cd6e

File tree

4 files changed

+55
-7
lines changed

4 files changed

+55
-7
lines changed

src/internal/poll/fd_windows.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,11 +1165,29 @@ func (fd *FD) Seek(offset int64, whence int) (int64, error) {
11651165
}
11661166
defer fd.readWriteUnlock()
11671167

1168-
if !fd.isBlocking && whence == io.SeekCurrent {
1169-
// Windows doesn't keep the file pointer for overlapped file handles.
1170-
// We do it ourselves in case to account for any read or write
1171-
// operations that may have occurred.
1172-
offset += fd.offset
1168+
if !fd.isBlocking {
1169+
// Windows doesn't use the file pointer for overlapped file handles,
1170+
// there is no point on calling syscall.Seek.
1171+
var newOffset int64
1172+
switch whence {
1173+
case io.SeekStart:
1174+
newOffset = offset
1175+
case io.SeekCurrent:
1176+
newOffset = fd.offset + offset
1177+
case io.SeekEnd:
1178+
var size int64
1179+
if err := windows.GetFileSizeEx(fd.Sysfd, &size); err != nil {
1180+
return 0, err
1181+
}
1182+
newOffset = size + offset
1183+
default:
1184+
return 0, windows.ERROR_INVALID_PARAMETER
1185+
}
1186+
if newOffset < 0 {
1187+
return 0, windows.ERROR_NEGATIVE_SEEK
1188+
}
1189+
fd.setOffset(newOffset)
1190+
return newOffset, nil
11731191
}
11741192
n, err := syscall.Seek(fd.Sysfd, offset, whence)
11751193
fd.setOffset(n)

src/internal/syscall/windows/syscall_windows.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const (
3939
ERROR_NOT_SUPPORTED syscall.Errno = 50
4040
ERROR_CALL_NOT_IMPLEMENTED syscall.Errno = 120
4141
ERROR_INVALID_NAME syscall.Errno = 123
42+
ERROR_NEGATIVE_SEEK syscall.Errno = 131
4243
ERROR_LOCK_FAILED syscall.Errno = 167
4344
ERROR_IO_INCOMPLETE syscall.Errno = 996
4445
ERROR_NO_TOKEN syscall.Errno = 1008
@@ -195,6 +196,7 @@ const (
195196
//sys SetFileInformationByHandle(handle syscall.Handle, fileInformationClass uint32, buf unsafe.Pointer, bufsize uint32) (err error) = kernel32.SetFileInformationByHandle
196197
//sys VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) = kernel32.VirtualQuery
197198
//sys GetTempPath2(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPath2W
199+
//sys GetFileSizeEx(handle syscall.Handle, size *int64) (err error) = kernel32.GetFileSizeEx
198200

199201
const (
200202
// flags for CreateToolhelp32Snapshot

src/internal/syscall/windows/zsyscall_windows.go

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/os/os_windows_test.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1868,10 +1868,26 @@ func TestFileOverlappedSeek(t *testing.T) {
18681868
if n != int64(len(buf)) {
18691869
t.Errorf("expected file pointer to be at offset %d, got %d", len(buf), n)
18701870
}
1871+
if n, err = f.Seek(1, io.SeekStart); err != nil {
1872+
t.Fatal(err)
1873+
} else if n != 1 {
1874+
t.Errorf("expected file pointer to be at offset %d, got %d", 1, n)
1875+
}
1876+
if n, err = f.Seek(-1, io.SeekEnd); err != nil {
1877+
t.Fatal(err)
1878+
} else if n != int64(len(content)-1) {
1879+
t.Errorf("expected file pointer to be at offset %d, got %d", len(content)-1, n)
1880+
}
1881+
if _, err := f.Seek(-1, io.SeekStart); !errors.Is(err, windows.ERROR_NEGATIVE_SEEK) {
1882+
t.Errorf("expected ERROR_NEGATIVE_SEEK, got %v", err)
1883+
}
1884+
if _, err := f.Seek(0, -1); !errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
1885+
t.Errorf("expected ERROR_INVALID_PARAMETER, got %v", err)
1886+
}
18711887
}
18721888

1873-
func TestFileOverlappedReadAtVolume(t *testing.T) {
1874-
// Test that we can use File.ReadAt with an overlapped volume handle.
1889+
func TestFileOverlappedReadAtSeekVolume(t *testing.T) {
1890+
// Test that we can use File.ReadAt and File.Seek with an overlapped volume handle.
18751891
// See https://go.dev/issues/74951.
18761892
t.Parallel()
18771893
name := `\\.\` + filepath.VolumeName(t.TempDir())
@@ -1888,6 +1904,9 @@ func TestFileOverlappedReadAtVolume(t *testing.T) {
18881904
if _, err := f.ReadAt(buf[:], 0); err != nil {
18891905
t.Fatal(err)
18901906
}
1907+
if _, err := f.Seek(0, io.SeekCurrent); err != nil {
1908+
t.Fatal(err)
1909+
}
18911910
}
18921911

18931912
func TestPipe(t *testing.T) {

0 commit comments

Comments
 (0)