os, syscall: implement ReadAt for unix

Windows will take more work, so test is skipped there.
This commit is contained in:
Dan Kegel
2021-11-20 11:43:52 -08:00
committed by Ron Evans
parent 47db50b273
commit f79f6b0e62
7 changed files with 102 additions and 3 deletions
+9 -2
View File
@@ -107,8 +107,15 @@ func (f *File) Read(b []byte) (n int, err error) {
return
}
func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
return 0, ErrNotImplemented
// 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}
}
return
}
// Write writes len(b) bytes to the File. It returns the number of bytes written
+4
View File
@@ -27,6 +27,10 @@ func (f stdioFileHandle) Read(b []byte) (n int, err error) {
return 0, ErrUnsupported
}
func (f stdioFileHandle) ReadAt(b []byte, off int64) (n int, err error) {
return 0, ErrNotImplemented
}
// Write writes len(b) bytes to the output. It returns the number of bytes
// written or an error if this file is not stdout or stderr.
func (f stdioFileHandle) Write(b []byte) (n int, err error) {
+17 -1
View File
@@ -2,7 +2,10 @@
package os
import "syscall"
import (
"io"
"syscall"
)
type syscallFd = int
@@ -22,3 +25,16 @@ func Pipe() (r *File, w *File, err error) {
}
return
}
// ReadAt reads up to len(b) bytes from the File starting at the given absolute offset.
// It returns the number of bytes read and any error encountered, possibly io.EOF.
// At end of file, Pread returns 0, io.EOF.
// TODO: move to file_anyos once ReadAt is implemented for windows
func (f unixFileHandle) ReadAt(b []byte, offset int64) (n int, err error) {
n, err = syscall.Pread(syscallFd(f), b, offset)
err = handleSyscallError(err)
if n == 0 && err == nil {
err = io.EOF
}
return
}
+8
View File
@@ -22,3 +22,11 @@ func Pipe() (r *File, w *File, err error) {
}
return
}
// ReadAt reads up to len(b) bytes from the File starting at the given absolute offset.
// It returns the number of bytes read and any error encountered, possibly io.EOF.
// At end of file, Pread returns 0, io.EOF.
// TODO: move to file_anyos once ReadAt is implemented for windows
func (f unixFileHandle) ReadAt(b []byte, offset int64) (n int, err error) {
return -1, ErrNotImplemented
}
+3
View File
@@ -46,6 +46,9 @@ type FileHandle interface {
// Read reads up to len(b) bytes from the file.
Read(b []byte) (n int, err error)
// ReadAt reads up to len(b) bytes from the file starting at the given absolute offset
ReadAt(b []byte, offset int64) (n int, err error)
// Write writes up to len(b) bytes to the file.
Write(b []byte) (n int, err error)
+48
View File
@@ -0,0 +1,48 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os_test
import (
"io"
. "os"
"runtime"
"testing"
)
// localTmp returns a local temporary directory not on NFS.
func localTmp() string {
return TempDir()
}
func newFile(testName string, t *testing.T) (f *File) {
// TODO: use CreateTemp when it lands
f, err := OpenFile(TempDir()+"/_Go_"+testName, O_RDWR|O_CREATE, 0644)
if err != nil {
t.Fatalf("TempFile %s: %s", testName, err)
}
return
}
func TestReadAt(t *testing.T) {
if runtime.GOOS == "windows" {
t.Log("TODO: implement Pread for Windows")
return
}
f := newFile("TestReadAt", t)
defer Remove(f.Name())
defer f.Close()
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, %v", n, err)
}
if string(b) != "world" {
t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
}
}