github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/sys/lazy.go (about)

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