github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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 if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil || newfd < 0 || newfd >= len(files.tab)+100 { 125 files.Unlock() 126 return EBADF 127 } 128 f := files.tab[fd] 129 f.fdref++ 130 for cap(files.tab) <= newfd { 131 files.tab = append(files.tab[:cap(files.tab)], nil) 132 } 133 oldf := files.tab[newfd] 134 var oldfdref int 135 if oldf != nil { 136 oldf.fdref-- 137 oldfdref = oldf.fdref 138 } 139 files.tab[newfd] = f 140 files.Unlock() 141 if oldf != nil { 142 if oldfdref == 0 { 143 oldf.impl.close() 144 } 145 } 146 return nil 147 } 148 149 func Fstat(fd int, st *Stat_t) error { 150 f, err := fdToFile(fd) 151 if err != nil { 152 return err 153 } 154 return f.impl.stat(st) 155 } 156 157 func Read(fd int, b []byte) (int, error) { 158 f, err := fdToFile(fd) 159 if err != nil { 160 return 0, err 161 } 162 return f.impl.read(b) 163 } 164 165 var zerobuf [0]byte 166 167 func Write(fd int, b []byte) (int, error) { 168 if b == nil { 169 // avoid nil in syscalls; nacl doesn't like that. 170 b = zerobuf[:] 171 } 172 f, err := fdToFile(fd) 173 if err != nil { 174 return 0, err 175 } 176 return f.impl.write(b) 177 } 178 179 func Pread(fd int, b []byte, offset int64) (int, error) { 180 f, err := fdToFile(fd) 181 if err != nil { 182 return 0, err 183 } 184 return f.impl.pread(b, offset) 185 } 186 187 func Pwrite(fd int, b []byte, offset int64) (int, error) { 188 f, err := fdToFile(fd) 189 if err != nil { 190 return 0, err 191 } 192 return f.impl.pwrite(b, offset) 193 } 194 195 func Seek(fd int, offset int64, whence int) (int64, error) { 196 f, err := fdToFile(fd) 197 if err != nil { 198 return 0, err 199 } 200 return f.impl.seek(offset, whence) 201 } 202 203 // defaulFileImpl implements fileImpl. 204 // It can be embedded to complete a partial fileImpl implementation. 205 type defaultFileImpl struct{} 206 207 func (*defaultFileImpl) close() error { return nil } 208 func (*defaultFileImpl) stat(*Stat_t) error { return ENOSYS } 209 func (*defaultFileImpl) read([]byte) (int, error) { return 0, ENOSYS } 210 func (*defaultFileImpl) write([]byte) (int, error) { return 0, ENOSYS } 211 func (*defaultFileImpl) seek(int64, int) (int64, error) { return 0, ENOSYS } 212 func (*defaultFileImpl) pread([]byte, int64) (int, error) { return 0, ENOSYS } 213 func (*defaultFileImpl) pwrite([]byte, int64) (int, error) { return 0, ENOSYS } 214 215 // naclFile is the fileImpl implementation for a Native Client file descriptor. 216 type naclFile struct { 217 defaultFileImpl 218 naclFD int 219 } 220 221 func (f *naclFile) stat(st *Stat_t) error { 222 return naclFstat(f.naclFD, st) 223 } 224 225 func (f *naclFile) read(b []byte) (int, error) { 226 n, err := naclRead(f.naclFD, b) 227 if err != nil { 228 n = 0 229 } 230 return n, err 231 } 232 233 // implemented in package runtime, to add time header on playground 234 func naclWrite(fd int, b []byte) int 235 236 func (f *naclFile) write(b []byte) (int, error) { 237 n := naclWrite(f.naclFD, b) 238 if n < 0 { 239 return 0, Errno(-n) 240 } 241 return n, nil 242 } 243 244 func (f *naclFile) seek(off int64, whence int) (int64, error) { 245 old := off 246 err := naclSeek(f.naclFD, &off, whence) 247 if err != nil { 248 return old, err 249 } 250 return off, nil 251 } 252 253 func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) { 254 // NaCl has no pread; simulate with seek and hope for no races. 255 old, err := f.seek(0, io.SeekCurrent) 256 if err != nil { 257 return 0, err 258 } 259 if _, err := f.seek(offset, io.SeekStart); err != nil { 260 return 0, err 261 } 262 n, err := rw(b) 263 f.seek(old, io.SeekStart) 264 return n, err 265 } 266 267 func (f *naclFile) pread(b []byte, offset int64) (int, error) { 268 return f.prw(b, offset, f.read) 269 } 270 271 func (f *naclFile) pwrite(b []byte, offset int64) (int, error) { 272 return f.prw(b, offset, f.write) 273 } 274 275 func (f *naclFile) close() error { 276 err := naclClose(f.naclFD) 277 f.naclFD = -1 278 return err 279 } 280 281 // A pipeFile is an in-memory implementation of a pipe. 282 // The byteq implementation is in net_nacl.go. 283 type pipeFile struct { 284 defaultFileImpl 285 rd *byteq 286 wr *byteq 287 } 288 289 func (f *pipeFile) close() error { 290 if f.rd != nil { 291 f.rd.close() 292 } 293 if f.wr != nil { 294 f.wr.close() 295 } 296 return nil 297 } 298 299 func (f *pipeFile) read(b []byte) (int, error) { 300 if f.rd == nil { 301 return 0, EINVAL 302 } 303 n, err := f.rd.read(b, 0) 304 if err == EAGAIN { 305 err = nil 306 } 307 return n, err 308 } 309 310 func (f *pipeFile) write(b []byte) (int, error) { 311 if f.wr == nil { 312 return 0, EINVAL 313 } 314 n, err := f.wr.write(b, 0) 315 if err == EAGAIN { 316 err = EPIPE 317 } 318 return n, err 319 } 320 321 func Pipe(fd []int) error { 322 q := newByteq() 323 fd[0] = newFD(&pipeFile{rd: q}) 324 fd[1] = newFD(&pipeFile{wr: q}) 325 return nil 326 }