os: implement file.Seek, add smoke test
Этот коммит содержится в:
родитель
84279ab2ec
коммит
998f01608c
7 изменённых файлов: 91 добавлений и 5 удалений
|
@ -176,9 +176,17 @@ func (f *File) Readdirnames(n int) (names []string, err error) {
|
|||
return nil, &PathError{"readdirnames", f.name, ErrNotImplemented}
|
||||
}
|
||||
|
||||
// Seek is a stub, not yet implemented
|
||||
// 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.
|
||||
// It returns the new offset and an error, if any.
|
||||
// The behavior of Seek on a file opened with O_APPEND is not specified.
|
||||
//
|
||||
// If f is a directory, the behavior of Seek varies by operating
|
||||
// system; you can seek to the beginning of the directory on Unix-like
|
||||
// operating systems, but not on Windows.
|
||||
func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
|
||||
return 0, &PathError{"seek", f.name, ErrNotImplemented}
|
||||
return f.handle.Seek(offset, whence)
|
||||
}
|
||||
|
||||
// Stat is a stub, not yet implemented
|
||||
|
|
|
@ -50,6 +50,11 @@ func (f stdioFileHandle) Close() error {
|
|||
return ErrUnsupported
|
||||
}
|
||||
|
||||
// Seek wraps syscall.Seek.
|
||||
func (f stdioFileHandle) Seek(offset int64, whence int) (int64, error) {
|
||||
return -1, ErrUnsupported
|
||||
}
|
||||
|
||||
//go:linkname putchar runtime.putchar
|
||||
func putchar(c byte)
|
||||
|
||||
|
|
|
@ -64,3 +64,9 @@ func (f unixFileHandle) ReadAt(b []byte, offset int64) (n int, err error) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Seek wraps syscall.Seek.
|
||||
func (f unixFileHandle) Seek(offset int64, whence int) (int64, error) {
|
||||
newoffset, err := syscall.Seek(syscallFd(f), offset, whence)
|
||||
return newoffset, handleSyscallError(err)
|
||||
}
|
||||
|
|
|
@ -66,6 +66,12 @@ func (f unixFileHandle) ReadAt(b []byte, offset int64) (n int, err error) {
|
|||
return -1, ErrNotImplemented
|
||||
}
|
||||
|
||||
// Seek wraps syscall.Seek.
|
||||
func (f unixFileHandle) Seek(offset int64, whence int) (int64, error) {
|
||||
newoffset, err := syscall.Seek(syscallFd(f), offset, whence)
|
||||
return newoffset, handleSyscallError(err)
|
||||
}
|
||||
|
||||
// isWindowsNulName reports whether name is os.DevNull ('NUL') on Windows.
|
||||
// True is returned if name is 'NUL' whatever the case.
|
||||
func isWindowsNulName(name string) bool {
|
||||
|
|
|
@ -49,6 +49,9 @@ type FileHandle interface {
|
|||
// 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)
|
||||
|
||||
// Seek resets the file pointer relative to start, current position, or end
|
||||
Seek(offset int64, whence int) (newoffset int64, err error)
|
||||
|
||||
// Write writes up to len(b) bytes to the file.
|
||||
Write(b []byte) (n int, err error)
|
||||
|
||||
|
|
|
@ -6,9 +6,11 @@ package os_test
|
|||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
. "os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -20,7 +22,7 @@ func localTmp() string {
|
|||
func newFile(testName string, t *testing.T) (f *File) {
|
||||
f, err := CreateTemp("", testName)
|
||||
if err != nil {
|
||||
t.Fatalf("TempFile %s: %s", testName, err)
|
||||
t.Fatalf("newFile %s: CreateTemp fails with %s", testName, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -86,6 +88,54 @@ func checkMode(t *testing.T, path string, mode FileMode) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSeek(t *testing.T) {
|
||||
f := newFile("TestSeek", t)
|
||||
if f == nil {
|
||||
t.Fatalf("f is nil")
|
||||
return // TODO: remove
|
||||
}
|
||||
defer Remove(f.Name())
|
||||
defer f.Close()
|
||||
|
||||
const data = "hello, world\n"
|
||||
io.WriteString(f, data)
|
||||
|
||||
type test struct {
|
||||
in int64
|
||||
whence int
|
||||
out int64
|
||||
}
|
||||
var tests = []test{
|
||||
{0, io.SeekCurrent, int64(len(data))},
|
||||
{0, io.SeekStart, 0},
|
||||
{5, io.SeekStart, 5},
|
||||
{0, io.SeekEnd, int64(len(data))},
|
||||
{0, io.SeekStart, 0},
|
||||
{-1, io.SeekEnd, int64(len(data)) - 1},
|
||||
{1 << 33, io.SeekStart, 1 << 33},
|
||||
{1 << 33, io.SeekEnd, 1<<33 + int64(len(data))},
|
||||
|
||||
// Issue 21681, Windows 4G-1, etc:
|
||||
{1<<32 - 1, io.SeekStart, 1<<32 - 1},
|
||||
{0, io.SeekCurrent, 1<<32 - 1},
|
||||
{2<<32 - 1, io.SeekStart, 2<<32 - 1},
|
||||
{0, io.SeekCurrent, 2<<32 - 1},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
off, err := f.Seek(tt.in, tt.whence)
|
||||
if off != tt.out || err != nil {
|
||||
if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 && runtime.GOOS == "linux" {
|
||||
mounts, _ := ioutil.ReadFile("/proc/mounts")
|
||||
if strings.Contains(string(mounts), "reiserfs") {
|
||||
// Reiserfs rejects the big seeks.
|
||||
t.Skipf("skipping test known to fail on reiserfs; https://golang.org/issue/91")
|
||||
}
|
||||
}
|
||||
t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadAt(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Log("TODO: implement Pread for Windows")
|
||||
|
|
|
@ -46,8 +46,12 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func Seek(fd int, offset int64, whence int) (off int64, err error) {
|
||||
return 0, ENOSYS // TODO
|
||||
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
|
||||
newoffset = libc_lseek(int32(fd), offset, whence)
|
||||
if newoffset < 0 {
|
||||
err = getErrno()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Open(path string, flag int, mode uint32) (fd int, err error) {
|
||||
|
@ -248,6 +252,10 @@ func libc_read(fd int32, buf *byte, count uint) int
|
|||
//export pread
|
||||
func libc_pread(fd int32, buf *byte, count uint, offset int64) int
|
||||
|
||||
// ssize_t lseek(int fd, off_t offset, int whence);
|
||||
//export lseek
|
||||
func libc_lseek(fd int32, offset int64, whence int) int64
|
||||
|
||||
// int open(const char *pathname, int flags, mode_t mode);
|
||||
//export open
|
||||
func libc_open(pathname *byte, flags int32, mode uint32) int32
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче