Commit 8409dea8 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

os: cap reads and writes to 2GB on Darwin and FreeBSD

Fixes #7812

LGTM=josharian, iant
R=rsc, iant, adg, ruiu, minux.ma, josharian
CC=golang-codereviews
https://golang.org/cl/89900044
parent 7faf72bd
...@@ -172,16 +172,29 @@ func (f *File) readdir(n int) (fi []FileInfo, err error) { ...@@ -172,16 +172,29 @@ func (f *File) readdir(n int) (fi []FileInfo, err error) {
return fi, err return fi, err
} }
// Darwin and FreeBSD can't read or write 2GB+ at a time,
// even on 64-bit systems. See golang.org/issue/7812.
const (
needsMaxRW = runtime.GOOS == "darwin" || runtime.GOOS == "freebsd"
maxRW = 2<<30 - 1
)
// read reads up to len(b) bytes from the File. // read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any. // It returns the number of bytes read and an error, if any.
func (f *File) read(b []byte) (n int, err error) { func (f *File) read(b []byte) (n int, err error) {
if needsMaxRW && len(b) > maxRW {
b = b[:maxRW]
}
return syscall.Read(f.fd, b) return syscall.Read(f.fd, b)
} }
// pread reads len(b) bytes from the File starting at byte offset off. // pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any. // It returns the number of bytes read and the error, if any.
// EOF is signaled by a zero count with err set to 0. // EOF is signaled by a zero count with err set to nil.
func (f *File) pread(b []byte, off int64) (n int, err error) { func (f *File) pread(b []byte, off int64) (n int, err error) {
if needsMaxRW && len(b) > maxRW {
b = b[:maxRW]
}
return syscall.Pread(f.fd, b, off) return syscall.Pread(f.fd, b, off)
} }
...@@ -189,13 +202,22 @@ func (f *File) pread(b []byte, off int64) (n int, err error) { ...@@ -189,13 +202,22 @@ func (f *File) pread(b []byte, off int64) (n int, err error) {
// It returns the number of bytes written and an error, if any. // It returns the number of bytes written and an error, if any.
func (f *File) write(b []byte) (n int, err error) { func (f *File) write(b []byte) (n int, err error) {
for { for {
m, err := syscall.Write(f.fd, b) bcap := b
if needsMaxRW && len(bcap) > maxRW {
bcap = bcap[:maxRW]
}
m, err := syscall.Write(f.fd, bcap)
n += m n += m
// If the syscall wrote some data but not all (short write) // If the syscall wrote some data but not all (short write)
// or it returned EINTR, then assume it stopped early for // or it returned EINTR, then assume it stopped early for
// reasons that are uninteresting to the caller, and try again. // reasons that are uninteresting to the caller, and try again.
if 0 < m && m < len(b) || err == syscall.EINTR { if 0 < m && m < len(bcap) || err == syscall.EINTR {
b = b[m:]
continue
}
if needsMaxRW && len(bcap) != len(b) && err == nil {
b = b[m:] b = b[m:]
continue continue
} }
...@@ -207,6 +229,9 @@ func (f *File) write(b []byte) (n int, err error) { ...@@ -207,6 +229,9 @@ func (f *File) write(b []byte) (n int, err error) {
// pwrite writes len(b) bytes to the File starting at byte offset off. // pwrite writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any. // It returns the number of bytes written and an error, if any.
func (f *File) pwrite(b []byte, off int64) (n int, err error) { func (f *File) pwrite(b []byte, off int64) (n int, err error) {
if needsMaxRW && len(b) > maxRW {
b = b[:maxRW]
}
return syscall.Pwrite(f.fd, b, off) return syscall.Pwrite(f.fd, b, off)
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment