github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/inode_operations.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package fs
    16  
    17  import (
    18  	"errors"
    19  
    20  	"github.com/SagerNet/gvisor/pkg/context"
    21  	ktime "github.com/SagerNet/gvisor/pkg/sentry/kernel/time"
    22  	"github.com/SagerNet/gvisor/pkg/sentry/memmap"
    23  	"github.com/SagerNet/gvisor/pkg/sentry/socket/unix/transport"
    24  )
    25  
    26  var (
    27  	// ErrResolveViaReadlink is a special error value returned by
    28  	// InodeOperations.Getlink() to indicate that a link should be
    29  	// resolved automatically by walking to the path returned by
    30  	// InodeOperations.Readlink().
    31  	ErrResolveViaReadlink = errors.New("link should be resolved via Readlink()")
    32  )
    33  
    34  // TimeSpec contains access and modification timestamps. If either ATimeOmit or
    35  // MTimeOmit is true, then the corresponding timestamp should not be updated.
    36  // If either ATimeSetSystemTime or MTimeSetSystemTime are set then the
    37  // corresponding timestamp should be ignored and the time will be set to the
    38  // current system time.
    39  type TimeSpec struct {
    40  	ATime              ktime.Time
    41  	ATimeOmit          bool
    42  	ATimeSetSystemTime bool
    43  	MTime              ktime.Time
    44  	MTimeOmit          bool
    45  	MTimeSetSystemTime bool
    46  }
    47  
    48  // InodeOperations are operations on an Inode that diverge per file system.
    49  //
    50  // Objects that implement InodeOperations may cache file system "private"
    51  // data that is useful for implementing these methods. In contrast, Inode
    52  // contains state that is common to all Inodes; this state may be optionally
    53  // used by InodeOperations. An object that implements InodeOperations may
    54  // not take a reference on an Inode.
    55  type InodeOperations interface {
    56  	// Release releases all private file system data held by this object.
    57  	// Once Release is called, this object is dead (no other methods will
    58  	// ever be called).
    59  	Release(context.Context)
    60  
    61  	// Lookup loads an Inode at name under dir into a Dirent. The name
    62  	// is a valid component path: it contains no "/"s nor is the empty
    63  	// string.
    64  	//
    65  	// Lookup may return one of:
    66  	//
    67  	// * A nil Dirent and a non-nil error. If the reason that Lookup failed
    68  	//   was because the name does not exist under Inode, then must return
    69  	//   syserror.ENOENT.
    70  	//
    71  	// * If name does not exist under dir and the file system wishes this
    72  	//   fact to be cached, a non-nil Dirent containing a nil Inode and a
    73  	//   nil error. This is a negative Dirent and must have exactly one
    74  	//   reference (at-construction reference).
    75  	//
    76  	// * If name does exist under this dir, a non-nil Dirent containing a
    77  	//   non-nil Inode, and a nil error. File systems that take extra
    78  	//   references on this Dirent should implement DirentOperations.
    79  	Lookup(ctx context.Context, dir *Inode, name string) (*Dirent, error)
    80  
    81  	// Create creates an Inode at name under dir and returns a new File
    82  	// whose Dirent backs the new Inode. Implementations must ensure that
    83  	// name does not already exist. Create may return one of:
    84  	//
    85  	// * A nil File and a non-nil error.
    86  	//
    87  	// * A non-nil File and a nil error. File.Dirent will be a new Dirent,
    88  	// with a single reference held by File. File systems that take extra
    89  	// references on this Dirent should implement DirentOperations.
    90  	//
    91  	// The caller must ensure that this operation is permitted.
    92  	Create(ctx context.Context, dir *Inode, name string, flags FileFlags, perm FilePermissions) (*File, error)
    93  
    94  	// CreateDirectory creates a new directory under this dir.
    95  	// CreateDirectory should otherwise do the same as Create.
    96  	//
    97  	// The caller must ensure that this operation is permitted.
    98  	CreateDirectory(ctx context.Context, dir *Inode, name string, perm FilePermissions) error
    99  
   100  	// CreateLink creates a symbolic link under dir between newname
   101  	// and oldname. CreateLink should otherwise do the same as Create.
   102  	//
   103  	// The caller must ensure that this operation is permitted.
   104  	CreateLink(ctx context.Context, dir *Inode, oldname string, newname string) error
   105  
   106  	// CreateHardLink creates a hard link under dir between the target
   107  	// Inode and name.
   108  	//
   109  	// The caller must ensure this operation is permitted.
   110  	CreateHardLink(ctx context.Context, dir *Inode, target *Inode, name string) error
   111  
   112  	// CreateFifo creates a new named pipe under dir at name.
   113  	//
   114  	// The caller must ensure that this operation is permitted.
   115  	CreateFifo(ctx context.Context, dir *Inode, name string, perm FilePermissions) error
   116  
   117  	// Remove removes the given named non-directory under dir.
   118  	//
   119  	// The caller must ensure that this operation is permitted.
   120  	Remove(ctx context.Context, dir *Inode, name string) error
   121  
   122  	// RemoveDirectory removes the given named directory under dir.
   123  	//
   124  	// The caller must ensure that this operation is permitted.
   125  	//
   126  	// RemoveDirectory should check that the directory to be
   127  	// removed is empty.
   128  	RemoveDirectory(ctx context.Context, dir *Inode, name string) error
   129  
   130  	// Rename atomically renames oldName under oldParent to newName under
   131  	// newParent where oldParent and newParent are directories. inode is
   132  	// the Inode of this InodeOperations.
   133  	//
   134  	// If replacement is true, then newName already exists and this call
   135  	// will replace it with oldName.
   136  	//
   137  	// Implementations are responsible for rejecting renames that replace
   138  	// non-empty directories.
   139  	Rename(ctx context.Context, inode *Inode, oldParent *Inode, oldName string, newParent *Inode, newName string, replacement bool) error
   140  
   141  	// Bind binds a new socket under dir at the given name.
   142  	//
   143  	// The caller must ensure that this operation is permitted.
   144  	Bind(ctx context.Context, dir *Inode, name string, data transport.BoundEndpoint, perm FilePermissions) (*Dirent, error)
   145  
   146  	// BoundEndpoint returns the socket endpoint at path stored in
   147  	// or generated by an Inode.
   148  	//
   149  	// The path is only relevant for generated endpoint because stored
   150  	// endpoints already know their path. It is ok for the endpoint to
   151  	// hold onto their path because the only way to change a bind
   152  	// address is to rebind the socket.
   153  	//
   154  	// This is valid iff the type of the Inode is a Socket, which
   155  	// generally implies that this Inode was created via CreateSocket.
   156  	//
   157  	// If there is no socket endpoint available, nil will be returned.
   158  	BoundEndpoint(inode *Inode, path string) transport.BoundEndpoint
   159  
   160  	// GetFile returns a new open File backed by a Dirent and FileFlags.
   161  	//
   162  	// Special Inode types may block using ctx.Sleeper. RegularFiles,
   163  	// Directories, and Symlinks must not block (see doCopyUp).
   164  	//
   165  	// The returned File will uniquely back an application fd.
   166  	GetFile(ctx context.Context, d *Dirent, flags FileFlags) (*File, error)
   167  
   168  	// UnstableAttr returns the most up-to-date "unstable" attributes of
   169  	// an Inode, where "unstable" means that they change in response to
   170  	// file system events.
   171  	UnstableAttr(ctx context.Context, inode *Inode) (UnstableAttr, error)
   172  
   173  	// GetXattr retrieves the value of extended attribute specified by name.
   174  	// Inodes that do not support extended attributes return EOPNOTSUPP. Inodes
   175  	// that support extended attributes but don't have a value at name return
   176  	// ENODATA.
   177  	//
   178  	// If this is called through the getxattr(2) syscall, size indicates the
   179  	// size of the buffer that the application has allocated to hold the
   180  	// attribute value. If the value is larger than size, implementations may
   181  	// return ERANGE to indicate that the buffer is too small, but they are also
   182  	// free to ignore the hint entirely (i.e. the value returned may be larger
   183  	// than size). All size checking is done independently at the syscall layer.
   184  	GetXattr(ctx context.Context, inode *Inode, name string, size uint64) (string, error)
   185  
   186  	// SetXattr sets the value of extended attribute specified by name. Inodes
   187  	// that do not support extended attributes return EOPNOTSUPP.
   188  	SetXattr(ctx context.Context, inode *Inode, name, value string, flags uint32) error
   189  
   190  	// ListXattr returns the set of all extended attributes names that
   191  	// have values. Inodes that do not support extended attributes return
   192  	// EOPNOTSUPP.
   193  	//
   194  	// If this is called through the listxattr(2) syscall, size indicates the
   195  	// size of the buffer that the application has allocated to hold the
   196  	// attribute list. If the list would be larger than size, implementations may
   197  	// return ERANGE to indicate that the buffer is too small, but they are also
   198  	// free to ignore the hint entirely. All size checking is done independently
   199  	// at the syscall layer.
   200  	ListXattr(ctx context.Context, inode *Inode, size uint64) (map[string]struct{}, error)
   201  
   202  	// RemoveXattr removes an extended attribute specified by name. Inodes that
   203  	// do not support extended attributes return EOPNOTSUPP.
   204  	RemoveXattr(ctx context.Context, inode *Inode, name string) error
   205  
   206  	// Check determines whether an Inode can be accessed with the
   207  	// requested permission mask using the context (which gives access
   208  	// to Credentials and UserNamespace).
   209  	Check(ctx context.Context, inode *Inode, p PermMask) bool
   210  
   211  	// SetPermissions sets new permissions for an Inode.  Returns false
   212  	// if it was not possible to set the new permissions.
   213  	//
   214  	// The caller must ensure that this operation is permitted.
   215  	SetPermissions(ctx context.Context, inode *Inode, f FilePermissions) bool
   216  
   217  	// SetOwner sets the ownership for this file.
   218  	//
   219  	// If either UID or GID are set to auth.NoID, its value will not be
   220  	// changed.
   221  	//
   222  	// The caller must ensure that this operation is permitted.
   223  	SetOwner(ctx context.Context, inode *Inode, owner FileOwner) error
   224  
   225  	// SetTimestamps sets the access and modification timestamps of an
   226  	// Inode according to the access and modification times in the TimeSpec.
   227  	//
   228  	// If either ATimeOmit or MTimeOmit is set, then the corresponding
   229  	// timestamp is not updated.
   230  	//
   231  	// If either ATimeSetSystemTime or MTimeSetSystemTime is true, that
   232  	// timestamp is set to the current time instead.
   233  	//
   234  	// The caller must ensure that this operation is permitted.
   235  	SetTimestamps(ctx context.Context, inode *Inode, ts TimeSpec) error
   236  
   237  	// Truncate changes the size of an Inode. Truncate should not check
   238  	// permissions internally, as it is used for both sys_truncate and
   239  	// sys_ftruncate.
   240  	//
   241  	// Implementations need not check that length >= 0.
   242  	Truncate(ctx context.Context, inode *Inode, size int64) error
   243  
   244  	// Allocate allows the caller to reserve disk space for the inode.
   245  	// It's equivalent to fallocate(2) with 'mode=0'.
   246  	Allocate(ctx context.Context, inode *Inode, offset int64, length int64) error
   247  
   248  	// WriteOut writes cached Inode state to a backing filesystem in a
   249  	// synchronous manner.
   250  	//
   251  	// File systems that do not cache metadata or data via an Inode
   252  	// implement WriteOut as a no-op. File systems that are entirely in
   253  	// memory also implement WriteOut as a no-op. Otherwise file systems
   254  	// call Inode.Sync to write back page cached data and cached metadata
   255  	// followed by syncing writeback handles.
   256  	//
   257  	// It derives from include/linux/fs.h:super_operations->write_inode.
   258  	WriteOut(ctx context.Context, inode *Inode) error
   259  
   260  	// Readlink reads the symlink path of an Inode.
   261  	//
   262  	// Readlink is permitted to return a different path depending on ctx,
   263  	// the request originator.
   264  	//
   265  	// The caller must ensure that this operation is permitted.
   266  	//
   267  	// Readlink should check that Inode is a symlink and its content is
   268  	// at least readable.
   269  	Readlink(ctx context.Context, inode *Inode) (string, error)
   270  
   271  	// Getlink resolves a symlink to a target *Dirent.
   272  	//
   273  	// Filesystems that can resolve the link by walking to the path returned
   274  	// by Readlink should return (nil, ErrResolveViaReadlink), which
   275  	// triggers link resolution via Realink and Lookup.
   276  	//
   277  	// Some links cannot be followed by Lookup. In this case, Getlink can
   278  	// return the Dirent of the link target. The caller holds a reference
   279  	// to the Dirent. Filesystems that return a non-nil *Dirent from Getlink
   280  	// cannot participate in an overlay because it is impossible for the
   281  	// overlay to ascertain whether or not the *Dirent should contain an
   282  	// overlayEntry.
   283  	//
   284  	// Any error returned from Getlink other than ErrResolveViaReadlink
   285  	// indicates the caller's inability to traverse this Inode as a link
   286  	// (e.g. linuxerr.ENOLINK indicates that the Inode is not a link,
   287  	// syscall.EPERM indicates that traversing the link is not allowed, etc).
   288  	Getlink(context.Context, *Inode) (*Dirent, error)
   289  
   290  	// Mappable returns a memmap.Mappable that provides memory mappings of the
   291  	// Inode's data. Mappable may return nil if this is not supported. The
   292  	// returned Mappable must remain valid until InodeOperations.Release is
   293  	// called.
   294  	Mappable(*Inode) memmap.Mappable
   295  
   296  	// The below methods require cleanup.
   297  
   298  	// AddLink increments the hard link count of an Inode.
   299  	//
   300  	// Remove in favor of Inode.IncLink.
   301  	AddLink()
   302  
   303  	// DropLink decrements the hard link count of an Inode.
   304  	//
   305  	// Remove in favor of Inode.DecLink.
   306  	DropLink()
   307  
   308  	// NotifyStatusChange sets the status change time to the current time.
   309  	//
   310  	// Remove in favor of updating the Inode's cached status change time.
   311  	NotifyStatusChange(ctx context.Context)
   312  
   313  	// IsVirtual indicates whether or not this corresponds to a virtual
   314  	// resource.
   315  	//
   316  	// If IsVirtual returns true, then caching will be disabled for this
   317  	// node, and fs.Dirent.Freeze() will not stop operations on the node.
   318  	//
   319  	// Remove in favor of freezing specific mounts.
   320  	IsVirtual() bool
   321  
   322  	// StatFS returns a filesystem Info implementation or an error.  If
   323  	// the filesystem does not support this operation (maybe in the future
   324  	// it will), then ENOSYS should be returned.
   325  	StatFS(context.Context) (Info, error)
   326  }