...

Source file src/syscall/fs_nacl.go

     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		if uid != -1 {
   586			ip.Uid = uint32(uid)
   587		}
   588		if gid != -1 {
   589			ip.Gid = uint32(gid)
   590		}
   591		return nil
   592	}
   593	
   594	func Fchown(fd int, uid, gid int) error {
   595		fs.mu.Lock()
   596		defer fs.mu.Unlock()
   597		f, err := fdToFsysFile(fd)
   598		if err != nil {
   599			return err
   600		}
   601		f.fsys.mu.Lock()
   602		defer f.fsys.mu.Unlock()
   603		f.inode.Uid = uint32(uid)
   604		f.inode.Gid = uint32(gid)
   605		return nil
   606	}
   607	
   608	func Lchown(path string, uid, gid int) error {
   609		return Chown(path, uid, gid)
   610	}
   611	
   612	func UtimesNano(path string, ts []Timespec) error {
   613		if len(ts) != 2 {
   614			return EINVAL
   615		}
   616		fsinit()
   617		fs.mu.Lock()
   618		defer fs.mu.Unlock()
   619		ip, _, err := fs.namei(path, false)
   620		if err != nil {
   621			return err
   622		}
   623		ip.Atime = ts[0].Sec
   624		ip.AtimeNsec = int64(ts[0].Nsec)
   625		ip.Mtime = ts[1].Sec
   626		ip.MtimeNsec = int64(ts[1].Nsec)
   627		return nil
   628	}
   629	
   630	func Link(path, link string) error {
   631		fsinit()
   632		fs.mu.Lock()
   633		defer fs.mu.Unlock()
   634		ip, _, err := fs.namei(path, false)
   635		if err != nil {
   636			return err
   637		}
   638		dp, elem, err := fs.namei(link, true)
   639		if err != nil {
   640			return err
   641		}
   642		if ip.Mode&S_IFMT == S_IFDIR {
   643			return EPERM
   644		}
   645		_, _, err = fs.dirlookup(dp, elem)
   646		if err == nil {
   647			return EEXIST
   648		}
   649		fs.dirlink(dp, elem, ip)
   650		return nil
   651	}
   652	
   653	func Rename(from, to string) error {
   654		fsinit()
   655		fs.mu.Lock()
   656		defer fs.mu.Unlock()
   657		fdp, felem, err := fs.namei(from, true)
   658		if err != nil {
   659			return err
   660		}
   661		fde, _, err := fs.dirlookup(fdp, felem)
   662		if err != nil {
   663			return err
   664		}
   665		tdp, telem, err := fs.namei(to, true)
   666		if err != nil {
   667			return err
   668		}
   669		fs.dirlink(tdp, telem, fde.inode)
   670		fde.inode.Nlink--
   671		*fde = fdp.dir[len(fdp.dir)-1]
   672		fdp.dir = fdp.dir[:len(fdp.dir)-1]
   673		fdp.dirSize()
   674		return nil
   675	}
   676	
   677	func (fs *fsys) truncate(ip *inode, length int64) error {
   678		if length > 1e9 || ip.Mode&S_IFMT != S_IFREG {
   679			return EINVAL
   680		}
   681		if length < int64(len(ip.data)) {
   682			ip.data = ip.data[:length]
   683		} else {
   684			data := make([]byte, length)
   685			copy(data, ip.data)
   686			ip.data = data
   687		}
   688		ip.Size = int64(len(ip.data))
   689		return nil
   690	}
   691	
   692	func Truncate(path string, length int64) error {
   693		fsinit()
   694		fs.mu.Lock()
   695		defer fs.mu.Unlock()
   696		ip, _, err := fs.namei(path, false)
   697		if err != nil {
   698			return err
   699		}
   700		return fs.truncate(ip, length)
   701	}
   702	
   703	func Ftruncate(fd int, length int64) error {
   704		f, err := fdToFsysFile(fd)
   705		if err != nil {
   706			return err
   707		}
   708		f.fsys.mu.Lock()
   709		defer f.fsys.mu.Unlock()
   710		return f.fsys.truncate(f.inode, length)
   711	}
   712	
   713	func Chdir(path string) error {
   714		fsinit()
   715		return chdir(path)
   716	}
   717	
   718	func chdir(path string) error {
   719		fs.mu.Lock()
   720		defer fs.mu.Unlock()
   721		ip, _, err := fs.namei(path, false)
   722		if err != nil {
   723			return err
   724		}
   725		fs.cwd = ip
   726		return nil
   727	}
   728	
   729	func Fchdir(fd int) error {
   730		f, err := fdToFsysFile(fd)
   731		if err != nil {
   732			return err
   733		}
   734		f.fsys.mu.Lock()
   735		defer f.fsys.mu.Unlock()
   736		if f.inode.Mode&S_IFMT != S_IFDIR {
   737			return ENOTDIR
   738		}
   739		fs.cwd = f.inode
   740		return nil
   741	}
   742	
   743	func Readlink(path string, buf []byte) (n int, err error) {
   744		return 0, ENOSYS
   745	}
   746	
   747	func Symlink(path, link string) error {
   748		return ENOSYS
   749	}
   750	
   751	func Fsync(fd int) error {
   752		return nil
   753	}
   754	
   755	// Special devices.
   756	
   757	func mkdev(path string, mode uint32, open func() (devFile, error)) error {
   758		f, err := fs.open(path, O_CREATE|O_RDONLY|O_EXCL, S_IFCHR|mode)
   759		if err != nil {
   760			return err
   761		}
   762		ip := f.(*fsysFile).inode
   763		ip.Rdev = int64(len(fs.dev))
   764		fs.dev = append(fs.dev, open)
   765		return nil
   766	}
   767	
   768	type nullFile struct{}
   769	
   770	func openNull() (devFile, error)                               { return &nullFile{}, nil }
   771	func (f *nullFile) close() error                               { return nil }
   772	func (f *nullFile) pread(b []byte, offset int64) (int, error)  { return 0, nil }
   773	func (f *nullFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
   774	
   775	type zeroFile struct{}
   776	
   777	func openZero() (devFile, error)                               { return &zeroFile{}, nil }
   778	func (f *zeroFile) close() error                               { return nil }
   779	func (f *zeroFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
   780	
   781	func (f *zeroFile) pread(b []byte, offset int64) (int, error) {
   782		for i := range b {
   783			b[i] = 0
   784		}
   785		return len(b), nil
   786	}
   787	
   788	type randomFile struct{}
   789	
   790	func openRandom() (devFile, error) {
   791		return randomFile{}, nil
   792	}
   793	
   794	func (f randomFile) close() error {
   795		return nil
   796	}
   797	
   798	func (f randomFile) pread(b []byte, offset int64) (int, error) {
   799		if err := naclGetRandomBytes(b); err != nil {
   800			return 0, err
   801		}
   802		return len(b), nil
   803	}
   804	
   805	func (f randomFile) pwrite(b []byte, offset int64) (int, error) {
   806		return 0, EPERM
   807	}
   808	
   809	func fdToFsysFile(fd int) (*fsysFile, error) {
   810		f, err := fdToFile(fd)
   811		if err != nil {
   812			return nil, err
   813		}
   814		impl := f.impl
   815		fsysf, ok := impl.(*fsysFile)
   816		if !ok {
   817			return nil, EINVAL
   818		}
   819		return fsysf, nil
   820	}
   821	
   822	// create creates a file in the file system with the given name, mode, time, and data.
   823	// It is meant to be called when initializing the file system image.
   824	func create(name string, mode uint32, sec int64, data []byte) error {
   825		fs.mu.Lock()
   826		defer fs.mu.Unlock()
   827		f, err := fs.open(name, O_CREATE|O_EXCL, mode)
   828		if err != nil {
   829			if mode&S_IFMT == S_IFDIR {
   830				ip, _, err := fs.namei(name, false)
   831				if err == nil && (ip.Mode&S_IFMT) == S_IFDIR {
   832					return nil // directory already exists
   833				}
   834			}
   835			return err
   836		}
   837		ip := f.(*fsysFile).inode
   838		ip.Atime = sec
   839		ip.Mtime = sec
   840		ip.Ctime = sec
   841		if len(data) > 0 {
   842			ip.Size = int64(len(data))
   843			ip.data = data
   844		}
   845		return nil
   846	}
   847	

View as plain text