diff options
Diffstat (limited to 'src/pkg/syscall/fs_nacl.go')
-rw-r--r-- | src/pkg/syscall/fs_nacl.go | 815 |
1 files changed, 0 insertions, 815 deletions
diff --git a/src/pkg/syscall/fs_nacl.go b/src/pkg/syscall/fs_nacl.go deleted file mode 100644 index ac9239483..000000000 --- a/src/pkg/syscall/fs_nacl.go +++ /dev/null @@ -1,815 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// A simulated Unix-like file system for use within NaCl. -// -// The simulation is not particularly tied to NaCl other than the reuse -// of NaCl's definition for the Stat_t structure. -// -// The file system need never be written to disk, so it is represented as -// in-memory Go data structures, never in a serialized form. -// -// TODO: Perhaps support symlinks, although they muck everything up. - -package syscall - -import ( - "sync" - "unsafe" -) - -// Provided by package runtime. -func now() (sec int64, nsec int32) - -// An fsys is a file system. -// Since there is no I/O (everything is in memory), -// the global lock mu protects the whole file system state, -// and that's okay. -type fsys struct { - mu sync.Mutex - root *inode // root directory - cwd *inode // process current directory - inum uint64 // number of inodes created - dev []func() (devFile, error) // table for opening devices -} - -// A devFile is the implementation required of device files -// like /dev/null or /dev/random. -type devFile interface { - pread([]byte, int64) (int, error) - pwrite([]byte, int64) (int, error) -} - -// An inode is a (possibly special) file in the file system. -type inode struct { - Stat_t - data []byte - dir []dirent -} - -// A dirent describes a single directory entry. -type dirent struct { - name string - inode *inode -} - -// An fsysFile is the fileImpl implementation backed by the file system. -type fsysFile struct { - defaultFileImpl - fsys *fsys - inode *inode - openmode int - offset int64 - dev devFile -} - -// newFsys creates a new file system. -func newFsys() *fsys { - fs := &fsys{} - fs.mu.Lock() - defer fs.mu.Unlock() - ip := fs.newInode() - ip.Mode = 0555 | S_IFDIR - fs.dirlink(ip, ".", ip) - fs.dirlink(ip, "..", ip) - fs.cwd = ip - fs.root = ip - return fs -} - -var fs = newFsys() - -func init() { - Mkdir("/dev", 0555) - Mkdir("/tmp", 0777) - mkdev("/dev/null", 0666, openNull) - mkdev("/dev/random", 0444, openRandom) - mkdev("/dev/urandom", 0444, openRandom) - mkdev("/dev/zero", 0666, openZero) - chdirEnv() -} - -func chdirEnv() { - pwd, ok := Getenv("NACLPWD") - if ok { - Chdir(pwd) - } -} - -// Except where indicated otherwise, unexported methods on fsys -// expect fs.mu to have been locked by the caller. - -// newInode creates a new inode. -func (fs *fsys) newInode() *inode { - fs.inum++ - ip := &inode{ - Stat_t: Stat_t{ - Ino: fs.inum, - Blksize: 512, - }, - } - return ip -} - -// atime sets ip.Atime to the current time. -func (fs *fsys) atime(ip *inode) { - sec, nsec := now() - ip.Atime, ip.AtimeNsec = sec, int64(nsec) -} - -// mtime sets ip.Mtime to the current time. -func (fs *fsys) mtime(ip *inode) { - sec, nsec := now() - ip.Mtime, ip.MtimeNsec = sec, int64(nsec) -} - -// dirlookup looks for an entry in the directory dp with the given name. -// It returns the directory entry and its index within the directory. -func (fs *fsys) dirlookup(dp *inode, name string) (de *dirent, index int, err error) { - fs.atime(dp) - for i := range dp.dir { - de := &dp.dir[i] - if de.name == name { - fs.atime(de.inode) - return de, i, nil - } - } - return nil, 0, ENOENT -} - -// dirlink adds to the directory dp an entry for name pointing at the inode ip. -// If dp already contains an entry for name, that entry is overwritten. -func (fs *fsys) dirlink(dp *inode, name string, ip *inode) { - fs.mtime(dp) - fs.atime(ip) - ip.Nlink++ - for i := range dp.dir { - if dp.dir[i].name == name { - dp.dir[i] = dirent{name, ip} - return - } - } - dp.dir = append(dp.dir, dirent{name, ip}) - dp.dirSize() -} - -func (dp *inode) dirSize() { - dp.Size = int64(len(dp.dir)) * (8 + 8 + 2 + 256) // Dirent -} - -// skipelem splits path into the first element and the remainder. -// the returned first element contains no slashes, and the returned -// remainder does not begin with a slash. -func skipelem(path string) (elem, rest string) { - for len(path) > 0 && path[0] == '/' { - path = path[1:] - } - if len(path) == 0 { - return "", "" - } - i := 0 - for i < len(path) && path[i] != '/' { - i++ - } - elem, path = path[:i], path[i:] - for len(path) > 0 && path[0] == '/' { - path = path[1:] - } - return elem, path -} - -// namei translates a file system path name into an inode. -// If parent is false, the returned ip corresponds to the given name, and elem is the empty string. -// If parent is false, the walk stops at the next-to-last element in the name, -// so that ip is the parent directory and elem is the final element in the path. -func (fs *fsys) namei(path string, parent bool) (ip *inode, elem string, err error) { - // Reject NUL in name. - for i := 0; i < len(path); i++ { - if path[i] == '\x00' { - return nil, "", EINVAL - } - } - - // Reject empty name. - if path == "" { - return nil, "", EINVAL - } - - if path[0] == '/' { - ip = fs.root - } else { - ip = fs.cwd - } - - for len(path) > 0 && path[len(path)-1] == '/' { - path = path[:len(path)-1] - } - - for { - elem, rest := skipelem(path) - if elem == "" { - if parent && ip.Mode&S_IFMT == S_IFDIR { - return ip, ".", nil - } - break - } - if ip.Mode&S_IFMT != S_IFDIR { - return nil, "", ENOTDIR - } - if len(elem) >= 256 { - return nil, "", ENAMETOOLONG - } - if parent && rest == "" { - // Stop one level early. - return ip, elem, nil - } - de, _, err := fs.dirlookup(ip, elem) - if err != nil { - return nil, "", err - } - ip = de.inode - path = rest - } - if parent { - return nil, "", ENOTDIR - } - return ip, "", nil -} - -// open opens or creates a file with the given name, open mode, -// and permission mode bits. -func (fs *fsys) open(name string, openmode int, mode uint32) (fileImpl, error) { - dp, elem, err := fs.namei(name, true) - if err != nil { - return nil, err - } - var ( - ip *inode - dev devFile - ) - de, _, err := fs.dirlookup(dp, elem) - if err != nil { - if openmode&O_CREATE == 0 { - return nil, err - } - ip = fs.newInode() - ip.Mode = mode - fs.dirlink(dp, elem, ip) - if ip.Mode&S_IFMT == S_IFDIR { - fs.dirlink(ip, ".", ip) - fs.dirlink(ip, "..", dp) - } - } else { - ip = de.inode - if openmode&(O_CREATE|O_EXCL) == O_CREATE|O_EXCL { - return nil, EEXIST - } - if openmode&O_TRUNC != 0 { - if ip.Mode&S_IFMT == S_IFDIR { - return nil, EISDIR - } - ip.data = nil - } - if ip.Mode&S_IFMT == S_IFCHR { - if ip.Rdev < 0 || ip.Rdev >= int64(len(fs.dev)) || fs.dev[ip.Rdev] == nil { - return nil, ENODEV - } - dev, err = fs.dev[ip.Rdev]() - if err != nil { - return nil, err - } - } - } - - switch openmode & O_ACCMODE { - case O_WRONLY, O_RDWR: - if ip.Mode&S_IFMT == S_IFDIR { - return nil, EISDIR - } - } - - switch ip.Mode & S_IFMT { - case S_IFDIR: - if openmode&O_ACCMODE != O_RDONLY { - return nil, EISDIR - } - - case S_IFREG: - // ok - - case S_IFCHR: - // handled above - - default: - // TODO: some kind of special file - return nil, EPERM - } - - f := &fsysFile{ - fsys: fs, - inode: ip, - openmode: openmode, - dev: dev, - } - if openmode&O_APPEND != 0 { - f.offset = ip.Size - } - return f, nil -} - -// fsysFile methods to implement fileImpl. - -func (f *fsysFile) stat(st *Stat_t) error { - f.fsys.mu.Lock() - defer f.fsys.mu.Unlock() - *st = f.inode.Stat_t - return nil -} - -func (f *fsysFile) read(b []byte) (int, error) { - f.fsys.mu.Lock() - defer f.fsys.mu.Unlock() - n, err := f.preadLocked(b, f.offset) - f.offset += int64(n) - return n, err -} - -func ReadDirent(fd int, buf []byte) (int, error) { - f, err := fdToFsysFile(fd) - if err != nil { - return 0, err - } - f.fsys.mu.Lock() - defer f.fsys.mu.Unlock() - if f.inode.Mode&S_IFMT != S_IFDIR { - return 0, EINVAL - } - n, err := f.preadLocked(buf, f.offset) - f.offset += int64(n) - return n, err -} - -func (f *fsysFile) write(b []byte) (int, error) { - f.fsys.mu.Lock() - defer f.fsys.mu.Unlock() - n, err := f.pwriteLocked(b, f.offset) - f.offset += int64(n) - return n, err -} - -func (f *fsysFile) seek(offset int64, whence int) (int64, error) { - f.fsys.mu.Lock() - defer f.fsys.mu.Unlock() - switch whence { - case 1: - offset += f.offset - case 2: - offset += f.inode.Size - } - if offset < 0 { - return 0, EINVAL - } - if offset > f.inode.Size { - return 0, EINVAL - } - f.offset = offset - return offset, nil -} - -func (f *fsysFile) pread(b []byte, offset int64) (int, error) { - f.fsys.mu.Lock() - defer f.fsys.mu.Unlock() - return f.preadLocked(b, offset) -} - -func (f *fsysFile) pwrite(b []byte, offset int64) (int, error) { - f.fsys.mu.Lock() - defer f.fsys.mu.Unlock() - return f.pwriteLocked(b, offset) -} - -func (f *fsysFile) preadLocked(b []byte, offset int64) (int, error) { - if f.openmode&O_ACCMODE == O_WRONLY { - return 0, EINVAL - } - if offset < 0 { - return 0, EINVAL - } - if f.dev != nil { - f.fsys.atime(f.inode) - f.fsys.mu.Unlock() - defer f.fsys.mu.Lock() - return f.dev.pread(b, offset) - } - if offset > f.inode.Size { - return 0, nil - } - if int64(len(b)) > f.inode.Size-offset { - b = b[:f.inode.Size-offset] - } - - if f.inode.Mode&S_IFMT == S_IFDIR { - if offset%direntSize != 0 || len(b) != 0 && len(b) < direntSize { - return 0, EINVAL - } - fs.atime(f.inode) - n := 0 - for len(b) >= direntSize { - src := f.inode.dir[int(offset/direntSize)] - dst := (*Dirent)(unsafe.Pointer(&b[0])) - dst.Ino = int64(src.inode.Ino) - dst.Off = offset - dst.Reclen = direntSize - for i := range dst.Name { - dst.Name[i] = 0 - } - copy(dst.Name[:], src.name) - n += direntSize - offset += direntSize - b = b[direntSize:] - } - return n, nil - } - - fs.atime(f.inode) - n := copy(b, f.inode.data[offset:]) - return n, nil -} - -func (f *fsysFile) pwriteLocked(b []byte, offset int64) (int, error) { - if f.openmode&O_ACCMODE == O_RDONLY { - return 0, EINVAL - } - if offset < 0 { - return 0, EINVAL - } - if f.dev != nil { - f.fsys.atime(f.inode) - f.fsys.mu.Unlock() - defer f.fsys.mu.Lock() - return f.dev.pwrite(b, offset) - } - if offset > f.inode.Size { - return 0, EINVAL - } - f.fsys.mtime(f.inode) - n := copy(f.inode.data[offset:], b) - if n < len(b) { - f.inode.data = append(f.inode.data, b[n:]...) - f.inode.Size = int64(len(f.inode.data)) - } - return len(b), nil -} - -// Standard Unix system calls. - -func Open(path string, openmode int, perm uint32) (fd int, err error) { - fs.mu.Lock() - defer fs.mu.Unlock() - f, err := fs.open(path, openmode, perm&0777|S_IFREG) - if err != nil { - return -1, err - } - return newFD(f), nil -} - -func Mkdir(path string, perm uint32) error { - fs.mu.Lock() - defer fs.mu.Unlock() - _, err := fs.open(path, O_CREATE|O_EXCL, perm&0777|S_IFDIR) - return err -} - -func Getcwd(buf []byte) (n int, err error) { - // Force package os to default to the old algorithm using .. and directory reads. - return 0, ENOSYS -} - -func Stat(path string, st *Stat_t) error { - fs.mu.Lock() - defer fs.mu.Unlock() - ip, _, err := fs.namei(path, false) - if err != nil { - return err - } - *st = ip.Stat_t - return nil -} - -func Lstat(path string, st *Stat_t) error { - return Stat(path, st) -} - -func unlink(path string, isdir bool) error { - fs.mu.Lock() - defer fs.mu.Unlock() - dp, elem, err := fs.namei(path, true) - if err != nil { - return err - } - if elem == "." || elem == ".." { - return EINVAL - } - de, _, err := fs.dirlookup(dp, elem) - if err != nil { - return err - } - if isdir { - if de.inode.Mode&S_IFMT != S_IFDIR { - return ENOTDIR - } - if len(de.inode.dir) != 2 { - return ENOTEMPTY - } - } else { - if de.inode.Mode&S_IFMT == S_IFDIR { - return EISDIR - } - } - de.inode.Nlink-- - *de = dp.dir[len(dp.dir)-1] - dp.dir = dp.dir[:len(dp.dir)-1] - dp.dirSize() - return nil -} - -func Unlink(path string) error { - return unlink(path, false) -} - -func Rmdir(path string) error { - return unlink(path, true) -} - -func Chmod(path string, mode uint32) error { - fs.mu.Lock() - defer fs.mu.Unlock() - ip, _, err := fs.namei(path, false) - if err != nil { - return err - } - ip.Mode = ip.Mode&^0777 | mode&0777 - return nil -} - -func Fchmod(fd int, mode uint32) error { - f, err := fdToFsysFile(fd) - if err != nil { - return err - } - f.fsys.mu.Lock() - defer f.fsys.mu.Unlock() - f.inode.Mode = f.inode.Mode&^0777 | mode&0777 - return nil -} - -func Chown(path string, uid, gid int) error { - fs.mu.Lock() - defer fs.mu.Unlock() - ip, _, err := fs.namei(path, false) - if err != nil { - return err - } - ip.Uid = uint32(uid) - ip.Gid = uint32(gid) - return nil -} - -func Fchown(fd int, uid, gid int) error { - fs.mu.Lock() - defer fs.mu.Unlock() - f, err := fdToFsysFile(fd) - if err != nil { - return err - } - f.fsys.mu.Lock() - defer f.fsys.mu.Unlock() - f.inode.Uid = uint32(uid) - f.inode.Gid = uint32(gid) - return nil -} - -func Lchown(path string, uid, gid int) error { - return Chown(path, uid, gid) -} - -func UtimesNano(path string, ts []Timespec) error { - if len(ts) != 2 { - return EINVAL - } - fs.mu.Lock() - defer fs.mu.Unlock() - ip, _, err := fs.namei(path, false) - if err != nil { - return err - } - ip.Atime = ts[0].Sec - ip.AtimeNsec = int64(ts[0].Nsec) - ip.Mtime = ts[1].Sec - ip.MtimeNsec = int64(ts[1].Nsec) - return nil -} - -func Link(path, link string) error { - ip, _, err := fs.namei(path, false) - if err != nil { - return err - } - dp, elem, err := fs.namei(link, true) - if err != nil { - return err - } - if ip.Mode&S_IFMT == S_IFDIR { - return EPERM - } - fs.dirlink(dp, elem, ip) - return nil -} - -func Rename(from, to string) error { - fdp, felem, err := fs.namei(from, true) - if err != nil { - return err - } - fde, _, err := fs.dirlookup(fdp, felem) - if err != nil { - return err - } - tdp, telem, err := fs.namei(to, true) - if err != nil { - return err - } - fs.dirlink(tdp, telem, fde.inode) - fde.inode.Nlink-- - *fde = fdp.dir[len(fdp.dir)-1] - fdp.dir = fdp.dir[:len(fdp.dir)-1] - fdp.dirSize() - return nil -} - -func (fs *fsys) truncate(ip *inode, length int64) error { - if length > 1e9 || ip.Mode&S_IFMT != S_IFREG { - return EINVAL - } - if length < int64(len(ip.data)) { - ip.data = ip.data[:length] - } else { - data := make([]byte, length) - copy(data, ip.data) - ip.data = data - } - ip.Size = int64(len(ip.data)) - return nil -} - -func Truncate(path string, length int64) error { - fs.mu.Lock() - defer fs.mu.Unlock() - ip, _, err := fs.namei(path, false) - if err != nil { - return err - } - return fs.truncate(ip, length) -} - -func Ftruncate(fd int, length int64) error { - f, err := fdToFsysFile(fd) - if err != nil { - return err - } - f.fsys.mu.Lock() - defer f.fsys.mu.Unlock() - return f.fsys.truncate(f.inode, length) -} - -func Chdir(path string) error { - fs.mu.Lock() - defer fs.mu.Unlock() - ip, _, err := fs.namei(path, false) - if err != nil { - return err - } - fs.cwd = ip - return nil -} - -func Fchdir(fd int) error { - f, err := fdToFsysFile(fd) - if err != nil { - return err - } - f.fsys.mu.Lock() - defer f.fsys.mu.Unlock() - if f.inode.Mode&S_IFMT != S_IFDIR { - return ENOTDIR - } - fs.cwd = f.inode - return nil -} - -func Readlink(path string, buf []byte) (n int, err error) { - return 0, ENOSYS -} - -func Symlink(path, link string) error { - return ENOSYS -} - -func Fsync(fd int) error { - return nil -} - -// Special devices. - -func mkdev(path string, mode uint32, open func() (devFile, error)) error { - fs.mu.Lock() - fs.mu.Unlock() - f, err := fs.open(path, O_CREATE|O_RDONLY|O_EXCL, S_IFCHR|mode) - if err != nil { - return err - } - ip := f.(*fsysFile).inode - ip.Rdev = int64(len(fs.dev)) - fs.dev = append(fs.dev, open) - return nil -} - -type nullFile struct{} - -func openNull() (devFile, error) { return &nullFile{}, nil } -func (f *nullFile) close() error { return nil } -func (f *nullFile) pread(b []byte, offset int64) (int, error) { return 0, nil } -func (f *nullFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil } - -type zeroFile struct{} - -func openZero() (devFile, error) { return &zeroFile{}, nil } -func (f *zeroFile) close() error { return nil } -func (f *zeroFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil } - -func (f *zeroFile) pread(b []byte, offset int64) (int, error) { - for i := range b { - b[i] = 0 - } - return len(b), nil -} - -type randomFile struct { - naclFD int -} - -func openRandom() (devFile, error) { - fd, err := openNamedService("SecureRandom", O_RDONLY) - if err != nil { - return nil, err - } - return &randomFile{naclFD: fd}, nil -} - -func (f *randomFile) close() error { - naclClose(f.naclFD) - f.naclFD = -1 - return nil -} - -func (f *randomFile) pread(b []byte, offset int64) (int, error) { - return naclRead(f.naclFD, b) -} - -func (f *randomFile) pwrite(b []byte, offset int64) (int, error) { - return 0, EPERM -} - -func fdToFsysFile(fd int) (*fsysFile, error) { - f, err := fdToFile(fd) - if err != nil { - return nil, err - } - impl := f.impl - fsysf, ok := impl.(*fsysFile) - if !ok { - return nil, EINVAL - } - return fsysf, nil -} - -// create creates a file in the file system with the given name, mode, time, and data. -// It is meant to be called when initializing the file system image. -func create(name string, mode uint32, sec int64, data []byte) error { - fs.mu.Lock() - fs.mu.Unlock() - f, err := fs.open(name, O_CREATE|O_EXCL, mode) - if err != nil { - return err - } - ip := f.(*fsysFile).inode - ip.Atime = sec - ip.Mtime = sec - ip.Ctime = sec - if len(data) > 0 { - ip.Size = int64(len(data)) - ip.data = data - } - return nil -} |