summaryrefslogtreecommitdiff
path: root/src/pkg/syscall/fs_nacl.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/syscall/fs_nacl.go')
-rw-r--r--src/pkg/syscall/fs_nacl.go815
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
-}