mirror of
https://github.com/rwinkhart/sys.git
synced 2026-09-05 16:47:27 -04:00
go.sys: copy files from syscall package to go.sys/{plan9,windows,unix}
This CL copies to each package of go.sys the files from syscall it will need.
Different directories have different files, but these:
mkall.sh
str.go
syscall.go
mksyscall.pl
race.go
race0.go
syscall_test.go
are copied to all three.
No changes yet, these are just copies. They are not ready to use yet:
package names are wrong, for starters. But this clean copy will make
it easier to follow the changes as the packages are enabled.
LGTM=rsc
R=golang-codereviews, rsc
CC=golang-codereviews
https://golang.org/cl/126960043
This commit is contained in:
+832
@@ -0,0 +1,832 @@
|
||||
// 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()
|
||||
var fsinit = func() {}
|
||||
|
||||
func init() {
|
||||
// do not trigger loading of zipped file system here
|
||||
oldFsinit := fsinit
|
||||
defer func() { fsinit = oldFsinit }()
|
||||
fsinit = func() {}
|
||||
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 true, 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) {
|
||||
fsinit()
|
||||
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 {
|
||||
fsinit()
|
||||
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 {
|
||||
fsinit()
|
||||
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 {
|
||||
fsinit()
|
||||
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 {
|
||||
fsinit()
|
||||
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
|
||||
}
|
||||
fsinit()
|
||||
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 {
|
||||
fsinit()
|
||||
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 {
|
||||
fsinit()
|
||||
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 {
|
||||
fsinit()
|
||||
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 {
|
||||
fsinit()
|
||||
return chdir(path)
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user