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