github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/syscall/fs_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  // A simulated Unix-like file system for use within NaCl.
     6  //
     7  // The simulation is not particularly tied to NaCl other than the reuse
     8  // of NaCl's definition for the Stat_t structure.
     9  //
    10  // The file system need never be written to disk, so it is represented as
    11  // in-memory Go data structures, never in a serialized form.
    12  //
    13  // TODO: Perhaps support symlinks, although they muck everything up.
    14  
    15  package syscall
    16  
    17  import (
    18  	"sync"
    19  	"unsafe"
    20  )
    21  
    22  // Provided by package runtime.
    23  func now() (sec int64, nsec int32)
    24  
    25  // An fsys is a file system.
    26  // Since there is no I/O (everything is in memory),
    27  // the global lock mu protects the whole file system state,
    28  // and that's okay.
    29  type fsys struct {
    30  	mu   sync.Mutex
    31  	root *inode                    // root directory
    32  	cwd  *inode                    // process current directory
    33  	inum uint64                    // number of inodes created
    34  	dev  []func() (devFile, error) // table for opening devices
    35  }
    36  
    37  // A devFile is the implementation required of device files
    38  // like /dev/null or /dev/random.
    39  type devFile interface {
    40  	pread([]byte, int64) (int, error)
    41  	pwrite([]byte, int64) (int, error)
    42  }
    43  
    44  // An inode is a (possibly special) file in the file system.
    45  type inode struct {
    46  	Stat_t
    47  	data []byte
    48  	dir  []dirent
    49  }
    50  
    51  // A dirent describes a single directory entry.
    52  type dirent struct {
    53  	name  string
    54  	inode *inode
    55  }
    56  
    57  // An fsysFile is the fileImpl implementation backed by the file system.
    58  type fsysFile struct {
    59  	defaultFileImpl
    60  	fsys     *fsys
    61  	inode    *inode
    62  	openmode int
    63  	offset   int64
    64  	dev      devFile
    65  }
    66  
    67  // newFsys creates a new file system.
    68  func newFsys() *fsys {
    69  	fs := &fsys{}
    70  	fs.mu.Lock()
    71  	defer fs.mu.Unlock()
    72  	ip := fs.newInode()
    73  	ip.Mode = 0555 | S_IFDIR
    74  	fs.dirlink(ip, ".", ip)
    75  	fs.dirlink(ip, "..", ip)
    76  	fs.cwd = ip
    77  	fs.root = ip
    78  	return fs
    79  }
    80  
    81  var fs = newFsys()
    82  
    83  func init() {
    84  	Mkdir("/dev", 0555)
    85  	Mkdir("/tmp", 0777)
    86  	mkdev("/dev/null", 0666, openNull)
    87  	mkdev("/dev/random", 0444, openRandom)
    88  	mkdev("/dev/urandom", 0444, openRandom)
    89  	mkdev("/dev/zero", 0666, openZero)
    90  	chdirEnv()
    91  }
    92  
    93  func chdirEnv() {
    94  	pwd, ok := Getenv("NACLPWD")
    95  	if ok {
    96  		Chdir(pwd)
    97  	}
    98  }
    99  
   100  // Except where indicated otherwise, unexported methods on fsys
   101  // expect fs.mu to have been locked by the caller.
   102  
   103  // newInode creates a new inode.
   104  func (fs *fsys) newInode() *inode {
   105  	fs.inum++
   106  	ip := &inode{
   107  		Stat_t: Stat_t{
   108  			Ino:     fs.inum,
   109  			Blksize: 512,
   110  		},
   111  	}
   112  	return ip
   113  }
   114  
   115  // atime sets ip.Atime to the current time.
   116  func (fs *fsys) atime(ip *inode) {
   117  	sec, nsec := now()
   118  	ip.Atime, ip.AtimeNsec = sec, int64(nsec)
   119  }
   120  
   121  // mtime sets ip.Mtime to the current time.
   122  func (fs *fsys) mtime(ip *inode) {
   123  	sec, nsec := now()
   124  	ip.Mtime, ip.MtimeNsec = sec, int64(nsec)
   125  }
   126  
   127  // dirlookup looks for an entry in the directory dp with the given name.
   128  // It returns the directory entry and its index within the directory.
   129  func (fs *fsys) dirlookup(dp *inode, name string) (de *dirent, index int, err error) {
   130  	fs.atime(dp)
   131  	for i := range dp.dir {
   132  		de := &dp.dir[i]
   133  		if de.name == name {
   134  			fs.atime(de.inode)
   135  			return de, i, nil
   136  		}
   137  	}
   138  	return nil, 0, ENOENT
   139  }
   140  
   141  // dirlink adds to the directory dp an entry for name pointing at the inode ip.
   142  // If dp already contains an entry for name, that entry is overwritten.
   143  func (fs *fsys) dirlink(dp *inode, name string, ip *inode) {
   144  	fs.mtime(dp)
   145  	fs.atime(ip)
   146  	ip.Nlink++
   147  	for i := range dp.dir {
   148  		if dp.dir[i].name == name {
   149  			dp.dir[i] = dirent{name, ip}
   150  			return
   151  		}
   152  	}
   153  	dp.dir = append(dp.dir, dirent{name, ip})
   154  	dp.dirSize()
   155  }
   156  
   157  func (dp *inode) dirSize() {
   158  	dp.Size = int64(len(dp.dir)) * (8 + 8 + 2 + 256) // Dirent
   159  }
   160  
   161  // skipelem splits path into the first element and the remainder.
   162  // the returned first element contains no slashes, and the returned
   163  // remainder does not begin with a slash.
   164  func skipelem(path string) (elem, rest string) {
   165  	for len(path) > 0 && path[0] == '/' {
   166  		path = path[1:]
   167  	}
   168  	if len(path) == 0 {
   169  		return "", ""
   170  	}
   171  	i := 0
   172  	for i < len(path) && path[i] != '/' {
   173  		i++
   174  	}
   175  	elem, path = path[:i], path[i:]
   176  	for len(path) > 0 && path[0] == '/' {
   177  		path = path[1:]
   178  	}
   179  	return elem, path
   180  }
   181  
   182  // namei translates a file system path name into an inode.
   183  // If parent is false, the returned ip corresponds to the given name, and elem is the empty string.
   184  // If parent is false, the walk stops at the next-to-last element in the name,
   185  // so that ip is the parent directory and elem is the final element in the path.
   186  func (fs *fsys) namei(path string, parent bool) (ip *inode, elem string, err error) {
   187  	// Reject NUL in name.
   188  	for i := 0; i < len(path); i++ {
   189  		if path[i] == '\x00' {
   190  			return nil, "", EINVAL
   191  		}
   192  	}
   193  
   194  	// Reject empty name.
   195  	if path == "" {
   196  		return nil, "", EINVAL
   197  	}
   198  
   199  	if path[0] == '/' {
   200  		ip = fs.root
   201  	} else {
   202  		ip = fs.cwd
   203  	}
   204  
   205  	for len(path) > 0 && path[len(path)-1] == '/' {
   206  		path = path[:len(path)-1]
   207  	}
   208  
   209  	for {
   210  		elem, rest := skipelem(path)
   211  		if elem == "" {
   212  			if parent && ip.Mode&S_IFMT == S_IFDIR {
   213  				return ip, ".", nil
   214  			}
   215  			break
   216  		}
   217  		if ip.Mode&S_IFMT != S_IFDIR {
   218  			return nil, "", ENOTDIR
   219  		}
   220  		if len(elem) >= 256 {
   221  			return nil, "", ENAMETOOLONG
   222  		}
   223  		if parent && rest == "" {
   224  			// Stop one level early.
   225  			return ip, elem, nil
   226  		}
   227  		de, _, err := fs.dirlookup(ip, elem)
   228  		if err != nil {
   229  			return nil, "", err
   230  		}
   231  		ip = de.inode
   232  		path = rest
   233  	}
   234  	if parent {
   235  		return nil, "", ENOTDIR
   236  	}
   237  	return ip, "", nil
   238  }
   239  
   240  // open opens or creates a file with the given name, open mode,
   241  // and permission mode bits.
   242  func (fs *fsys) open(name string, openmode int, mode uint32) (fileImpl, error) {
   243  	dp, elem, err := fs.namei(name, true)
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	var (
   248  		ip  *inode
   249  		dev devFile
   250  	)
   251  	de, _, err := fs.dirlookup(dp, elem)
   252  	if err != nil {
   253  		if openmode&O_CREATE == 0 {
   254  			return nil, err
   255  		}
   256  		ip = fs.newInode()
   257  		ip.Mode = mode
   258  		fs.dirlink(dp, elem, ip)
   259  		if ip.Mode&S_IFMT == S_IFDIR {
   260  			fs.dirlink(ip, ".", ip)
   261  			fs.dirlink(ip, "..", dp)
   262  		}
   263  	} else {
   264  		ip = de.inode
   265  		if openmode&(O_CREATE|O_EXCL) == O_CREATE|O_EXCL {
   266  			return nil, EEXIST
   267  		}
   268  		if openmode&O_TRUNC != 0 {
   269  			if ip.Mode&S_IFMT == S_IFDIR {
   270  				return nil, EISDIR
   271  			}
   272  			ip.data = nil
   273  		}
   274  		if ip.Mode&S_IFMT == S_IFCHR {
   275  			if ip.Rdev < 0 || ip.Rdev >= int64(len(fs.dev)) || fs.dev[ip.Rdev] == nil {
   276  				return nil, ENODEV
   277  			}
   278  			dev, err = fs.dev[ip.Rdev]()
   279  			if err != nil {
   280  				return nil, err
   281  			}
   282  		}
   283  	}
   284  
   285  	switch openmode & O_ACCMODE {
   286  	case O_WRONLY, O_RDWR:
   287  		if ip.Mode&S_IFMT == S_IFDIR {
   288  			return nil, EISDIR
   289  		}
   290  	}
   291  
   292  	switch ip.Mode & S_IFMT {
   293  	case S_IFDIR:
   294  		if openmode&O_ACCMODE != O_RDONLY {
   295  			return nil, EISDIR
   296  		}
   297  
   298  	case S_IFREG:
   299  		// ok
   300  
   301  	case S_IFCHR:
   302  		// handled above
   303  
   304  	default:
   305  		// TODO: some kind of special file
   306  		return nil, EPERM
   307  	}
   308  
   309  	f := &fsysFile{
   310  		fsys:     fs,
   311  		inode:    ip,
   312  		openmode: openmode,
   313  		dev:      dev,
   314  	}
   315  	if openmode&O_APPEND != 0 {
   316  		f.offset = ip.Size
   317  	}
   318  	return f, nil
   319  }
   320  
   321  // fsysFile methods to implement fileImpl.
   322  
   323  func (f *fsysFile) stat(st *Stat_t) error {
   324  	f.fsys.mu.Lock()
   325  	defer f.fsys.mu.Unlock()
   326  	*st = f.inode.Stat_t
   327  	return nil
   328  }
   329  
   330  func (f *fsysFile) read(b []byte) (int, error) {
   331  	f.fsys.mu.Lock()
   332  	defer f.fsys.mu.Unlock()
   333  	n, err := f.preadLocked(b, f.offset)
   334  	f.offset += int64(n)
   335  	return n, err
   336  }
   337  
   338  func ReadDirent(fd int, buf []byte) (int, error) {
   339  	f, err := fdToFsysFile(fd)
   340  	if err != nil {
   341  		return 0, err
   342  	}
   343  	f.fsys.mu.Lock()
   344  	defer f.fsys.mu.Unlock()
   345  	if f.inode.Mode&S_IFMT != S_IFDIR {
   346  		return 0, EINVAL
   347  	}
   348  	n, err := f.preadLocked(buf, f.offset)
   349  	f.offset += int64(n)
   350  	return n, err
   351  }
   352  
   353  func (f *fsysFile) write(b []byte) (int, error) {
   354  	f.fsys.mu.Lock()
   355  	defer f.fsys.mu.Unlock()
   356  	n, err := f.pwriteLocked(b, f.offset)
   357  	f.offset += int64(n)
   358  	return n, err
   359  }
   360  
   361  func (f *fsysFile) seek(offset int64, whence int) (int64, error) {
   362  	f.fsys.mu.Lock()
   363  	defer f.fsys.mu.Unlock()
   364  	switch whence {
   365  	case 1:
   366  		offset += f.offset
   367  	case 2:
   368  		offset += f.inode.Size
   369  	}
   370  	if offset < 0 {
   371  		return 0, EINVAL
   372  	}
   373  	if offset > f.inode.Size {
   374  		return 0, EINVAL
   375  	}
   376  	f.offset = offset
   377  	return offset, nil
   378  }
   379  
   380  func (f *fsysFile) pread(b []byte, offset int64) (int, error) {
   381  	f.fsys.mu.Lock()
   382  	defer f.fsys.mu.Unlock()
   383  	return f.preadLocked(b, offset)
   384  }
   385  
   386  func (f *fsysFile) pwrite(b []byte, offset int64) (int, error) {
   387  	f.fsys.mu.Lock()
   388  	defer f.fsys.mu.Unlock()
   389  	return f.pwriteLocked(b, offset)
   390  }
   391  
   392  func (f *fsysFile) preadLocked(b []byte, offset int64) (int, error) {
   393  	if f.openmode&O_ACCMODE == O_WRONLY {
   394  		return 0, EINVAL
   395  	}
   396  	if offset < 0 {
   397  		return 0, EINVAL
   398  	}
   399  	if f.dev != nil {
   400  		f.fsys.atime(f.inode)
   401  		f.fsys.mu.Unlock()
   402  		defer f.fsys.mu.Lock()
   403  		return f.dev.pread(b, offset)
   404  	}
   405  	if offset > f.inode.Size {
   406  		return 0, nil
   407  	}
   408  	if int64(len(b)) > f.inode.Size-offset {
   409  		b = b[:f.inode.Size-offset]
   410  	}
   411  
   412  	if f.inode.Mode&S_IFMT == S_IFDIR {
   413  		if offset%direntSize != 0 || len(b) != 0 && len(b) < direntSize {
   414  			return 0, EINVAL
   415  		}
   416  		fs.atime(f.inode)
   417  		n := 0
   418  		for len(b) >= direntSize {
   419  			src := f.inode.dir[int(offset/direntSize)]
   420  			dst := (*Dirent)(unsafe.Pointer(&b[0]))
   421  			dst.Ino = int64(src.inode.Ino)
   422  			dst.Off = offset
   423  			dst.Reclen = direntSize
   424  			for i := range dst.Name {
   425  				dst.Name[i] = 0
   426  			}
   427  			copy(dst.Name[:], src.name)
   428  			n += direntSize
   429  			offset += direntSize
   430  			b = b[direntSize:]
   431  		}
   432  		return n, nil
   433  	}
   434  
   435  	fs.atime(f.inode)
   436  	n := copy(b, f.inode.data[offset:])
   437  	return n, nil
   438  }
   439  
   440  func (f *fsysFile) pwriteLocked(b []byte, offset int64) (int, error) {
   441  	if f.openmode&O_ACCMODE == O_RDONLY {
   442  		return 0, EINVAL
   443  	}
   444  	if offset < 0 {
   445  		return 0, EINVAL
   446  	}
   447  	if f.dev != nil {
   448  		f.fsys.atime(f.inode)
   449  		f.fsys.mu.Unlock()
   450  		defer f.fsys.mu.Lock()
   451  		return f.dev.pwrite(b, offset)
   452  	}
   453  	if offset > f.inode.Size {
   454  		return 0, EINVAL
   455  	}
   456  	f.fsys.mtime(f.inode)
   457  	n := copy(f.inode.data[offset:], b)
   458  	if n < len(b) {
   459  		f.inode.data = append(f.inode.data, b[n:]...)
   460  		f.inode.Size = int64(len(f.inode.data))
   461  	}
   462  	return len(b), nil
   463  }
   464  
   465  // Standard Unix system calls.
   466  
   467  func Open(path string, openmode int, perm uint32) (fd int, err error) {
   468  	fs.mu.Lock()
   469  	defer fs.mu.Unlock()
   470  	f, err := fs.open(path, openmode, perm&0777|S_IFREG)
   471  	if err != nil {
   472  		return -1, err
   473  	}
   474  	return newFD(f), nil
   475  }
   476  
   477  func Mkdir(path string, perm uint32) error {
   478  	fs.mu.Lock()
   479  	defer fs.mu.Unlock()
   480  	_, err := fs.open(path, O_CREATE|O_EXCL, perm&0777|S_IFDIR)
   481  	return err
   482  }
   483  
   484  func Getcwd(buf []byte) (n int, err error) {
   485  	// Force package os to default to the old algorithm using .. and directory reads.
   486  	return 0, ENOSYS
   487  }
   488  
   489  func Stat(path string, st *Stat_t) error {
   490  	fs.mu.Lock()
   491  	defer fs.mu.Unlock()
   492  	ip, _, err := fs.namei(path, false)
   493  	if err != nil {
   494  		return err
   495  	}
   496  	*st = ip.Stat_t
   497  	return nil
   498  }
   499  
   500  func Lstat(path string, st *Stat_t) error {
   501  	return Stat(path, st)
   502  }
   503  
   504  func unlink(path string, isdir bool) error {
   505  	fs.mu.Lock()
   506  	defer fs.mu.Unlock()
   507  	dp, elem, err := fs.namei(path, true)
   508  	if err != nil {
   509  		return err
   510  	}
   511  	if elem == "." || elem == ".." {
   512  		return EINVAL
   513  	}
   514  	de, _, err := fs.dirlookup(dp, elem)
   515  	if err != nil {
   516  		return err
   517  	}
   518  	if isdir {
   519  		if de.inode.Mode&S_IFMT != S_IFDIR {
   520  			return ENOTDIR
   521  		}
   522  		if len(de.inode.dir) != 2 {
   523  			return ENOTEMPTY
   524  		}
   525  	} else {
   526  		if de.inode.Mode&S_IFMT == S_IFDIR {
   527  			return EISDIR
   528  		}
   529  	}
   530  	de.inode.Nlink--
   531  	*de = dp.dir[len(dp.dir)-1]
   532  	dp.dir = dp.dir[:len(dp.dir)-1]
   533  	dp.dirSize()
   534  	return nil
   535  }
   536  
   537  func Unlink(path string) error {
   538  	return unlink(path, false)
   539  }
   540  
   541  func Rmdir(path string) error {
   542  	return unlink(path, true)
   543  }
   544  
   545  func Chmod(path string, mode uint32) error {
   546  	fs.mu.Lock()
   547  	defer fs.mu.Unlock()
   548  	ip, _, err := fs.namei(path, false)
   549  	if err != nil {
   550  		return err
   551  	}
   552  	ip.Mode = ip.Mode&^0777 | mode&0777
   553  	return nil
   554  }
   555  
   556  func Fchmod(fd int, mode uint32) error {
   557  	f, err := fdToFsysFile(fd)
   558  	if err != nil {
   559  		return err
   560  	}
   561  	f.fsys.mu.Lock()
   562  	defer f.fsys.mu.Unlock()
   563  	f.inode.Mode = f.inode.Mode&^0777 | mode&0777
   564  	return nil
   565  }
   566  
   567  func Chown(path string, uid, gid int) error {
   568  	fs.mu.Lock()
   569  	defer fs.mu.Unlock()
   570  	ip, _, err := fs.namei(path, false)
   571  	if err != nil {
   572  		return err
   573  	}
   574  	ip.Uid = uint32(uid)
   575  	ip.Gid = uint32(gid)
   576  	return nil
   577  }
   578  
   579  func Fchown(fd int, uid, gid int) error {
   580  	fs.mu.Lock()
   581  	defer fs.mu.Unlock()
   582  	f, err := fdToFsysFile(fd)
   583  	if err != nil {
   584  		return err
   585  	}
   586  	f.fsys.mu.Lock()
   587  	defer f.fsys.mu.Unlock()
   588  	f.inode.Uid = uint32(uid)
   589  	f.inode.Gid = uint32(gid)
   590  	return nil
   591  }
   592  
   593  func Lchown(path string, uid, gid int) error {
   594  	return Chown(path, uid, gid)
   595  }
   596  
   597  func UtimesNano(path string, ts []Timespec) error {
   598  	if len(ts) != 2 {
   599  		return EINVAL
   600  	}
   601  	fs.mu.Lock()
   602  	defer fs.mu.Unlock()
   603  	ip, _, err := fs.namei(path, false)
   604  	if err != nil {
   605  		return err
   606  	}
   607  	ip.Atime = ts[0].Sec
   608  	ip.AtimeNsec = int64(ts[0].Nsec)
   609  	ip.Mtime = ts[1].Sec
   610  	ip.MtimeNsec = int64(ts[1].Nsec)
   611  	return nil
   612  }
   613  
   614  func Link(path, link string) error {
   615  	ip, _, err := fs.namei(path, false)
   616  	if err != nil {
   617  		return err
   618  	}
   619  	dp, elem, err := fs.namei(link, true)
   620  	if err != nil {
   621  		return err
   622  	}
   623  	if ip.Mode&S_IFMT == S_IFDIR {
   624  		return EPERM
   625  	}
   626  	fs.dirlink(dp, elem, ip)
   627  	return nil
   628  }
   629  
   630  func Rename(from, to string) error {
   631  	fdp, felem, err := fs.namei(from, true)
   632  	if err != nil {
   633  		return err
   634  	}
   635  	fde, _, err := fs.dirlookup(fdp, felem)
   636  	if err != nil {
   637  		return err
   638  	}
   639  	tdp, telem, err := fs.namei(to, true)
   640  	if err != nil {
   641  		return err
   642  	}
   643  	fs.dirlink(tdp, telem, fde.inode)
   644  	fde.inode.Nlink--
   645  	*fde = fdp.dir[len(fdp.dir)-1]
   646  	fdp.dir = fdp.dir[:len(fdp.dir)-1]
   647  	fdp.dirSize()
   648  	return nil
   649  }
   650  
   651  func (fs *fsys) truncate(ip *inode, length int64) error {
   652  	if length > 1e9 || ip.Mode&S_IFMT != S_IFREG {
   653  		return EINVAL
   654  	}
   655  	if length < int64(len(ip.data)) {
   656  		ip.data = ip.data[:length]
   657  	} else {
   658  		data := make([]byte, length)
   659  		copy(data, ip.data)
   660  		ip.data = data
   661  	}
   662  	ip.Size = int64(len(ip.data))
   663  	return nil
   664  }
   665  
   666  func Truncate(path string, length int64) error {
   667  	fs.mu.Lock()
   668  	defer fs.mu.Unlock()
   669  	ip, _, err := fs.namei(path, false)
   670  	if err != nil {
   671  		return err
   672  	}
   673  	return fs.truncate(ip, length)
   674  }
   675  
   676  func Ftruncate(fd int, length int64) error {
   677  	f, err := fdToFsysFile(fd)
   678  	if err != nil {
   679  		return err
   680  	}
   681  	f.fsys.mu.Lock()
   682  	defer f.fsys.mu.Unlock()
   683  	return f.fsys.truncate(f.inode, length)
   684  }
   685  
   686  func Chdir(path string) error {
   687  	fs.mu.Lock()
   688  	defer fs.mu.Unlock()
   689  	ip, _, err := fs.namei(path, false)
   690  	if err != nil {
   691  		return err
   692  	}
   693  	fs.cwd = ip
   694  	return nil
   695  }
   696  
   697  func Fchdir(fd int) error {
   698  	f, err := fdToFsysFile(fd)
   699  	if err != nil {
   700  		return err
   701  	}
   702  	f.fsys.mu.Lock()
   703  	defer f.fsys.mu.Unlock()
   704  	if f.inode.Mode&S_IFMT != S_IFDIR {
   705  		return ENOTDIR
   706  	}
   707  	fs.cwd = f.inode
   708  	return nil
   709  }
   710  
   711  func Readlink(path string, buf []byte) (n int, err error) {
   712  	return 0, ENOSYS
   713  }
   714  
   715  func Symlink(path, link string) error {
   716  	return ENOSYS
   717  }
   718  
   719  func Fsync(fd int) error {
   720  	return nil
   721  }
   722  
   723  // Special devices.
   724  
   725  func mkdev(path string, mode uint32, open func() (devFile, error)) error {
   726  	fs.mu.Lock()
   727  	fs.mu.Unlock()
   728  	f, err := fs.open(path, O_CREATE|O_RDONLY|O_EXCL, S_IFCHR|mode)
   729  	if err != nil {
   730  		return err
   731  	}
   732  	ip := f.(*fsysFile).inode
   733  	ip.Rdev = int64(len(fs.dev))
   734  	fs.dev = append(fs.dev, open)
   735  	return nil
   736  }
   737  
   738  type nullFile struct{}
   739  
   740  func openNull() (devFile, error)                               { return &nullFile{}, nil }
   741  func (f *nullFile) close() error                               { return nil }
   742  func (f *nullFile) pread(b []byte, offset int64) (int, error)  { return 0, nil }
   743  func (f *nullFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
   744  
   745  type zeroFile struct{}
   746  
   747  func openZero() (devFile, error)                               { return &zeroFile{}, nil }
   748  func (f *zeroFile) close() error                               { return nil }
   749  func (f *zeroFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
   750  
   751  func (f *zeroFile) pread(b []byte, offset int64) (int, error) {
   752  	for i := range b {
   753  		b[i] = 0
   754  	}
   755  	return len(b), nil
   756  }
   757  
   758  type randomFile struct {
   759  	naclFD int
   760  }
   761  
   762  func openRandom() (devFile, error) {
   763  	fd, err := openNamedService("SecureRandom", O_RDONLY)
   764  	if err != nil {
   765  		return nil, err
   766  	}
   767  	return &randomFile{naclFD: fd}, nil
   768  }
   769  
   770  func (f *randomFile) close() error {
   771  	naclClose(f.naclFD)
   772  	f.naclFD = -1
   773  	return nil
   774  }
   775  
   776  func (f *randomFile) pread(b []byte, offset int64) (int, error) {
   777  	return naclRead(f.naclFD, b)
   778  }
   779  
   780  func (f *randomFile) pwrite(b []byte, offset int64) (int, error) {
   781  	return 0, EPERM
   782  }
   783  
   784  func fdToFsysFile(fd int) (*fsysFile, error) {
   785  	f, err := fdToFile(fd)
   786  	if err != nil {
   787  		return nil, err
   788  	}
   789  	impl := f.impl
   790  	fsysf, ok := impl.(*fsysFile)
   791  	if !ok {
   792  		return nil, EINVAL
   793  	}
   794  	return fsysf, nil
   795  }
   796  
   797  // create creates a file in the file system with the given name, mode, time, and data.
   798  // It is meant to be called when initializing the file system image.
   799  func create(name string, mode uint32, sec int64, data []byte) error {
   800  	fs.mu.Lock()
   801  	fs.mu.Unlock()
   802  	f, err := fs.open(name, O_CREATE|O_EXCL, mode)
   803  	if err != nil {
   804  		return err
   805  	}
   806  	ip := f.(*fsysFile).inode
   807  	ip.Atime = sec
   808  	ip.Mtime = sec
   809  	ip.Ctime = sec
   810  	if len(data) > 0 {
   811  		ip.Size = int64(len(data))
   812  		ip.data = data
   813  	}
   814  	return nil
   815  }