From f7e92c596c17a2ba3e473a63c479b8f9338046dd Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 27 Aug 2009 18:36:45 -0700 Subject: [PATCH] os.File.ReadAt/WriteAt R=r DELTA=84 (81 added, 0 deleted, 3 changed) OCL=34006 CL=34006 --- src/pkg/os/file.go | 47 ++++++++++++++++++++++++++++++++++++++++--- src/pkg/os/os_test.go | 40 ++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/src/pkg/os/file.go b/src/pkg/os/file.go index 958a8230c6..c9c00788ff 100644 --- a/src/pkg/os/file.go +++ b/src/pkg/os/file.go @@ -115,7 +115,7 @@ var EOF Error = eofError(0) // It returns the number of bytes read and an Error, if any. // EOF is signaled by a zero count with err set to EOF. // TODO(r): Add Pread, Pwrite (maybe ReadAt, WriteAt). -func (file *File) Read(b []byte) (ret int, err Error) { +func (file *File) Read(b []byte) (n int, err Error) { if file == nil { return 0, EINVAL } @@ -132,10 +132,31 @@ func (file *File) Read(b []byte) (ret int, err Error) { return n, err } +// ReadAt reads len(b) bytes from the File starting at byte offset off. +// It returns the number of bytes read and the Error, if any. +// EOF is signaled by a zero count with err set to EOF. +// ReadAt always returns a non-nil Error when n != len(b). +func (file *File) ReadAt(b []byte, off int64) (n int, err Error) { + if file == nil { + return 0, EINVAL; + } + for len(b) > 0 { + m, e := syscall.Pread(file.fd, b, off); + n += m; + if e != 0 { + err = &PathError{"read", file.name, Errno(e)}; + break; + } + b = b[m:len(b)]; + off += int64(m); + } + return; +} + // Write writes len(b) bytes to the File. // It returns the number of bytes written and an Error, if any. -// If the byte count differs from len(b), it usually implies an error occurred. -func (file *File) Write(b []byte) (ret int, err Error) { +// Write returns a non-nil Error when n != len(b). +func (file *File) Write(b []byte) (n int, err Error) { if file == nil { return 0, EINVAL } @@ -157,6 +178,26 @@ func (file *File) Write(b []byte) (ret int, err Error) { return n, err } +// WriteAt writes len(b) bytes to the File starting at byte offset off. +// It returns the number of bytes written and an Error, if any. +// WriteAt returns a non-nil Error when n != len(b). +func (file *File) WriteAt(b []byte, off int64) (n int, err Error) { + if file == nil { + return 0, EINVAL; + } + for len(b) > 0 { + m, e := syscall.Pwrite(file.fd, b, off); + n += m; + if e != 0 { + err = &PathError{"write", file.name, Errno(e)}; + break; + } + b = b[m:len(b)]; + off += int64(m); + } + return; +} + // Seek sets the offset for the next Read or Write on file to offset, interpreted // according to whence: 0 means relative to the origin of the file, 1 means // relative to the current offset, and 2 means relative to the end. diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go index 84c4d15a01..9f7df2ac58 100644 --- a/src/pkg/os/os_test.go +++ b/src/pkg/os/os_test.go @@ -628,3 +628,43 @@ func TestHostname(t *testing.T) { t.Errorf("Hostname() = %q, want %q", hostname, want); } } + +func TestReadAt(t *testing.T) { + f, err := Open("_obj/readtest", O_CREAT|O_RDWR|O_TRUNC, 0666); + if err != nil { + t.Fatalf("open _obj/readtest: %s", err); + } + const data = "hello, world\n"; + io.WriteString(f, data); + + b := make([]byte, 5); + n, err := f.ReadAt(b, 7); + if err != nil || n != len(b) { + t.Fatalf("ReadAt 7: %d, %r", n, err); + } + if string(b) != "world" { + t.Fatalf("ReadAt 7: have %q want %q", string(b), "world"); + } +} + +func TestWriteAt(t *testing.T) { + f, err := Open("_obj/writetest", O_CREAT|O_RDWR|O_TRUNC, 0666); + if err != nil { + t.Fatalf("open _obj/writetest: %s", err); + } + const data = "hello, world\n"; + io.WriteString(f, data); + + n, err := f.WriteAt(strings.Bytes("WORLD"), 7); + if err != nil || n != 5 { + t.Fatalf("WriteAt 7: %d, %v", n, err); + } + + b, err := io.ReadFile("_obj/writetest"); + if err != nil { + t.Fatalf("ReadFile _obj/writetest: %v", err); + } + if string(b) != "hello, WORLD\n" { + t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n"); + } +} -- 2.48.1