summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/ramfs/ramfs.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/fs/ramfs/ramfs.go')
-rw-r--r--pkg/sentry/fs/ramfs/ramfs.go441
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)
-}