fd_nacl.go 7.1 KB

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