From 1e2791b216aa79f2214a6c9e77ba0709b613ac0d Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Thu, 9 Dec 2021 18:50:17 -0800 Subject: [PATCH] src/os: loop in File.ReadAt to handle short reads This matches what upstream Go does. This also means len(b) == 0 successfully reads 0 bytes without any extra logic. The tests in archive/zip test for this behaviour. --- src/os/file.go | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/os/file.go b/src/os/file.go index e39b5094..33f204cd 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -10,6 +10,7 @@ package os import ( + "errors" "io" "syscall" ) @@ -106,14 +107,29 @@ func (f *File) Read(b []byte) (n int, err error) { return } +var errNegativeOffset = errors.New("negative offset") + // ReadAt reads up to len(b) bytes from the File at the given absolute offset. // It returns the number of bytes read and any error encountered, possible io.EOF. // At end of file, Read returns 0, io.EOF. func (f *File) ReadAt(b []byte, offset int64) (n int, err error) { - n, err = f.handle.ReadAt(b, offset) - if err != nil && err != io.EOF { - err = &PathError{"readat", f.name, err} + if offset < 0 { + return 0, &PathError{Op: "readat", Path: f.name, Err: errNegativeOffset} } + + for len(b) > 0 { + m, e := f.handle.ReadAt(b, offset) + if e != nil { + if err != io.EOF { + err = &PathError{"readat", f.name, err} + } + break + } + n += m + b = b[m:] + offset += int64(m) + } + return }