}
defer fd.readWriteUnlock()
- 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
+ if !fd.isBlocking {
+ // Windows doesn't use the file pointer for overlapped file handles,
+ // there is no point on calling syscall.Seek.
+ var newOffset int64
+ switch whence {
+ case io.SeekStart:
+ newOffset = offset
+ case io.SeekCurrent:
+ newOffset = fd.offset + offset
+ case io.SeekEnd:
+ var size int64
+ if err := windows.GetFileSizeEx(fd.Sysfd, &size); err != nil {
+ return 0, err
+ }
+ newOffset = size + offset
+ default:
+ return 0, windows.ERROR_INVALID_PARAMETER
+ }
+ if newOffset < 0 {
+ return 0, windows.ERROR_NEGATIVE_SEEK
+ }
+ fd.setOffset(newOffset)
+ return newOffset, nil
}
n, err := syscall.Seek(fd.Sysfd, offset, whence)
fd.setOffset(n)
ERROR_NOT_SUPPORTED syscall.Errno = 50
ERROR_CALL_NOT_IMPLEMENTED syscall.Errno = 120
ERROR_INVALID_NAME syscall.Errno = 123
+ ERROR_NEGATIVE_SEEK syscall.Errno = 131
ERROR_LOCK_FAILED syscall.Errno = 167
ERROR_IO_INCOMPLETE syscall.Errno = 996
ERROR_NO_TOKEN syscall.Errno = 1008
//sys SetFileInformationByHandle(handle syscall.Handle, fileInformationClass uint32, buf unsafe.Pointer, bufsize uint32) (err error) = kernel32.SetFileInformationByHandle
//sys VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) = kernel32.VirtualQuery
//sys GetTempPath2(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPath2W
+//sys GetFileSizeEx(handle syscall.Handle, size *int64) (err error) = kernel32.GetFileSizeEx
const (
// flags for CreateToolhelp32Snapshot
procGetConsoleCP = modkernel32.NewProc("GetConsoleCP")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
+ procGetFileSizeEx = modkernel32.NewProc("GetFileSizeEx")
procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW")
procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW")
procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW")
return
}
+func GetFileSizeEx(handle syscall.Handle, size *int64) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetFileSizeEx.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(size)), 0)
+ if r1 == 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) {
r0, _, e1 := syscall.SyscallN(procGetFinalPathNameByHandleW.Addr(), uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags))
n = uint32(r0)
if n != int64(len(buf)) {
t.Errorf("expected file pointer to be at offset %d, got %d", len(buf), n)
}
+ if n, err = f.Seek(1, io.SeekStart); err != nil {
+ t.Fatal(err)
+ } else if n != 1 {
+ t.Errorf("expected file pointer to be at offset %d, got %d", 1, n)
+ }
+ if n, err = f.Seek(-1, io.SeekEnd); err != nil {
+ t.Fatal(err)
+ } else if n != int64(len(content)-1) {
+ t.Errorf("expected file pointer to be at offset %d, got %d", len(content)-1, n)
+ }
+ if _, err := f.Seek(-1, io.SeekStart); !errors.Is(err, windows.ERROR_NEGATIVE_SEEK) {
+ t.Errorf("expected ERROR_NEGATIVE_SEEK, got %v", err)
+ }
+ if _, err := f.Seek(0, -1); !errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
+ t.Errorf("expected ERROR_INVALID_PARAMETER, got %v", err)
+ }
}
-func TestFileOverlappedReadAtVolume(t *testing.T) {
- // Test that we can use File.ReadAt with an overlapped volume handle.
+func TestFileOverlappedReadAtSeekVolume(t *testing.T) {
+ // Test that we can use File.ReadAt and File.Seek with an overlapped volume handle.
// See https://go.dev/issues/74951.
t.Parallel()
name := `\\.\` + filepath.VolumeName(t.TempDir())
if _, err := f.ReadAt(buf[:], 0); err != nil {
t.Fatal(err)
}
+ if _, err := f.Seek(0, io.SeekCurrent); err != nil {
+ t.Fatal(err)
+ }
}
func TestPipe(t *testing.T) {