Browse Source

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.
pull/2558/head
Damian Gryski 3 years ago
committed by Ron Evans
parent
commit
322abf6d22
  1. 5
      src/os/file.go
  2. 35
      src/os/os_anyos_test.go
  3. 5
      src/os/stat_other.go
  4. 14
      src/os/stat_unix.go
  5. 28
      src/os/stat_windows.go
  6. 13
      src/syscall/syscall_libc_darwin.go
  7. 13
      src/syscall/syscall_libc_wasi.go

5
src/os/file.go

@ -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
}

35
src/os/os_anyos_test.go

@ -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 {

5
src/os/stat_other.go

@ -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}

14
src/os/stat_unix.go

@ -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

28
src/os/stat_windows.go

@ -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 {

13
src/syscall/syscall_libc_darwin.go

@ -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

13
src/syscall/syscall_libc_wasi.go

@ -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

Loading…
Cancel
Save