syscall: make Seek use SetFilePointerEx on Windows, allowing large seek offsets

Fixes #21681
Updates #21728

Change-Id: I79cf4564c1355ecab891102d4215cbbffd8eb0ce
Reviewed-on: https://go-review.googlesource.com/82535
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Brad Fitzpatrick 2017-12-06 18:20:26 +00:00
parent 9ce6b5c2ed
commit 7c46b62d0a
2 changed files with 39 additions and 11 deletions

View file

@ -332,6 +332,27 @@ func Write(fd Handle, p []byte) (n int, err error) {
var ioSync int64
var procSetFilePointerEx = modkernel32.NewProc("SetFilePointerEx")
const ptrSize = unsafe.Sizeof(uintptr(0))
// setFilePointerEx calls SetFilePointerEx.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365542(v=vs.85).aspx
func setFilePointerEx(handle Handle, distToMove int64, newFilePointer *int64, whence uint32) error {
var e1 Errno
if ptrSize == 8 {
_, _, e1 = Syscall6(procSetFilePointerEx.Addr(), 4, uintptr(handle), uintptr(distToMove), uintptr(unsafe.Pointer(newFilePointer)), uintptr(whence), 0, 0)
} else {
// distToMove is a LARGE_INTEGER:
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa383713(v=vs.85).aspx
_, _, e1 = Syscall6(procSetFilePointerEx.Addr(), 5, uintptr(handle), uintptr(distToMove), uintptr(distToMove>>32), uintptr(unsafe.Pointer(newFilePointer)), uintptr(whence), 0)
}
if e1 != 0 {
return errnoErr(e1)
}
return nil
}
func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) {
var w uint32
switch whence {
@ -342,18 +363,13 @@ func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) {
case 2:
w = FILE_END
}
hi := int32(offset >> 32)
lo := int32(offset)
// use GetFileType to check pipe, pipe can't do seek
ft, _ := GetFileType(fd)
if ft == FILE_TYPE_PIPE {
return 0, ESPIPE
}
rlo, e := SetFilePointer(fd, lo, &hi, w)
if e != nil {
return 0, e
}
return int64(hi)<<32 + int64(rlo), nil
err = setFilePointerEx(fd, offset, &newoffset, w)
return
}
func Close(fd Handle) (err error) {