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 | ||||
|  |  | |||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 Dan Kegel
						Dan Kegel