src/{syscall, os}: add File.Stat, with smoke test
This is File.Stat from https://github.com/tinygo-org/tinygo/pull/2371, plus the windows bits, plus a smoke test more or less from upstream, all pulled together and rebased by dkegel-fastly.
Этот коммит содержится в:
родитель
b85cb55aab
коммит
322abf6d22
7 изменённых файлов: 108 добавлений и 5 удалений
|
@ -193,11 +193,6 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
|
|||
return f.handle.Seek(offset, whence)
|
||||
}
|
||||
|
||||
// Stat is a stub, not yet implemented
|
||||
func (f *File) Stat() (FileInfo, error) {
|
||||
return nil, &PathError{"stat", f.name, ErrNotImplemented}
|
||||
}
|
||||
|
||||
func (f *File) SyscallConn() (syscall.RawConn, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
@ -48,6 +49,40 @@ func TestStatBadDir(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func equal(name1, name2 string) (r bool) {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
r = strings.ToLower(name1) == strings.ToLower(name2)
|
||||
default:
|
||||
r = name1 == name2
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func TestFstat(t *testing.T) {
|
||||
sfname := "TestFstat"
|
||||
path := TempDir() + "/" + sfname
|
||||
payload := writeFile(t, path, O_CREATE|O_TRUNC|O_RDWR, "Hello")
|
||||
defer Remove(path)
|
||||
|
||||
file, err1 := Open(path)
|
||||
if err1 != nil {
|
||||
t.Fatal("open failed:", err1)
|
||||
}
|
||||
defer file.Close()
|
||||
dir, err2 := file.Stat()
|
||||
if err2 != nil {
|
||||
t.Fatal("fstat failed:", err2)
|
||||
}
|
||||
if !equal(sfname, dir.Name()) {
|
||||
t.Error("name should be ", sfname, "; is", dir.Name())
|
||||
}
|
||||
filesize := len(payload)
|
||||
if dir.Size() != int64(filesize) {
|
||||
t.Error("size should be", filesize, "; is", dir.Size())
|
||||
}
|
||||
}
|
||||
|
||||
func writeFile(t *testing.T, fname string, flag int, text string) string {
|
||||
f, err := OpenFile(fname, flag, 0666)
|
||||
if err != nil {
|
||||
|
|
|
@ -11,6 +11,11 @@ func (f *File) Sync() error {
|
|||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
// Stat is a stub, not yet implemented
|
||||
func (f *File) Stat() (FileInfo, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
// statNolog stats a file with no test logging.
|
||||
func statNolog(name string) (FileInfo, error) {
|
||||
return nil, &PathError{Op: "stat", Path: name, Err: ErrNotImplemented}
|
||||
|
|
|
@ -15,6 +15,20 @@ func (f *File) Sync() error {
|
|||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
// Stat returns the FileInfo structure describing file.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func (f *File) Stat() (FileInfo, error) {
|
||||
var fs fileStat
|
||||
err := ignoringEINTR(func() error {
|
||||
return syscall.Fstat(int(f.handle.(unixFileHandle)), &fs.sys)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "fstat", Path: f.name, Err: err}
|
||||
}
|
||||
fillFileStatFromSys(&fs, f.name)
|
||||
return &fs, nil
|
||||
}
|
||||
|
||||
// statNolog stats a file with no test logging.
|
||||
func statNolog(name string) (FileInfo, error) {
|
||||
var fs fileStat
|
||||
|
|
|
@ -15,6 +15,34 @@ func (f *File) Sync() error {
|
|||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
// Stat returns the FileInfo structure describing file.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func (file *File) Stat() (FileInfo, error) {
|
||||
if file == nil {
|
||||
return nil, ErrInvalid
|
||||
}
|
||||
|
||||
if isWindowsNulName(file.name) {
|
||||
return &devNullStat, nil
|
||||
}
|
||||
|
||||
ft, err := syscall.GetFileType(syscallFd(file.handle.(unixFileHandle)))
|
||||
if err != nil {
|
||||
return nil, &PathError{Op: "GetFileType", Path: file.name, Err: err}
|
||||
}
|
||||
switch ft {
|
||||
case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR:
|
||||
return &fileStat{name: basename(file.name), filetype: ft}, nil
|
||||
}
|
||||
|
||||
fs, err := newFileStatFromGetFileInformationByHandle(file.name, syscallFd(file.handle.(unixFileHandle)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fs.filetype = ft
|
||||
return fs, err
|
||||
}
|
||||
|
||||
// stat implements both Stat and Lstat of a file.
|
||||
func stat(funcname, name string, createFileAttrs uint32) (FileInfo, error) {
|
||||
if len(name) == 0 {
|
||||
|
|
|
@ -172,6 +172,15 @@ func Stat(path string, p *Stat_t) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func Fstat(fd int, p *Stat_t) (err error) {
|
||||
n := libc_fstat(int32(fd), unsafe.Pointer(p))
|
||||
|
||||
if n < 0 {
|
||||
err = getErrno()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Lstat(path string, p *Stat_t) (err error) {
|
||||
data := cstring(path)
|
||||
n := libc_lstat(&data[0], unsafe.Pointer(p))
|
||||
|
@ -188,6 +197,10 @@ func Lstat(path string, p *Stat_t) (err error) {
|
|||
//export stat$INODE64
|
||||
func libc_stat(pathname *byte, ptr unsafe.Pointer) int32
|
||||
|
||||
// int fstat(int fd, struct stat * buf);
|
||||
//export fstat$INODE64
|
||||
func libc_fstat(fd int32, ptr unsafe.Pointer) int32
|
||||
|
||||
// int lstat(const char *path, struct stat * buf);
|
||||
//export lstat$INODE64
|
||||
func libc_lstat(pathname *byte, ptr unsafe.Pointer) int32
|
||||
|
|
|
@ -212,6 +212,15 @@ func Stat(path string, p *Stat_t) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func Fstat(fd int, p *Stat_t) (err error) {
|
||||
n := libc_fstat(int32(fd), unsafe.Pointer(p))
|
||||
|
||||
if n < 0 {
|
||||
err = getErrno()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Lstat(path string, p *Stat_t) (err error) {
|
||||
data := cstring(path)
|
||||
n := libc_lstat(&data[0], unsafe.Pointer(p))
|
||||
|
@ -225,6 +234,10 @@ func Lstat(path string, p *Stat_t) (err error) {
|
|||
//export stat
|
||||
func libc_stat(pathname *byte, ptr unsafe.Pointer) int32
|
||||
|
||||
// int fstat(fd int, struct stat * buf);
|
||||
//export fstat
|
||||
func libc_fstat(fd int32, ptr unsafe.Pointer) int32
|
||||
|
||||
// int lstat(const char *path, struct stat * buf);
|
||||
//export lstat
|
||||
func libc_lstat(pathname *byte, ptr unsafe.Pointer) int32
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче