// 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
}
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
}
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.
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");
+ }
+}