o.bufs = o.bufs[:0]
}
for _, b := range *buf {
- var p *byte
+ if len(b) == 0 {
+ o.bufs = append(o.bufs, syscall.WSABuf{})
+ continue
+ }
+ for len(b) > maxRW {
+ o.bufs = append(o.bufs, syscall.WSABuf{Len: maxRW, Buf: &b[0]})
+ b = b[maxRW:]
+ }
if len(b) > 0 {
- p = &b[0]
+ o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: &b[0]})
}
- o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: p})
}
}
return syscall.Shutdown(fd.Sysfd, how)
}
+// Windows ReadFile and WSARecv use DWORD (uint32) parameter to pass buffer length.
+// This prevents us reading blocks larger than 4GB.
+// See golang.org/issue/26923.
+const maxRW = 1 << 30 // 1GB is large enough and keeps subsequent reads aligned
+
// Read implements io.Reader.
func (fd *FD) Read(buf []byte) (int, error) {
if err := fd.readLock(); err != nil {
}
defer fd.readUnlock()
+ if len(buf) > maxRW {
+ buf = buf[:maxRW]
+ }
+
var n int
var err error
if fd.isFile || fd.isDir || fd.isConsole {
}
defer fd.decref()
+ if len(b) > maxRW {
+ b = b[:maxRW]
+ }
+
fd.l.Lock()
defer fd.l.Unlock()
curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
if len(buf) == 0 {
return 0, nil, nil
}
+ if len(buf) > maxRW {
+ buf = buf[:maxRW]
+ }
if err := fd.readLock(); err != nil {
return 0, nil, err
}
}
defer fd.writeUnlock()
- var n int
- var err error
- if fd.isFile || fd.isDir || fd.isConsole {
- fd.l.Lock()
- defer fd.l.Unlock()
- if fd.isConsole {
- n, err = fd.writeConsole(buf)
+ ntotal := 0
+ for len(buf) > 0 {
+ b := buf
+ if len(b) > maxRW {
+ b = b[:maxRW]
+ }
+ var n int
+ var err error
+ if fd.isFile || fd.isDir || fd.isConsole {
+ fd.l.Lock()
+ defer fd.l.Unlock()
+ if fd.isConsole {
+ n, err = fd.writeConsole(b)
+ } else {
+ n, err = syscall.Write(fd.Sysfd, b)
+ }
+ if err != nil {
+ n = 0
+ }
} else {
- n, err = syscall.Write(fd.Sysfd, buf)
+ if race.Enabled {
+ race.ReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ o := &fd.wop
+ o.InitBuf(b)
+ n, err = wsrv.ExecIO(o, func(o *operation) error {
+ return syscall.WSASend(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
+ })
}
+ ntotal += n
if err != nil {
- n = 0
+ return ntotal, err
}
- } else {
- if race.Enabled {
- race.ReleaseMerge(unsafe.Pointer(&ioSync))
- }
- o := &fd.wop
- o.InitBuf(buf)
- n, err = wsrv.ExecIO(o, func(o *operation) error {
- return syscall.WSASend(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
- })
+ buf = buf[n:]
}
- return n, err
+ return ntotal, nil
}
// writeConsole writes len(b) bytes to the console File.
}
// Pwrite emulates the Unix pwrite system call.
-func (fd *FD) Pwrite(b []byte, off int64) (int, error) {
+func (fd *FD) Pwrite(buf []byte, off int64) (int, error) {
// Call incref, not writeLock, because since pwrite specifies the
// offset it is independent from other writes.
if err := fd.incref(); err != nil {
return 0, e
}
defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
- o := syscall.Overlapped{
- OffsetHigh: uint32(off >> 32),
- Offset: uint32(off),
- }
- var done uint32
- e = syscall.WriteFile(fd.Sysfd, b, &done, &o)
- if e != nil {
- return 0, e
+
+ ntotal := 0
+ for len(buf) > 0 {
+ b := buf
+ if len(b) > maxRW {
+ b = b[:maxRW]
+ }
+ var n uint32
+ o := syscall.Overlapped{
+ OffsetHigh: uint32(off >> 32),
+ Offset: uint32(off),
+ }
+ e = syscall.WriteFile(fd.Sysfd, b, &n, &o)
+ ntotal += int(n)
+ if e != nil {
+ return ntotal, e
+ }
+ buf = buf[n:]
+ off += int64(n)
}
- return int(done), nil
+ return ntotal, nil
}
// Writev emulates the Unix writev system call.
return 0, err
}
defer fd.writeUnlock()
- o := &fd.wop
- o.InitBuf(buf)
- o.sa = sa
- n, err := wsrv.ExecIO(o, func(o *operation) error {
- return syscall.WSASendto(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
- })
- return n, err
+
+ ntotal := 0
+ for len(buf) > 0 {
+ b := buf
+ if len(b) > maxRW {
+ b = b[:maxRW]
+ }
+ o := &fd.wop
+ o.InitBuf(b)
+ o.sa = sa
+ n, err := wsrv.ExecIO(o, func(o *operation) error {
+ return syscall.WSASendto(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
+ })
+ ntotal += int(n)
+ if err != nil {
+ return ntotal, err
+ }
+ buf = buf[n:]
+ }
+ return ntotal, nil
}
// Call ConnectEx. This doesn't need any locking, since it is only
}
defer fd.readUnlock()
+ if len(p) > maxRW {
+ p = p[:maxRW]
+ }
+
o := &fd.rop
o.InitMsg(p, oob)
o.rsa = new(syscall.RawSockaddrAny)
// WriteMsg wraps the WSASendMsg network call.
func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, error) {
+ if len(p) > maxRW {
+ return 0, 0, errors.New("packet is too large (only 1GB is allowed)")
+ }
+
if err := fd.writeLock(); err != nil {
return 0, 0, err
}