github.com/tetratelabs/wazero@v1.2.1/internal/sys/lazy.go (about)

     1  package sys
     2  
     3  import (
     4  	"io/fs"
     5  	"os"
     6  	"syscall"
     7  
     8  	"github.com/tetratelabs/wazero/internal/fsapi"
     9  )
    10  
    11  // compile-time check to ensure lazyDir implements internalapi.File.
    12  var _ fsapi.File = (*lazyDir)(nil)
    13  
    14  type lazyDir struct {
    15  	fsapi.DirFile
    16  
    17  	fs fsapi.FS
    18  	f  fsapi.File
    19  }
    20  
    21  // Ino implements the same method as documented on internalapi.File
    22  func (r *lazyDir) Ino() (uint64, syscall.Errno) {
    23  	if f, ok := r.file(); !ok {
    24  		return 0, syscall.EBADF
    25  	} else {
    26  		return f.Ino()
    27  	}
    28  }
    29  
    30  // IsAppend implements the same method as documented on internalapi.File
    31  func (r *lazyDir) IsAppend() bool {
    32  	return false
    33  }
    34  
    35  // SetAppend implements the same method as documented on internalapi.File
    36  func (r *lazyDir) SetAppend(bool) syscall.Errno {
    37  	return syscall.EISDIR
    38  }
    39  
    40  // Seek implements the same method as documented on internalapi.File
    41  func (r *lazyDir) Seek(offset int64, whence int) (newOffset int64, errno syscall.Errno) {
    42  	if f, ok := r.file(); !ok {
    43  		return 0, syscall.EBADF
    44  	} else {
    45  		return f.Seek(offset, whence)
    46  	}
    47  }
    48  
    49  // Stat implements the same method as documented on internalapi.File
    50  func (r *lazyDir) Stat() (fsapi.Stat_t, syscall.Errno) {
    51  	if f, ok := r.file(); !ok {
    52  		return fsapi.Stat_t{}, syscall.EBADF
    53  	} else {
    54  		return f.Stat()
    55  	}
    56  }
    57  
    58  // Readdir implements the same method as documented on internalapi.File
    59  func (r *lazyDir) Readdir(n int) (dirents []fsapi.Dirent, errno syscall.Errno) {
    60  	if f, ok := r.file(); !ok {
    61  		return nil, syscall.EBADF
    62  	} else {
    63  		return f.Readdir(n)
    64  	}
    65  }
    66  
    67  // Sync implements the same method as documented on internalapi.File
    68  func (r *lazyDir) Sync() syscall.Errno {
    69  	if f, ok := r.file(); !ok {
    70  		return syscall.EBADF
    71  	} else {
    72  		return f.Sync()
    73  	}
    74  }
    75  
    76  // Datasync implements the same method as documented on internalapi.File
    77  func (r *lazyDir) Datasync() syscall.Errno {
    78  	if f, ok := r.file(); !ok {
    79  		return syscall.EBADF
    80  	} else {
    81  		return f.Datasync()
    82  	}
    83  }
    84  
    85  // Chmod implements the same method as documented on internalapi.File
    86  func (r *lazyDir) Chmod(mode fs.FileMode) syscall.Errno {
    87  	if f, ok := r.file(); !ok {
    88  		return syscall.EBADF
    89  	} else {
    90  		return f.Chmod(mode)
    91  	}
    92  }
    93  
    94  // Chown implements the same method as documented on internalapi.File
    95  func (r *lazyDir) Chown(uid, gid int) syscall.Errno {
    96  	if f, ok := r.file(); !ok {
    97  		return syscall.EBADF
    98  	} else {
    99  		return f.Chown(uid, gid)
   100  	}
   101  }
   102  
   103  // Utimens implements the same method as documented on internalapi.File
   104  func (r *lazyDir) Utimens(times *[2]syscall.Timespec) syscall.Errno {
   105  	if f, ok := r.file(); !ok {
   106  		return syscall.EBADF
   107  	} else {
   108  		return f.Utimens(times)
   109  	}
   110  }
   111  
   112  // file returns the underlying file or false if it doesn't exist.
   113  func (r *lazyDir) file() (fsapi.File, bool) {
   114  	if f := r.f; r.f != nil {
   115  		return f, true
   116  	}
   117  	var errno syscall.Errno
   118  	r.f, errno = r.fs.OpenFile(".", os.O_RDONLY, 0)
   119  	switch errno {
   120  	case 0:
   121  		return r.f, true
   122  	case syscall.ENOENT:
   123  		return nil, false
   124  	default:
   125  		panic(errno) // unexpected
   126  	}
   127  }
   128  
   129  // Close implements fs.File
   130  func (r *lazyDir) Close() syscall.Errno {
   131  	f := r.f
   132  	if f == nil {
   133  		return 0 // never opened
   134  	}
   135  	return f.Close()
   136  }