github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/src/syscall/fd_nacl.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // File descriptor support for Native Client. 6 // We want to provide access to a broader range of (simulated) files than 7 // Native Client allows, so we maintain our own file descriptor table exposed 8 // to higher-level packages. 9 10 package syscall 11 12 import ( 13 "io" 14 "sync" 15 ) 16 17 // files is the table indexed by a file descriptor. 18 var files struct { 19 sync.RWMutex 20 tab []*file 21 } 22 23 // A file is an open file, something with a file descriptor. 24 // A particular *file may appear in files multiple times, due to use of Dup or Dup2. 25 type file struct { 26 fdref int // uses in files.tab 27 impl fileImpl // underlying implementation 28 } 29 30 // A fileImpl is the implementation of something that can be a file. 31 type fileImpl interface { 32 // Standard operations. 33 // These can be called concurrently from multiple goroutines. 34 stat(*Stat_t) error 35 read([]byte) (int, error) 36 write([]byte) (int, error) 37 seek(int64, int) (int64, error) 38 pread([]byte, int64) (int, error) 39 pwrite([]byte, int64) (int, error) 40 41 // Close is called when the last reference to a *file is removed 42 // from the file descriptor table. It may be called concurrently 43 // with active operations such as blocked read or write calls. 44 close() error 45 } 46 47 // newFD adds impl to the file descriptor table, 48 // returning the new file descriptor. 49 // Like Unix, it uses the lowest available descriptor. 50 func newFD(impl fileImpl) int { 51 files.Lock() 52 defer files.Unlock() 53 f := &file{impl: impl, fdref: 1} 54 for fd, oldf := range files.tab { 55 if oldf == nil { 56 files.tab[fd] = f 57 return fd 58 } 59 } 60 fd := len(files.tab) 61 files.tab = append(files.tab, f) 62 return fd 63 } 64 65 // Install Native Client stdin, stdout, stderr. 66 func init() { 67 newFD(&naclFile{naclFD: 0}) 68 newFD(&naclFile{naclFD: 1}) 69 newFD(&naclFile{naclFD: 2}) 70 } 71 72 // fdToFile retrieves the *file corresponding to a file descriptor. 73 func fdToFile(fd int) (*file, error) { 74 files.Lock() 75 defer files.Unlock() 76 if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil { 77 return nil, EBADF 78 } 79 return files.tab[fd], nil 80 } 81 82 func Close(fd int) error { 83 files.Lock() 84 if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil { 85 files.Unlock() 86 return EBADF 87 } 88 f := files.tab[fd] 89 files.tab[fd] = nil 90 f.fdref-- 91 fdref := f.fdref 92 files.Unlock() 93 if fdref > 0 { 94 return nil 95 } 96 return f.impl.close() 97 } 98 99 func CloseOnExec(fd int) { 100 // nothing to do - no exec 101 } 102 103 func Dup(fd int) (int, error) { 104 files.Lock() 105 defer files.Unlock() 106 if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil { 107 return -1, EBADF 108 } 109 f := files.tab[fd] 110 f.fdref++ 111 for newfd, oldf := range files.tab { 112 if oldf == nil { 113 files.tab[newfd] = f 114 return newfd, nil 115 } 116 } 117 newfd := len(files.tab) 118 files.tab = append(files.tab, f) 119 return newfd, nil 120 } 121 122 func Dup2(fd, newfd int) error { 123 files.Lock() 124 defer files.Unlock() 125 if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil || newfd < 0 || newfd >= len(files.tab)+100 { 126 files.Unlock() 127 return EBADF 128 } 129 f := files.tab[fd] 130 f.fdref++ 131 for cap(files.tab) <= newfd { 132 files.tab = append(files.tab[:cap(files.tab)], nil) 133 } 134 oldf := files.tab[newfd] 135 var oldfdref int 136 if oldf != nil { 137 oldf.fdref-- 138 oldfdref = oldf.fdref 139 } 140 files.tab[newfd] = f 141 files.Unlock() 142 if oldf != nil { 143 if oldfdref == 0 { 144 oldf.impl.close() 145 } 146 } 147 return nil 148 } 149 150 func Fstat(fd int, st *Stat_t) error { 151 f, err := fdToFile(fd) 152 if err != nil { 153 return err 154 } 155 return f.impl.stat(st) 156 } 157 158 func Read(fd int, b []byte) (int, error) { 159 f, err := fdToFile(fd) 160 if err != nil { 161 return 0, err 162 } 163 return f.impl.read(b) 164 } 165 166 var zerobuf [0]byte 167 168 func Write(fd int, b []byte) (int, error) { 169 if b == nil { 170 // avoid nil in syscalls; nacl doesn't like that. 171 b = zerobuf[:] 172 } 173 f, err := fdToFile(fd) 174 if err != nil { 175 return 0, err 176 } 177 return f.impl.write(b) 178 } 179 180 func Pread(fd int, b []byte, offset int64) (int, error) { 181 f, err := fdToFile(fd) 182 if err != nil { 183 return 0, err 184 } 185 return f.impl.pread(b, offset) 186 } 187 188 func Pwrite(fd int, b []byte, offset int64) (int, error) { 189 f, err := fdToFile(fd) 190 if err != nil { 191 return 0, err 192 } 193 return f.impl.pwrite(b, offset) 194 } 195 196 func Seek(fd int, offset int64, whence int) (int64, error) { 197 f, err := fdToFile(fd) 198 if err != nil { 199 return 0, err 200 } 201 return f.impl.seek(offset, whence) 202 } 203 204 // defaulFileImpl implements fileImpl. 205 // It can be embedded to complete a partial fileImpl implementation. 206 type defaultFileImpl struct{} 207 208 func (*defaultFileImpl) close() error { return nil } 209 func (*defaultFileImpl) stat(*Stat_t) error { return ENOSYS } 210 func (*defaultFileImpl) read([]byte) (int, error) { return 0, ENOSYS } 211 func (*defaultFileImpl) write([]byte) (int, error) { return 0, ENOSYS } 212 func (*defaultFileImpl) seek(int64, int) (int64, error) { return 0, ENOSYS } 213 func (*defaultFileImpl) pread([]byte, int64) (int, error) { return 0, ENOSYS } 214 func (*defaultFileImpl) pwrite([]byte, int64) (int, error) { return 0, ENOSYS } 215 216 // naclFile is the fileImpl implementation for a Native Client file descriptor. 217 type naclFile struct { 218 defaultFileImpl 219 naclFD int 220 } 221 222 func (f *naclFile) stat(st *Stat_t) error { 223 return naclFstat(f.naclFD, st) 224 } 225 226 func (f *naclFile) read(b []byte) (int, error) { 227 n, err := naclRead(f.naclFD, b) 228 if err != nil { 229 n = 0 230 } 231 return n, err 232 } 233 234 // implemented in package runtime, to add time header on playground 235 func naclWrite(fd int, b []byte) int 236 237 func (f *naclFile) write(b []byte) (int, error) { 238 n := naclWrite(f.naclFD, b) 239 if n < 0 { 240 return 0, Errno(-n) 241 } 242 return n, nil 243 } 244 245 func (f *naclFile) seek(off int64, whence int) (int64, error) { 246 old := off 247 err := naclSeek(f.naclFD, &off, whence) 248 if err != nil { 249 return old, err 250 } 251 return off, nil 252 } 253 254 func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) { 255 // NaCl has no pread; simulate with seek and hope for no races. 256 old, err := f.seek(0, io.SeekCurrent) 257 if err != nil { 258 return 0, err 259 } 260 if _, err := f.seek(offset, io.SeekStart); err != nil { 261 return 0, err 262 } 263 n, err := rw(b) 264 f.seek(old, io.SeekStart) 265 return n, err 266 } 267 268 func (f *naclFile) pread(b []byte, offset int64) (int, error) { 269 return f.prw(b, offset, f.read) 270 } 271 272 func (f *naclFile) pwrite(b []byte, offset int64) (int, error) { 273 return f.prw(b, offset, f.write) 274 } 275 276 func (f *naclFile) close() error { 277 err := naclClose(f.naclFD) 278 f.naclFD = -1 279 return err 280 } 281 282 // A pipeFile is an in-memory implementation of a pipe. 283 // The byteq implementation is in net_nacl.go. 284 type pipeFile struct { 285 defaultFileImpl 286 rd *byteq 287 wr *byteq 288 } 289 290 func (f *pipeFile) close() error { 291 if f.rd != nil { 292 f.rd.close() 293 } 294 if f.wr != nil { 295 f.wr.close() 296 } 297 return nil 298 } 299 300 func (f *pipeFile) read(b []byte) (int, error) { 301 if f.rd == nil { 302 return 0, EINVAL 303 } 304 n, err := f.rd.read(b, 0) 305 if err == EAGAIN { 306 err = nil 307 } 308 return n, err 309 } 310 311 func (f *pipeFile) write(b []byte) (int, error) { 312 if f.wr == nil { 313 return 0, EINVAL 314 } 315 n, err := f.wr.write(b, 0) 316 if err == EAGAIN { 317 err = EPIPE 318 } 319 return n, err 320 } 321 322 func Pipe(fd []int) error { 323 q := newByteq() 324 fd[0] = newFD(&pipeFile{rd: q}) 325 fd[1] = newFD(&pipeFile{wr: q}) 326 return nil 327 }