381 lines
12 KiB
Go
381 lines
12 KiB
Go
// Copyright 2018 Google Inc.
|
|
//
|
|
// 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 fsutil
|
|
|
|
import (
|
|
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
|
|
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
|
|
ktime "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/time"
|
|
"gvisor.googlesource.com/gvisor/pkg/sentry/memmap"
|
|
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
|
|
"gvisor.googlesource.com/gvisor/pkg/syserror"
|
|
"gvisor.googlesource.com/gvisor/pkg/tcpip/transport/unix"
|
|
"gvisor.googlesource.com/gvisor/pkg/waiter"
|
|
)
|
|
|
|
// NewSimpleInodeOperations constructs fs.InodeOperations from InodeSimpleAttributes.
|
|
func NewSimpleInodeOperations(i InodeSimpleAttributes) fs.InodeOperations {
|
|
return &simpleInodeOperations{InodeSimpleAttributes: i}
|
|
}
|
|
|
|
// simpleInodeOperations is a simple implementation of Inode.
|
|
type simpleInodeOperations struct {
|
|
DeprecatedFileOperations `state:"nosave"`
|
|
InodeNotDirectory `state:"nosave"`
|
|
InodeNotSocket `state:"nosave"`
|
|
InodeNotRenameable `state:"nosave"`
|
|
InodeNotOpenable `state:"nosave"`
|
|
InodeNotVirtual `state:"nosave"`
|
|
InodeNotSymlink `state:"nosave"`
|
|
InodeNoExtendedAttributes `state:"nosave"`
|
|
NoMappable `state:"nosave"`
|
|
NoopWriteOut `state:"nosave"`
|
|
|
|
InodeSimpleAttributes
|
|
}
|
|
|
|
// InodeSimpleAttributes implements a subset of the Inode interface. It provides
|
|
// read-only access to attributes.
|
|
type InodeSimpleAttributes struct {
|
|
// FSType is the filesystem type reported by StatFS.
|
|
FSType uint64
|
|
|
|
// UAttr are the unstable attributes of the Inode.
|
|
UAttr fs.UnstableAttr
|
|
}
|
|
|
|
// Release implements fs.InodeOperations.Release.
|
|
func (i *InodeSimpleAttributes) Release(context.Context) {}
|
|
|
|
// StatFS implements fs.InodeOperations.StatFS.
|
|
func (i *InodeSimpleAttributes) StatFS(context.Context) (fs.Info, error) {
|
|
return fs.Info{Type: i.FSType}, nil
|
|
}
|
|
|
|
// UnstableAttr implements fs.InodeOperations.UnstableAttr.
|
|
func (i *InodeSimpleAttributes) UnstableAttr(context.Context, *fs.Inode) (fs.UnstableAttr, error) {
|
|
return i.UAttr, nil
|
|
}
|
|
|
|
// Check implements fs.InodeOperations.Check.
|
|
func (i *InodeSimpleAttributes) Check(ctx context.Context, inode *fs.Inode, p fs.PermMask) bool {
|
|
return fs.ContextCanAccessFile(ctx, inode, p)
|
|
}
|
|
|
|
// AddLink implements fs.InodeOperations.AddLink.
|
|
func (*InodeSimpleAttributes) AddLink() {}
|
|
|
|
// DropLink implements fs.InodeOperations.DropLink.
|
|
func (*InodeSimpleAttributes) DropLink() {}
|
|
|
|
// NotifyStatusChange implements fs.fs.InodeOperations.
|
|
func (i *InodeSimpleAttributes) NotifyStatusChange(ctx context.Context) {
|
|
i.UAttr.StatusChangeTime = ktime.NowFromContext(ctx)
|
|
}
|
|
|
|
// SetPermissions implements fs.InodeOperations.SetPermissions.
|
|
func (*InodeSimpleAttributes) SetPermissions(context.Context, *fs.Inode, fs.FilePermissions) bool {
|
|
return false
|
|
}
|
|
|
|
// SetOwner implements fs.InodeOperations.SetOwner.
|
|
func (*InodeSimpleAttributes) SetOwner(context.Context, *fs.Inode, fs.FileOwner) error {
|
|
return syserror.EINVAL
|
|
}
|
|
|
|
// SetTimestamps implements fs.InodeOperations.SetTimestamps.
|
|
func (*InodeSimpleAttributes) SetTimestamps(context.Context, *fs.Inode, fs.TimeSpec) error {
|
|
return syserror.EINVAL
|
|
}
|
|
|
|
// Truncate implements fs.InodeOperations.Truncate.
|
|
func (*InodeSimpleAttributes) Truncate(context.Context, *fs.Inode, int64) error {
|
|
return syserror.EINVAL
|
|
}
|
|
|
|
// InMemoryAttributes implements utilities for updating in-memory unstable
|
|
// attributes and extended attributes. It is not thread-safe.
|
|
//
|
|
// Users need not initialize Xattrs to non-nil (it will be initialized
|
|
// when the first extended attribute is set.
|
|
type InMemoryAttributes struct {
|
|
Unstable fs.UnstableAttr
|
|
Xattrs map[string][]byte
|
|
}
|
|
|
|
// SetPermissions updates the permissions to p.
|
|
func (i *InMemoryAttributes) SetPermissions(ctx context.Context, p fs.FilePermissions) bool {
|
|
i.Unstable.Perms = p
|
|
i.Unstable.StatusChangeTime = ktime.NowFromContext(ctx)
|
|
return true
|
|
}
|
|
|
|
// SetOwner updates the file owner to owner.
|
|
func (i *InMemoryAttributes) SetOwner(ctx context.Context, owner fs.FileOwner) error {
|
|
if owner.UID.Ok() {
|
|
i.Unstable.Owner.UID = owner.UID
|
|
}
|
|
if owner.GID.Ok() {
|
|
i.Unstable.Owner.GID = owner.GID
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SetTimestamps sets the timestamps to ts.
|
|
func (i *InMemoryAttributes) SetTimestamps(ctx context.Context, ts fs.TimeSpec) error {
|
|
if ts.ATimeOmit && ts.MTimeOmit {
|
|
return nil
|
|
}
|
|
|
|
now := ktime.NowFromContext(ctx)
|
|
if !ts.ATimeOmit {
|
|
if ts.ATimeSetSystemTime {
|
|
i.Unstable.AccessTime = now
|
|
} else {
|
|
i.Unstable.AccessTime = ts.ATime
|
|
}
|
|
}
|
|
if !ts.MTimeOmit {
|
|
if ts.MTimeSetSystemTime {
|
|
i.Unstable.ModificationTime = now
|
|
} else {
|
|
i.Unstable.ModificationTime = ts.MTime
|
|
}
|
|
}
|
|
i.Unstable.StatusChangeTime = now
|
|
return nil
|
|
}
|
|
|
|
// TouchAccessTime updates access time to the current time.
|
|
func (i *InMemoryAttributes) TouchAccessTime(ctx context.Context) {
|
|
i.Unstable.AccessTime = ktime.NowFromContext(ctx)
|
|
}
|
|
|
|
// TouchModificationTime updates modification and status change
|
|
// time to the current time.
|
|
func (i *InMemoryAttributes) TouchModificationTime(ctx context.Context) {
|
|
now := ktime.NowFromContext(ctx)
|
|
i.Unstable.ModificationTime = now
|
|
i.Unstable.StatusChangeTime = now
|
|
}
|
|
|
|
// TouchStatusChangeTime updates status change time to the current time.
|
|
func (i *InMemoryAttributes) TouchStatusChangeTime(ctx context.Context) {
|
|
i.Unstable.StatusChangeTime = ktime.NowFromContext(ctx)
|
|
}
|
|
|
|
// Getxattr returns the extended attribute at name or ENOATTR if
|
|
// it isn't set.
|
|
func (i *InMemoryAttributes) Getxattr(name string) ([]byte, error) {
|
|
if value, ok := i.Xattrs[name]; ok {
|
|
return value, nil
|
|
}
|
|
return nil, syserror.ENOATTR
|
|
}
|
|
|
|
// Setxattr sets the extended attribute at name to value.
|
|
func (i *InMemoryAttributes) Setxattr(name string, value []byte) error {
|
|
if i.Xattrs == nil {
|
|
i.Xattrs = make(map[string][]byte)
|
|
}
|
|
i.Xattrs[name] = value
|
|
return nil
|
|
}
|
|
|
|
// Listxattr returns the set of all currently set extended attributes.
|
|
func (i *InMemoryAttributes) Listxattr() (map[string]struct{}, error) {
|
|
names := make(map[string]struct{}, len(i.Xattrs))
|
|
for name := range i.Xattrs {
|
|
names[name] = struct{}{}
|
|
}
|
|
return names, nil
|
|
}
|
|
|
|
// NoMappable returns a nil memmap.Mappable.
|
|
type NoMappable struct{}
|
|
|
|
// Mappable implements fs.InodeOperations.Mappable.
|
|
func (NoMappable) Mappable(*fs.Inode) memmap.Mappable {
|
|
return nil
|
|
}
|
|
|
|
// NoopWriteOut is a no-op implementation of Inode.WriteOut.
|
|
type NoopWriteOut struct{}
|
|
|
|
// WriteOut is a no-op.
|
|
func (NoopWriteOut) WriteOut(context.Context, *fs.Inode) error {
|
|
return nil
|
|
}
|
|
|
|
// InodeNotDirectory can be used by Inodes that are not directories.
|
|
type InodeNotDirectory struct{}
|
|
|
|
// Lookup implements fs.InodeOperations.Lookup.
|
|
func (InodeNotDirectory) Lookup(context.Context, *fs.Inode, string) (*fs.Dirent, error) {
|
|
return nil, syserror.ENOTDIR
|
|
}
|
|
|
|
// Create implements fs.InodeOperations.Create.
|
|
func (InodeNotDirectory) Create(context.Context, *fs.Inode, string, fs.FileFlags, fs.FilePermissions) (*fs.File, error) {
|
|
return nil, syserror.ENOTDIR
|
|
}
|
|
|
|
// CreateLink implements fs.InodeOperations.CreateLink.
|
|
func (InodeNotDirectory) CreateLink(context.Context, *fs.Inode, string, string) error {
|
|
return syserror.ENOTDIR
|
|
}
|
|
|
|
// CreateHardLink implements fs.InodeOperations.CreateHardLink.
|
|
func (InodeNotDirectory) CreateHardLink(context.Context, *fs.Inode, *fs.Inode, string) error {
|
|
return syserror.ENOTDIR
|
|
}
|
|
|
|
// CreateDirectory implements fs.InodeOperations.CreateDirectory.
|
|
func (InodeNotDirectory) CreateDirectory(context.Context, *fs.Inode, string, fs.FilePermissions) error {
|
|
return syserror.ENOTDIR
|
|
}
|
|
|
|
// Bind implements fs.InodeOperations.Bind.
|
|
func (InodeNotDirectory) Bind(context.Context, *fs.Inode, string, unix.BoundEndpoint, fs.FilePermissions) error {
|
|
return syserror.ENOTDIR
|
|
}
|
|
|
|
// CreateFifo implements fs.InodeOperations.CreateFifo.
|
|
func (InodeNotDirectory) CreateFifo(context.Context, *fs.Inode, string, fs.FilePermissions) error {
|
|
return syserror.ENOTDIR
|
|
}
|
|
|
|
// Remove implements fs.InodeOperations.Remove.
|
|
func (InodeNotDirectory) Remove(context.Context, *fs.Inode, string) error {
|
|
return syserror.ENOTDIR
|
|
}
|
|
|
|
// RemoveDirectory implements fs.InodeOperations.RemoveDirectory.
|
|
func (InodeNotDirectory) RemoveDirectory(context.Context, *fs.Inode, string) error {
|
|
return syserror.ENOTDIR
|
|
}
|
|
|
|
// InodeNotSocket can be used by Inodes that are not sockets.
|
|
type InodeNotSocket struct{}
|
|
|
|
// BoundEndpoint implements fs.InodeOperations.BoundEndpoint.
|
|
func (InodeNotSocket) BoundEndpoint(*fs.Inode, string) unix.BoundEndpoint {
|
|
return nil
|
|
}
|
|
|
|
// InodeNotRenameable can be used by Inodes that cannot be renamed.
|
|
type InodeNotRenameable struct{}
|
|
|
|
// Rename implements fs.InodeOperations.Rename.
|
|
func (InodeNotRenameable) Rename(context.Context, *fs.Inode, string, *fs.Inode, string) error {
|
|
return syserror.EINVAL
|
|
}
|
|
|
|
// InodeNotOpenable can be used by Inodes that cannot be opened.
|
|
type InodeNotOpenable struct{}
|
|
|
|
// GetFile implements fs.InodeOperations.GetFile.
|
|
func (InodeNotOpenable) GetFile(context.Context, *fs.Dirent, fs.FileFlags) (*fs.File, error) {
|
|
return nil, syserror.EIO
|
|
}
|
|
|
|
// InodeNotVirtual can be used by Inodes that are not virtual.
|
|
type InodeNotVirtual struct{}
|
|
|
|
// IsVirtual implements fs.InodeOperations.IsVirtual.
|
|
func (InodeNotVirtual) IsVirtual() bool {
|
|
return false
|
|
}
|
|
|
|
// InodeNotSymlink can be used by Inodes that are not symlinks.
|
|
type InodeNotSymlink struct{}
|
|
|
|
// Readlink implements fs.InodeOperations.Readlink.
|
|
func (InodeNotSymlink) Readlink(context.Context, *fs.Inode) (string, error) {
|
|
return "", syserror.ENOLINK
|
|
}
|
|
|
|
// Getlink implements fs.InodeOperations.Getlink.
|
|
func (InodeNotSymlink) Getlink(context.Context, *fs.Inode) (*fs.Dirent, error) {
|
|
return nil, syserror.ENOLINK
|
|
}
|
|
|
|
// InodeNoExtendedAttributes can be used by Inodes that do not support
|
|
// extended attributes.
|
|
type InodeNoExtendedAttributes struct{}
|
|
|
|
// Getxattr implements fs.InodeOperations.Getxattr.
|
|
func (InodeNoExtendedAttributes) Getxattr(*fs.Inode, string) ([]byte, error) {
|
|
return nil, syserror.EOPNOTSUPP
|
|
}
|
|
|
|
// Setxattr implements fs.InodeOperations.Setxattr.
|
|
func (InodeNoExtendedAttributes) Setxattr(*fs.Inode, string, []byte) error {
|
|
return syserror.EOPNOTSUPP
|
|
}
|
|
|
|
// Listxattr implements fs.InodeOperations.Listxattr.
|
|
func (InodeNoExtendedAttributes) Listxattr(*fs.Inode) (map[string]struct{}, error) {
|
|
return nil, syserror.EOPNOTSUPP
|
|
}
|
|
|
|
// DeprecatedFileOperations panics if any deprecated Inode method is called.
|
|
type DeprecatedFileOperations struct{}
|
|
|
|
// Readiness implements fs.InodeOperations.Waitable.Readiness.
|
|
func (DeprecatedFileOperations) Readiness(waiter.EventMask) waiter.EventMask {
|
|
panic("not implemented")
|
|
}
|
|
|
|
// EventRegister implements fs.InodeOperations.Waitable.EventRegister.
|
|
func (DeprecatedFileOperations) EventRegister(*waiter.Entry, waiter.EventMask) {
|
|
panic("not implemented")
|
|
}
|
|
|
|
// EventUnregister implements fs.InodeOperations.Waitable.EventUnregister.
|
|
func (DeprecatedFileOperations) EventUnregister(*waiter.Entry) {
|
|
panic("not implemented")
|
|
}
|
|
|
|
// DeprecatedPreadv implements fs.InodeOperations.DeprecatedPreadv.
|
|
func (DeprecatedFileOperations) DeprecatedPreadv(context.Context, usermem.IOSequence, int64) (int64, error) {
|
|
panic("not implemented")
|
|
}
|
|
|
|
// DeprecatedPwritev implements fs.InodeOperations.DeprecatedPwritev.
|
|
func (DeprecatedFileOperations) DeprecatedPwritev(context.Context, usermem.IOSequence, int64) (int64, error) {
|
|
panic("not implemented")
|
|
}
|
|
|
|
// DeprecatedReaddir implements fs.InodeOperations.DeprecatedReaddir.
|
|
func (DeprecatedFileOperations) DeprecatedReaddir(context.Context, *fs.DirCtx, int) (int, error) {
|
|
panic("not implemented")
|
|
}
|
|
|
|
// DeprecatedFsync implements fs.InodeOperations.DeprecatedFsync.
|
|
func (DeprecatedFileOperations) DeprecatedFsync() error {
|
|
panic("not implemented")
|
|
}
|
|
|
|
// DeprecatedFlush implements fs.InodeOperations.DeprecatedFlush.
|
|
func (DeprecatedFileOperations) DeprecatedFlush() error {
|
|
panic("not implemented")
|
|
}
|
|
|
|
// DeprecatedMappable implements fs.InodeOperations.DeprecatedMappable.
|
|
func (DeprecatedFileOperations) DeprecatedMappable(context.Context, *fs.Inode) (memmap.Mappable, bool) {
|
|
panic("not implemented")
|
|
}
|