diff options
Diffstat (limited to 'pkg/sentry/fs/ramfs/ramfs.go')
-rw-r--r-- | pkg/sentry/fs/ramfs/ramfs.go | 441 |
1 files changed, 0 insertions, 441 deletions
diff --git a/pkg/sentry/fs/ramfs/ramfs.go b/pkg/sentry/fs/ramfs/ramfs.go deleted file mode 100644 index d77688a34..000000000 --- a/pkg/sentry/fs/ramfs/ramfs.go +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package ramfs implements an in-memory file system that can be associated with -// any device. -package ramfs - -import ( - "errors" - "sync" - "syscall" - - "gvisor.googlesource.com/gvisor/pkg/sentry/context" - "gvisor.googlesource.com/gvisor/pkg/sentry/fs" - "gvisor.googlesource.com/gvisor/pkg/sentry/fs/fsutil" - ktime "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/time" - "gvisor.googlesource.com/gvisor/pkg/sentry/memmap" - "gvisor.googlesource.com/gvisor/pkg/sentry/socket/unix/transport" - "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" - "gvisor.googlesource.com/gvisor/pkg/syserror" - "gvisor.googlesource.com/gvisor/pkg/waiter" -) - -var ( - // ErrInvalidOp indicates the operation is not valid. - ErrInvalidOp = errors.New("invalid operation") - - // ErrDenied indicates the operation was denied. - ErrDenied = errors.New("operation denied") - - // ErrNotFound indicates that a node was not found on a walk. - ErrNotFound = errors.New("node not found") - - // ErrCrossDevice indicates a cross-device link or rename. - ErrCrossDevice = errors.New("can't link across filesystems") - - // ErrIsDirectory indicates that the operation failed because - // the node is a directory. - ErrIsDirectory = errors.New("is a directory") - - // ErrNotDirectory indicates that the operation failed because - // the node is a not directory. - ErrNotDirectory = errors.New("not a directory") - - // ErrNotEmpty indicates that the operation failed because the - // directory is not empty. - ErrNotEmpty = errors.New("directory not empty") -) - -// Entry represents common internal state for file and directory nodes. -// This may be used by other packages to easily create ramfs files. -// -// +stateify savable -type Entry struct { - waiter.AlwaysReady `state:"nosave"` - fsutil.NoMappable `state:"nosave"` - fsutil.NoopWriteOut `state:"nosave"` - fsutil.InodeNotSocket `state:"nosave"` - - // mu protects the fields below. - mu sync.Mutex `state:"nosave"` - - // unstable is unstable attributes. - unstable fs.UnstableAttr - - // xattrs are the extended attributes of the Entry. - xattrs map[string][]byte -} - -// InitEntry initializes an entry. -func (e *Entry) InitEntry(ctx context.Context, owner fs.FileOwner, p fs.FilePermissions) { - e.InitEntryWithAttr(ctx, fs.WithCurrentTime(ctx, fs.UnstableAttr{ - Owner: owner, - Perms: p, - // Always start unlinked. - Links: 0, - })) -} - -// InitEntryWithAttr initializes an entry with a complete set of attributes. -func (e *Entry) InitEntryWithAttr(ctx context.Context, uattr fs.UnstableAttr) { - e.unstable = uattr - e.xattrs = make(map[string][]byte) -} - -// UnstableAttr implements fs.InodeOperations.UnstableAttr. -func (e *Entry) UnstableAttr(ctx context.Context, inode *fs.Inode) (fs.UnstableAttr, error) { - e.mu.Lock() - attr := e.unstable - e.mu.Unlock() - return attr, nil -} - -// Check implements fs.InodeOperations.Check. -func (*Entry) Check(ctx context.Context, inode *fs.Inode, p fs.PermMask) bool { - return fs.ContextCanAccessFile(ctx, inode, p) -} - -// Getxattr implements fs.InodeOperations.Getxattr. -func (e *Entry) Getxattr(inode *fs.Inode, name string) ([]byte, error) { - // Hot path. Avoid defers. - e.mu.Lock() - value, ok := e.xattrs[name] - e.mu.Unlock() - if ok { - return value, nil - } - return nil, syserror.ENOATTR -} - -// Setxattr implements fs.InodeOperations.Setxattr. -func (e *Entry) Setxattr(inode *fs.Inode, name string, value []byte) error { - e.mu.Lock() - e.xattrs[name] = value - e.mu.Unlock() - return nil -} - -// Listxattr implements fs.InodeOperations.Listxattr. -func (e *Entry) Listxattr(inode *fs.Inode) (map[string]struct{}, error) { - e.mu.Lock() - names := make(map[string]struct{}, len(e.xattrs)) - for name := range e.xattrs { - names[name] = struct{}{} - } - e.mu.Unlock() - return names, nil -} - -// GetFile returns a fs.File backed by the dirent argument and flags. -func (*Entry) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) (*fs.File, error) { - return fsutil.NewHandle(ctx, d, flags, d.Inode.HandleOps()), nil -} - -// SetPermissions always sets the permissions. -func (e *Entry) SetPermissions(ctx context.Context, inode *fs.Inode, p fs.FilePermissions) bool { - e.mu.Lock() - e.unstable.Perms = p - e.unstable.StatusChangeTime = ktime.NowFromContext(ctx) - e.mu.Unlock() - return true -} - -// SetOwner always sets ownership. -func (e *Entry) SetOwner(ctx context.Context, inode *fs.Inode, owner fs.FileOwner) error { - e.mu.Lock() - if owner.UID.Ok() { - e.unstable.Owner.UID = owner.UID - } - if owner.GID.Ok() { - e.unstable.Owner.GID = owner.GID - } - e.mu.Unlock() - return nil -} - -// SetTimestamps sets the timestamps. -func (e *Entry) SetTimestamps(ctx context.Context, inode *fs.Inode, ts fs.TimeSpec) error { - if ts.ATimeOmit && ts.MTimeOmit { - return nil - } - - e.mu.Lock() - now := ktime.NowFromContext(ctx) - if !ts.ATimeOmit { - if ts.ATimeSetSystemTime { - e.unstable.AccessTime = now - } else { - e.unstable.AccessTime = ts.ATime - } - } - if !ts.MTimeOmit { - if ts.MTimeSetSystemTime { - e.unstable.ModificationTime = now - } else { - e.unstable.ModificationTime = ts.MTime - } - } - e.unstable.StatusChangeTime = now - e.mu.Unlock() - return nil -} - -// NotifyStatusChange updates the status change time (ctime). -func (e *Entry) NotifyStatusChange(ctx context.Context) { - e.mu.Lock() - e.unstable.StatusChangeTime = ktime.NowFromContext(ctx) - e.mu.Unlock() -} - -// StatusChangeTime returns the last status change time for this node. -func (e *Entry) StatusChangeTime() ktime.Time { - e.mu.Lock() - t := e.unstable.StatusChangeTime - e.mu.Unlock() - return t -} - -// NotifyModification updates the modification time and the status change time. -func (e *Entry) NotifyModification(ctx context.Context) { - e.mu.Lock() - now := ktime.NowFromContext(ctx) - e.unstable.ModificationTime = now - e.unstable.StatusChangeTime = now - e.mu.Unlock() -} - -// ModificationTime returns the last modification time for this node. -func (e *Entry) ModificationTime() ktime.Time { - e.mu.Lock() - t := e.unstable.ModificationTime - e.mu.Unlock() - return t -} - -// NotifyAccess updates the access time. -func (e *Entry) NotifyAccess(ctx context.Context) { - e.mu.Lock() - now := ktime.NowFromContext(ctx) - e.unstable.AccessTime = now - e.mu.Unlock() -} - -// AccessTime returns the last access time for this node. -func (e *Entry) AccessTime() ktime.Time { - e.mu.Lock() - t := e.unstable.AccessTime - e.mu.Unlock() - return t -} - -// Permissions returns permissions on this entry. -func (e *Entry) Permissions() fs.FilePermissions { - e.mu.Lock() - p := e.unstable.Perms - e.mu.Unlock() - return p -} - -// Lookup is not supported by default. -func (*Entry) Lookup(context.Context, *fs.Inode, string) (*fs.Dirent, error) { - return nil, ErrInvalidOp -} - -// Create is not supported by default. -func (*Entry) Create(context.Context, *fs.Inode, string, fs.FileFlags, fs.FilePermissions) (*fs.File, error) { - return nil, ErrInvalidOp -} - -// CreateLink is not supported by default. -func (*Entry) CreateLink(context.Context, *fs.Inode, string, string) error { - return ErrInvalidOp -} - -// CreateHardLink is not supported by default. -func (*Entry) CreateHardLink(context.Context, *fs.Inode, *fs.Inode, string) error { - return ErrInvalidOp -} - -// IsVirtual returns true. -func (*Entry) IsVirtual() bool { - return true -} - -// CreateDirectory is not supported by default. -func (*Entry) CreateDirectory(context.Context, *fs.Inode, string, fs.FilePermissions) error { - return ErrInvalidOp -} - -// Bind is not supported by default. -func (*Entry) Bind(context.Context, *fs.Inode, string, transport.BoundEndpoint, fs.FilePermissions) (*fs.Dirent, error) { - return nil, ErrInvalidOp -} - -// CreateFifo implements fs.InodeOperations.CreateFifo. CreateFifo is not supported by -// default. -func (*Entry) CreateFifo(context.Context, *fs.Inode, string, fs.FilePermissions) error { - return ErrInvalidOp -} - -// Remove is not supported by default. -func (*Entry) Remove(context.Context, *fs.Inode, string) error { - return ErrInvalidOp -} - -// RemoveDirectory is not supported by default. -func (*Entry) RemoveDirectory(context.Context, *fs.Inode, string) error { - return ErrInvalidOp -} - -// StatFS always returns ENOSYS. -func (*Entry) StatFS(context.Context) (fs.Info, error) { - return fs.Info{}, syscall.ENOSYS -} - -// Rename implements fs.InodeOperations.Rename. -func (e *Entry) Rename(ctx context.Context, oldParent *fs.Inode, oldName string, newParent *fs.Inode, newName string) error { - return Rename(ctx, oldParent.InodeOperations, oldName, newParent.InodeOperations, newName) -} - -// Rename renames from a *ramfs.Dir to another *ramfs.Dir. -func Rename(ctx context.Context, oldParent fs.InodeOperations, oldName string, newParent fs.InodeOperations, newName string) error { - op, ok := oldParent.(*Dir) - if !ok { - return ErrCrossDevice - } - np, ok := newParent.(*Dir) - if !ok { - return ErrCrossDevice - } - - np.mu.Lock() - defer np.mu.Unlock() - - // Check whether the ramfs entry to be replaced is a non-empty directory. - if replaced, ok := np.children[newName]; ok { - if fs.IsDir(replaced.StableAttr) { - // FIXME: simplify by pinning children of ramfs-backed directories - // in the Dirent tree: this allows us to generalize ramfs operations without - // relying on an implementation of Readdir (which may do anything, like require - // that the file be open ... which would be reasonable). - dirCtx := &fs.DirCtx{} - _, err := replaced.HandleOps().DeprecatedReaddir(ctx, dirCtx, 0) - if err != nil { - return err - } - attrs := dirCtx.DentAttrs() - - // ramfs-backed directories should not contain "." and "..", but we do this - // just in case. - delete(attrs, ".") - delete(attrs, "..") - - // If the directory to be replaced is not empty, reject the rename. - if len(attrs) != 0 { - return ErrNotEmpty - } - } - } - - // Be careful, we may have already grabbed this mutex above. - if op != np { - op.mu.Lock() - defer op.mu.Unlock() - } - - // Do the swap. - n := op.children[oldName] - op.removeChildLocked(ctx, oldName) - np.addChildLocked(newName, n) - - // Update ctime. - n.NotifyStatusChange(ctx) - - return nil -} - -// Truncate is not supported by default. -func (*Entry) Truncate(context.Context, *fs.Inode, int64) error { - return ErrInvalidOp -} - -// Readlink always returns ENOLINK. -func (*Entry) Readlink(context.Context, *fs.Inode) (string, error) { - return "", syscall.ENOLINK -} - -// Getlink always returns ENOLINK. -func (*Entry) Getlink(context.Context, *fs.Inode) (*fs.Dirent, error) { - return nil, syscall.ENOLINK -} - -// Release is a no-op. -func (e *Entry) Release(context.Context) {} - -// AddLink implements InodeOperationss.AddLink. -func (e *Entry) AddLink() { - e.mu.Lock() - e.unstable.Links++ - e.mu.Unlock() -} - -// DropLink implements InodeOperationss.DropLink. -func (e *Entry) DropLink() { - e.mu.Lock() - e.unstable.Links-- - e.mu.Unlock() -} - -// DeprecatedReaddir is not supported by default. -func (*Entry) DeprecatedReaddir(context.Context, *fs.DirCtx, int) (int, error) { - return 0, ErrNotDirectory -} - -// DeprecatedPreadv always returns ErrInvalidOp. -func (*Entry) DeprecatedPreadv(context.Context, usermem.IOSequence, int64) (int64, error) { - return 0, ErrInvalidOp -} - -// DeprecatedPwritev always returns ErrInvalidOp. -func (*Entry) DeprecatedPwritev(context.Context, usermem.IOSequence, int64) (int64, error) { - return 0, ErrInvalidOp -} - -// DeprecatedFsync is a noop. -func (*Entry) DeprecatedFsync() error { - // Ignore, this is in memory. - return nil -} - -// DeprecatedFlush always returns nil. -func (*Entry) DeprecatedFlush() error { - return nil -} - -// DeprecatedMappable implements fs.InodeOperations.DeprecatedMappable. -func (*Entry) DeprecatedMappable(context.Context, *fs.Inode) (memmap.Mappable, bool) { - return nil, false -} - -func init() { - // Register ramfs errors. - syserror.AddErrorTranslation(ErrInvalidOp, syscall.EINVAL) - syserror.AddErrorTranslation(ErrDenied, syscall.EACCES) - syserror.AddErrorTranslation(ErrNotFound, syscall.ENOENT) - syserror.AddErrorTranslation(ErrCrossDevice, syscall.EXDEV) - syserror.AddErrorTranslation(ErrIsDirectory, syscall.EISDIR) - syserror.AddErrorTranslation(ErrNotDirectory, syscall.ENOTDIR) - syserror.AddErrorTranslation(ErrNotEmpty, syscall.ENOTEMPTY) -} |