package sysfs
import (
"io"
"io/fs"
"os"
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
"github.com/tetratelabs/wazero/internal/fsapi"
"github.com/tetratelabs/wazero/sys"
)
func newOsFile(path string , flag experimentalsys .Oflag , perm fs .FileMode , f *os .File ) fsapi .File {
return &osFile {path : path , flag : flag , perm : perm , reopenDir : true , file : f , fd : f .Fd ()}
}
type osFile struct {
path string
flag experimentalsys .Oflag
perm fs .FileMode
file *os .File
fd uintptr
reopenDir bool
closed bool
cachedSt *cachedStat
}
func (f *osFile ) cachedStat () (dev uint64 , ino sys .Inode , isDir bool , errno experimentalsys .Errno ) {
if f .cachedSt == nil {
if _, errno = f .Stat (); errno != 0 {
return
}
}
return f .cachedSt .dev , f .cachedSt .ino , f .cachedSt .isDir , 0
}
func (f *osFile ) Dev () (uint64 , experimentalsys .Errno ) {
dev , _ , _ , errno := f .cachedStat ()
return dev , errno
}
func (f *osFile ) Ino () (sys .Inode , experimentalsys .Errno ) {
_ , ino , _ , errno := f .cachedStat ()
return ino , errno
}
func (f *osFile ) IsDir () (bool , experimentalsys .Errno ) {
_ , _ , isDir , errno := f .cachedStat ()
return isDir , errno
}
func (f *osFile ) IsAppend () bool {
return f .flag &experimentalsys .O_APPEND == experimentalsys .O_APPEND
}
func (f *osFile ) SetAppend (enable bool ) (errno experimentalsys .Errno ) {
if enable {
f .flag |= experimentalsys .O_APPEND
} else {
f .flag &= ^experimentalsys .O_APPEND
}
return fileError (f , f .closed , f .reopen ())
}
func (f *osFile ) reopen () (errno experimentalsys .Errno ) {
var (
isDir bool
offset int64
err error
)
isDir , errno = f .IsDir ()
if errno != 0 {
return errno
}
if !isDir {
offset , err = f .file .Seek (0 , io .SeekCurrent )
if err != nil {
return experimentalsys .UnwrapOSError (err )
}
}
flag := f .flag &^ (experimentalsys .O_CREAT | experimentalsys .O_TRUNC )
file , errno := OpenFile (f .path , flag , f .perm )
if errno != 0 {
return errno
}
errno = f .checkSameFile (file )
if errno != 0 {
return errno
}
if !isDir {
_, err = file .Seek (offset , io .SeekStart )
if err != nil {
_ = file .Close ()
return experimentalsys .UnwrapOSError (err )
}
}
_ = f .file .Close ()
f .file = file
f .fd = file .Fd ()
return 0
}
func (f *osFile ) checkSameFile (osf *os .File ) experimentalsys .Errno {
fi1 , err := f .file .Stat ()
if err != nil {
return experimentalsys .UnwrapOSError (err )
}
fi2 , err := osf .Stat ()
if err != nil {
return experimentalsys .UnwrapOSError (err )
}
if os .SameFile (fi1 , fi2 ) {
return 0
}
return experimentalsys .ENOENT
}
func (f *osFile ) IsNonblock () bool {
return isNonblock (f )
}
func (f *osFile ) SetNonblock (enable bool ) (errno experimentalsys .Errno ) {
if enable {
f .flag |= experimentalsys .O_NONBLOCK
} else {
f .flag &= ^experimentalsys .O_NONBLOCK
}
if errno = setNonblock (f .fd , enable ); errno != 0 {
return fileError (f , f .closed , errno )
}
return 0
}
func (f *osFile ) Stat () (sys .Stat_t , experimentalsys .Errno ) {
if f .closed {
return sys .Stat_t {}, experimentalsys .EBADF
}
st , errno := statFile (f .file )
switch errno {
case 0 :
f .cachedSt = &cachedStat {dev : st .Dev , ino : st .Ino , isDir : st .Mode &fs .ModeDir == fs .ModeDir }
case experimentalsys .EIO :
errno = experimentalsys .EBADF
}
return st , errno
}
func (f *osFile ) Read (buf []byte ) (n int , errno experimentalsys .Errno ) {
if len (buf ) == 0 {
return 0 , 0
}
if nonBlockingFileReadSupported && f .IsNonblock () {
n , errno = readFd (f .fd , buf )
} else {
n , errno = read (f .file , buf )
}
if errno != 0 {
errno = fileError (f , f .closed , errno )
}
return
}
func (f *osFile ) Pread (buf []byte , off int64 ) (n int , errno experimentalsys .Errno ) {
if n , errno = pread (f .file , buf , off ); errno != 0 {
errno = fileError (f , f .closed , errno )
}
return
}
func (f *osFile ) Seek (offset int64 , whence int ) (newOffset int64 , errno experimentalsys .Errno ) {
if newOffset , errno = seek (f .file , offset , whence ); errno != 0 {
errno = fileError (f , f .closed , errno )
if errno == experimentalsys .EISDIR && offset == 0 && whence == io .SeekStart {
errno = 0
f .reopenDir = true
}
}
return
}
func (f *osFile ) Poll (flag fsapi .Pflag , timeoutMillis int32 ) (ready bool , errno experimentalsys .Errno ) {
return poll (f .fd , flag , timeoutMillis )
}
func (f *osFile ) Readdir (n int ) (dirents []experimentalsys .Dirent , errno experimentalsys .Errno ) {
if f .reopenDir {
f .reopenDir = false
if errno = adjustReaddirErr (f , f .closed , f .reopen ()); errno != 0 {
return
}
}
if dirents , errno = readdir (f .file , f .path , n ); errno != 0 {
errno = adjustReaddirErr (f , f .closed , errno )
}
return
}
func (f *osFile ) Write (buf []byte ) (n int , errno experimentalsys .Errno ) {
if len (buf ) == 0 {
return 0 , 0
}
if nonBlockingFileWriteSupported && f .IsNonblock () {
n , errno = writeFd (f .fd , buf )
} else if n , errno = write (f .file , buf ); errno != 0 {
errno = fileError (f , f .closed , errno )
}
return
}
func (f *osFile ) Pwrite (buf []byte , off int64 ) (n int , errno experimentalsys .Errno ) {
if n , errno = pwrite (f .file , buf , off ); errno != 0 {
errno = fileError (f , f .closed , errno )
}
return
}
func (f *osFile ) Truncate (size int64 ) (errno experimentalsys .Errno ) {
if size < 0 {
return experimentalsys .EINVAL
}
if errno = experimentalsys .UnwrapOSError (f .file .Truncate (size )); errno != 0 {
errno = fileError (f , f .closed , errno )
}
return
}
func (f *osFile ) Sync () experimentalsys .Errno {
return fsync (f .file )
}
func (f *osFile ) Datasync () experimentalsys .Errno {
return datasync (f .file )
}
func (f *osFile ) Utimens (atim , mtim int64 ) experimentalsys .Errno {
if f .closed {
return experimentalsys .EBADF
}
err := futimens (f .fd , atim , mtim )
return experimentalsys .UnwrapOSError (err )
}
func (f *osFile ) Close () experimentalsys .Errno {
if f .closed {
return 0
}
f .closed = true
return f .close ()
}
func (f *osFile ) close () experimentalsys .Errno {
return experimentalsys .UnwrapOSError (f .file .Close ())
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .