Skip to content

Commit 396d289

Browse files
dgryskidkegel-fastly
authored andcommitted
src/{syscall, os}: add File.Stat, with smoke test
This is File.Stat from tinygo-org#2371, plus the windows bits, plus a smoke test more or less from upstream, all pulled together and rebased by dkegel-fastly.
1 parent 2c7ea98 commit 396d289

File tree

7 files changed

+108
-5
lines changed

7 files changed

+108
-5
lines changed

src/os/file.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,6 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
193193
return f.handle.Seek(offset, whence)
194194
}
195195

196-
// Stat is a stub, not yet implemented
197-
func (f *File) Stat() (FileInfo, error) {
198-
return nil, &PathError{"stat", f.name, ErrNotImplemented}
199-
}
200-
201196
func (f *File) SyscallConn() (syscall.RawConn, error) {
202197
return nil, ErrNotImplemented
203198
}

src/os/os_anyos_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"path/filepath"
99
"runtime"
1010
"strconv"
11+
"strings"
1112
"testing"
1213
"time"
1314
)
@@ -48,6 +49,40 @@ func TestStatBadDir(t *testing.T) {
4849
}
4950
}
5051

52+
func equal(name1, name2 string) (r bool) {
53+
switch runtime.GOOS {
54+
case "windows":
55+
r = strings.ToLower(name1) == strings.ToLower(name2)
56+
default:
57+
r = name1 == name2
58+
}
59+
return
60+
}
61+
62+
func TestFstat(t *testing.T) {
63+
sfname := "TestFstat"
64+
path := TempDir() + "/" + sfname
65+
payload := writeFile(t, path, O_CREATE|O_TRUNC|O_RDWR, "Hello")
66+
defer Remove(path)
67+
68+
file, err1 := Open(path)
69+
if err1 != nil {
70+
t.Fatal("open failed:", err1)
71+
}
72+
defer file.Close()
73+
dir, err2 := file.Stat()
74+
if err2 != nil {
75+
t.Fatal("fstat failed:", err2)
76+
}
77+
if !equal(sfname, dir.Name()) {
78+
t.Error("name should be ", sfname, "; is", dir.Name())
79+
}
80+
filesize := len(payload)
81+
if dir.Size() != int64(filesize) {
82+
t.Error("size should be", filesize, "; is", dir.Size())
83+
}
84+
}
85+
5186
func writeFile(t *testing.T, fname string, flag int, text string) string {
5287
f, err := OpenFile(fname, flag, 0666)
5388
if err != nil {

src/os/stat_other.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ func (f *File) Sync() error {
1111
return ErrNotImplemented
1212
}
1313

14+
// Stat is a stub, not yet implemented
15+
func (f *File) Stat() (FileInfo, error) {
16+
return nil, ErrNotImplemented
17+
}
18+
1419
// statNolog stats a file with no test logging.
1520
func statNolog(name string) (FileInfo, error) {
1621
return nil, &PathError{Op: "stat", Path: name, Err: ErrNotImplemented}

src/os/stat_unix.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ func (f *File) Sync() error {
1515
return ErrNotImplemented
1616
}
1717

18+
// Stat returns the FileInfo structure describing file.
19+
// If there is an error, it will be of type *PathError.
20+
func (f *File) Stat() (FileInfo, error) {
21+
var fs fileStat
22+
err := ignoringEINTR(func() error {
23+
return syscall.Fstat(int(f.handle.(unixFileHandle)), &fs.sys)
24+
})
25+
if err != nil {
26+
return nil, &PathError{Op: "fstat", Path: f.name, Err: err}
27+
}
28+
fillFileStatFromSys(&fs, f.name)
29+
return &fs, nil
30+
}
31+
1832
// statNolog stats a file with no test logging.
1933
func statNolog(name string) (FileInfo, error) {
2034
var fs fileStat

src/os/stat_windows.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,34 @@ func (f *File) Sync() error {
1515
return ErrNotImplemented
1616
}
1717

18+
// Stat returns the FileInfo structure describing file.
19+
// If there is an error, it will be of type *PathError.
20+
func (file *File) Stat() (FileInfo, error) {
21+
if file == nil {
22+
return nil, ErrInvalid
23+
}
24+
25+
if isWindowsNulName(file.name) {
26+
return &devNullStat, nil
27+
}
28+
29+
ft, err := syscall.GetFileType(syscallFd(file.handle.(unixFileHandle)))
30+
if err != nil {
31+
return nil, &PathError{Op: "GetFileType", Path: file.name, Err: err}
32+
}
33+
switch ft {
34+
case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR:
35+
return &fileStat{name: basename(file.name), filetype: ft}, nil
36+
}
37+
38+
fs, err := newFileStatFromGetFileInformationByHandle(file.name, syscallFd(file.handle.(unixFileHandle)))
39+
if err != nil {
40+
return nil, err
41+
}
42+
fs.filetype = ft
43+
return fs, err
44+
}
45+
1846
// stat implements both Stat and Lstat of a file.
1947
func stat(funcname, name string, createFileAttrs uint32) (FileInfo, error) {
2048
if len(name) == 0 {

src/syscall/syscall_libc_darwin.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,15 @@ func Stat(path string, p *Stat_t) (err error) {
172172
return
173173
}
174174

175+
func Fstat(fd int, p *Stat_t) (err error) {
176+
n := libc_fstat(int32(fd), unsafe.Pointer(p))
177+
178+
if n < 0 {
179+
err = getErrno()
180+
}
181+
return
182+
}
183+
175184
func Lstat(path string, p *Stat_t) (err error) {
176185
data := cstring(path)
177186
n := libc_lstat(&data[0], unsafe.Pointer(p))
@@ -188,6 +197,10 @@ func Lstat(path string, p *Stat_t) (err error) {
188197
//export stat$INODE64
189198
func libc_stat(pathname *byte, ptr unsafe.Pointer) int32
190199

200+
// int fstat(int fd, struct stat * buf);
201+
//export fstat$INODE64
202+
func libc_fstat(fd int32, ptr unsafe.Pointer) int32
203+
191204
// int lstat(const char *path, struct stat * buf);
192205
//export lstat$INODE64
193206
func libc_lstat(pathname *byte, ptr unsafe.Pointer) int32

src/syscall/syscall_libc_wasi.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,15 @@ func Stat(path string, p *Stat_t) (err error) {
212212
return
213213
}
214214

215+
func Fstat(fd int, p *Stat_t) (err error) {
216+
n := libc_fstat(int32(fd), unsafe.Pointer(p))
217+
218+
if n < 0 {
219+
err = getErrno()
220+
}
221+
return
222+
}
223+
215224
func Lstat(path string, p *Stat_t) (err error) {
216225
data := cstring(path)
217226
n := libc_lstat(&data[0], unsafe.Pointer(p))
@@ -225,6 +234,10 @@ func Lstat(path string, p *Stat_t) (err error) {
225234
//export stat
226235
func libc_stat(pathname *byte, ptr unsafe.Pointer) int32
227236

237+
// int fstat(fd int, struct stat * buf);
238+
//export fstat
239+
func libc_fstat(fd int32, ptr unsafe.Pointer) int32
240+
228241
// int lstat(const char *path, struct stat * buf);
229242
//export lstat
230243
func libc_lstat(pathname *byte, ptr unsafe.Pointer) int32

0 commit comments

Comments
 (0)