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}
|
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) {
|
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
|
// Stat is a stub, not yet implemented
|
||||||
|
|
|
@ -50,6 +50,11 @@ func (f stdioFileHandle) Close() error {
|
||||||
return ErrUnsupported
|
return ErrUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Seek wraps syscall.Seek.
|
||||||
|
func (f stdioFileHandle) Seek(offset int64, whence int) (int64, error) {
|
||||||
|
return -1, ErrUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
//go:linkname putchar runtime.putchar
|
//go:linkname putchar runtime.putchar
|
||||||
func putchar(c byte)
|
func putchar(c byte)
|
||||||
|
|
||||||
|
|
|
@ -64,3 +64,9 @@ func (f unixFileHandle) ReadAt(b []byte, offset int64) (n int, err error) {
|
||||||
}
|
}
|
||||||
return
|
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
|
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.
|
// isWindowsNulName reports whether name is os.DevNull ('NUL') on Windows.
|
||||||
// True is returned if name is 'NUL' whatever the case.
|
// True is returned if name is 'NUL' whatever the case.
|
||||||
func isWindowsNulName(name string) bool {
|
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 reads up to len(b) bytes from the file starting at the given absolute offset
|
||||||
ReadAt(b []byte, offset int64) (n int, err error)
|
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 writes up to len(b) bytes to the file.
|
||||||
Write(b []byte) (n int, err error)
|
Write(b []byte) (n int, err error)
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,11 @@ package os_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
. "os"
|
. "os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,7 +22,7 @@ func localTmp() string {
|
||||||
func newFile(testName string, t *testing.T) (f *File) {
|
func newFile(testName string, t *testing.T) (f *File) {
|
||||||
f, err := CreateTemp("", testName)
|
f, err := CreateTemp("", testName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("TempFile %s: %s", testName, err)
|
t.Fatalf("newFile %s: CreateTemp fails with %s", testName, err)
|
||||||
}
|
}
|
||||||
return
|
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) {
|
func TestReadAt(t *testing.T) {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
t.Log("TODO: implement Pread for 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func Seek(fd int, offset int64, whence int) (off int64, err error) {
|
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
|
||||||
return 0, ENOSYS // TODO
|
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) {
|
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
|
//export pread
|
||||||
func libc_pread(fd int32, buf *byte, count uint, offset int64) int
|
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);
|
// int open(const char *pathname, int flags, mode_t mode);
|
||||||
//export open
|
//export open
|
||||||
func libc_open(pathname *byte, flags int32, mode uint32) int32
|
func libc_open(pathname *byte, flags int32, mode uint32) int32
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче