github.com/tetratelabs/wazero@v1.2.1/internal/sys/stdio.go (about) 1 package sys 2 3 import ( 4 "io" 5 "os" 6 "syscall" 7 "time" 8 9 "github.com/tetratelabs/wazero/internal/fsapi" 10 "github.com/tetratelabs/wazero/internal/platform" 11 "github.com/tetratelabs/wazero/internal/sysfs" 12 ) 13 14 // StdinFile is a fs.ModeDevice file for use implementing FdStdin. 15 // This is safer than reading from os.DevNull as it can never overrun 16 // operating system file descriptors. 17 type StdinFile struct { 18 noopStdinFile 19 io.Reader 20 } 21 22 // Read implements the same method as documented on internalapi.File 23 func (f *StdinFile) Read(buf []byte) (int, syscall.Errno) { 24 n, err := f.Reader.Read(buf) 25 return n, platform.UnwrapOSError(err) 26 } 27 28 type writerFile struct { 29 noopStdoutFile 30 31 w io.Writer 32 } 33 34 // Write implements the same method as documented on internalapi.File 35 func (f *writerFile) Write(buf []byte) (int, syscall.Errno) { 36 n, err := f.w.Write(buf) 37 return n, platform.UnwrapOSError(err) 38 } 39 40 // noopStdinFile is a fs.ModeDevice file for use implementing FdStdin. This is 41 // safer than reading from os.DevNull as it can never overrun operating system 42 // file descriptors. 43 type noopStdinFile struct { 44 noopStdioFile 45 } 46 47 // AccessMode implements the same method as documented on internalapi.File 48 func (noopStdinFile) AccessMode() int { 49 return syscall.O_RDONLY 50 } 51 52 // Read implements the same method as documented on internalapi.File 53 func (noopStdinFile) Read([]byte) (int, syscall.Errno) { 54 return 0, 0 // Always EOF 55 } 56 57 // PollRead implements the same method as documented on internalapi.File 58 func (noopStdinFile) PollRead(*time.Duration) (ready bool, errno syscall.Errno) { 59 return true, 0 // always ready to read nothing 60 } 61 62 // noopStdoutFile is a fs.ModeDevice file for use implementing FdStdout and 63 // FdStderr. 64 type noopStdoutFile struct { 65 noopStdioFile 66 } 67 68 // AccessMode implements the same method as documented on internalapi.File 69 func (noopStdoutFile) AccessMode() int { 70 return syscall.O_WRONLY 71 } 72 73 // Write implements the same method as documented on internalapi.File 74 func (noopStdoutFile) Write(buf []byte) (int, syscall.Errno) { 75 return len(buf), 0 // same as io.Discard 76 } 77 78 type noopStdioFile struct { 79 fsapi.UnimplementedFile 80 } 81 82 // Stat implements the same method as documented on internalapi.File 83 func (noopStdioFile) Stat() (fsapi.Stat_t, syscall.Errno) { 84 return fsapi.Stat_t{Mode: modeDevice, Nlink: 1}, 0 85 } 86 87 // IsDir implements the same method as documented on internalapi.File 88 func (noopStdioFile) IsDir() (bool, syscall.Errno) { 89 return false, 0 90 } 91 92 // Close implements the same method as documented on internalapi.File 93 func (noopStdioFile) Close() (errno syscall.Errno) { return } 94 95 func stdinFileEntry(r io.Reader) (*FileEntry, error) { 96 if r == nil { 97 return &FileEntry{Name: "stdin", IsPreopen: true, File: &noopStdinFile{}}, nil 98 } else if f, ok := r.(*os.File); ok { 99 if f, err := sysfs.NewStdioFile(true, f); err != nil { 100 return nil, err 101 } else { 102 return &FileEntry{Name: "stdin", IsPreopen: true, File: f}, nil 103 } 104 } else { 105 return &FileEntry{Name: "stdin", IsPreopen: true, File: &StdinFile{Reader: r}}, nil 106 } 107 } 108 109 func stdioWriterFileEntry(name string, w io.Writer) (*FileEntry, error) { 110 if w == nil { 111 return &FileEntry{Name: name, IsPreopen: true, File: &noopStdoutFile{}}, nil 112 } else if f, ok := w.(*os.File); ok { 113 if f, err := sysfs.NewStdioFile(false, f); err != nil { 114 return nil, err 115 } else { 116 return &FileEntry{Name: name, IsPreopen: true, File: f}, nil 117 } 118 } else { 119 return &FileEntry{Name: name, IsPreopen: true, File: &writerFile{w: w}}, nil 120 } 121 }