github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/kernfs/inode_impl_util.go (about)

     1  // Copyright 2019 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 kernfs
    16  
    17  import (
    18  	"fmt"
    19  	"sync/atomic"
    20  
    21  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    22  	"github.com/SagerNet/gvisor/pkg/context"
    23  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    24  	"github.com/SagerNet/gvisor/pkg/hostarch"
    25  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/auth"
    26  	ktime "github.com/SagerNet/gvisor/pkg/sentry/kernel/time"
    27  	"github.com/SagerNet/gvisor/pkg/sentry/vfs"
    28  	"github.com/SagerNet/gvisor/pkg/sync"
    29  	"github.com/SagerNet/gvisor/pkg/syserror"
    30  )
    31  
    32  // InodeNoopRefCount partially implements the Inode interface, specifically the
    33  // inodeRefs sub interface. InodeNoopRefCount implements a simple reference
    34  // count for inodes, performing no extra actions when references are obtained or
    35  // released. This is suitable for simple file inodes that don't reference any
    36  // resources.
    37  //
    38  // +stateify savable
    39  type InodeNoopRefCount struct {
    40  	InodeTemporary
    41  }
    42  
    43  // IncRef implements Inode.IncRef.
    44  func (InodeNoopRefCount) IncRef() {
    45  }
    46  
    47  // DecRef implements Inode.DecRef.
    48  func (InodeNoopRefCount) DecRef(context.Context) {
    49  }
    50  
    51  // TryIncRef implements Inode.TryIncRef.
    52  func (InodeNoopRefCount) TryIncRef() bool {
    53  	return true
    54  }
    55  
    56  // InodeDirectoryNoNewChildren partially implements the Inode interface.
    57  // InodeDirectoryNoNewChildren represents a directory inode which does not
    58  // support creation of new children.
    59  //
    60  // +stateify savable
    61  type InodeDirectoryNoNewChildren struct{}
    62  
    63  // NewFile implements Inode.NewFile.
    64  func (InodeDirectoryNoNewChildren) NewFile(context.Context, string, vfs.OpenOptions) (Inode, error) {
    65  	return nil, linuxerr.EPERM
    66  }
    67  
    68  // NewDir implements Inode.NewDir.
    69  func (InodeDirectoryNoNewChildren) NewDir(context.Context, string, vfs.MkdirOptions) (Inode, error) {
    70  	return nil, linuxerr.EPERM
    71  }
    72  
    73  // NewLink implements Inode.NewLink.
    74  func (InodeDirectoryNoNewChildren) NewLink(context.Context, string, Inode) (Inode, error) {
    75  	return nil, linuxerr.EPERM
    76  }
    77  
    78  // NewSymlink implements Inode.NewSymlink.
    79  func (InodeDirectoryNoNewChildren) NewSymlink(context.Context, string, string) (Inode, error) {
    80  	return nil, linuxerr.EPERM
    81  }
    82  
    83  // NewNode implements Inode.NewNode.
    84  func (InodeDirectoryNoNewChildren) NewNode(context.Context, string, vfs.MknodOptions) (Inode, error) {
    85  	return nil, linuxerr.EPERM
    86  }
    87  
    88  // InodeNotDirectory partially implements the Inode interface, specifically the
    89  // inodeDirectory and inodeDynamicDirectory sub interfaces. Inodes that do not
    90  // represent directories can embed this to provide no-op implementations for
    91  // directory-related functions.
    92  //
    93  // +stateify savable
    94  type InodeNotDirectory struct {
    95  	InodeAlwaysValid
    96  }
    97  
    98  // HasChildren implements Inode.HasChildren.
    99  func (InodeNotDirectory) HasChildren() bool {
   100  	return false
   101  }
   102  
   103  // NewFile implements Inode.NewFile.
   104  func (InodeNotDirectory) NewFile(context.Context, string, vfs.OpenOptions) (Inode, error) {
   105  	panic("NewFile called on non-directory inode")
   106  }
   107  
   108  // NewDir implements Inode.NewDir.
   109  func (InodeNotDirectory) NewDir(context.Context, string, vfs.MkdirOptions) (Inode, error) {
   110  	panic("NewDir called on non-directory inode")
   111  }
   112  
   113  // NewLink implements Inode.NewLinkink.
   114  func (InodeNotDirectory) NewLink(context.Context, string, Inode) (Inode, error) {
   115  	panic("NewLink called on non-directory inode")
   116  }
   117  
   118  // NewSymlink implements Inode.NewSymlink.
   119  func (InodeNotDirectory) NewSymlink(context.Context, string, string) (Inode, error) {
   120  	panic("NewSymlink called on non-directory inode")
   121  }
   122  
   123  // NewNode implements Inode.NewNode.
   124  func (InodeNotDirectory) NewNode(context.Context, string, vfs.MknodOptions) (Inode, error) {
   125  	panic("NewNode called on non-directory inode")
   126  }
   127  
   128  // Unlink implements Inode.Unlink.
   129  func (InodeNotDirectory) Unlink(context.Context, string, Inode) error {
   130  	panic("Unlink called on non-directory inode")
   131  }
   132  
   133  // RmDir implements Inode.RmDir.
   134  func (InodeNotDirectory) RmDir(context.Context, string, Inode) error {
   135  	panic("RmDir called on non-directory inode")
   136  }
   137  
   138  // Rename implements Inode.Rename.
   139  func (InodeNotDirectory) Rename(context.Context, string, string, Inode, Inode) error {
   140  	panic("Rename called on non-directory inode")
   141  }
   142  
   143  // Lookup implements Inode.Lookup.
   144  func (InodeNotDirectory) Lookup(ctx context.Context, name string) (Inode, error) {
   145  	panic("Lookup called on non-directory inode")
   146  }
   147  
   148  // IterDirents implements Inode.IterDirents.
   149  func (InodeNotDirectory) IterDirents(ctx context.Context, mnt *vfs.Mount, callback vfs.IterDirentsCallback, offset, relOffset int64) (newOffset int64, err error) {
   150  	panic("IterDirents called on non-directory inode")
   151  }
   152  
   153  // InodeNotSymlink partially implements the Inode interface, specifically the
   154  // inodeSymlink sub interface. All inodes that are not symlinks may embed this
   155  // to return the appropriate errors from symlink-related functions.
   156  //
   157  // +stateify savable
   158  type InodeNotSymlink struct{}
   159  
   160  // Readlink implements Inode.Readlink.
   161  func (InodeNotSymlink) Readlink(context.Context, *vfs.Mount) (string, error) {
   162  	return "", linuxerr.EINVAL
   163  }
   164  
   165  // Getlink implements Inode.Getlink.
   166  func (InodeNotSymlink) Getlink(context.Context, *vfs.Mount) (vfs.VirtualDentry, string, error) {
   167  	return vfs.VirtualDentry{}, "", linuxerr.EINVAL
   168  }
   169  
   170  // InodeAttrs partially implements the Inode interface, specifically the
   171  // inodeMetadata sub interface. InodeAttrs provides functionality related to
   172  // inode attributes.
   173  //
   174  // Must be initialized by Init prior to first use.
   175  //
   176  // +stateify savable
   177  type InodeAttrs struct {
   178  	devMajor  uint32
   179  	devMinor  uint32
   180  	ino       uint64
   181  	mode      uint32
   182  	uid       uint32
   183  	gid       uint32
   184  	nlink     uint32
   185  	blockSize uint32
   186  
   187  	// Timestamps, all nsecs from the Unix epoch.
   188  	atime int64
   189  	mtime int64
   190  	ctime int64
   191  }
   192  
   193  // Init initializes this InodeAttrs.
   194  func (a *InodeAttrs) Init(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, mode linux.FileMode) {
   195  	if mode.FileType() == 0 {
   196  		panic(fmt.Sprintf("No file type specified in 'mode' for InodeAttrs.Init(): mode=0%o", mode))
   197  	}
   198  
   199  	nlink := uint32(1)
   200  	if mode.FileType() == linux.ModeDirectory {
   201  		nlink = 2
   202  	}
   203  	a.devMajor = devMajor
   204  	a.devMinor = devMinor
   205  	atomic.StoreUint64(&a.ino, ino)
   206  	atomic.StoreUint32(&a.mode, uint32(mode))
   207  	atomic.StoreUint32(&a.uid, uint32(creds.EffectiveKUID))
   208  	atomic.StoreUint32(&a.gid, uint32(creds.EffectiveKGID))
   209  	atomic.StoreUint32(&a.nlink, nlink)
   210  	atomic.StoreUint32(&a.blockSize, hostarch.PageSize)
   211  	now := ktime.NowFromContext(ctx).Nanoseconds()
   212  	atomic.StoreInt64(&a.atime, now)
   213  	atomic.StoreInt64(&a.mtime, now)
   214  	atomic.StoreInt64(&a.ctime, now)
   215  }
   216  
   217  // DevMajor returns the device major number.
   218  func (a *InodeAttrs) DevMajor() uint32 {
   219  	return a.devMajor
   220  }
   221  
   222  // DevMinor returns the device minor number.
   223  func (a *InodeAttrs) DevMinor() uint32 {
   224  	return a.devMinor
   225  }
   226  
   227  // Ino returns the inode id.
   228  func (a *InodeAttrs) Ino() uint64 {
   229  	return atomic.LoadUint64(&a.ino)
   230  }
   231  
   232  // Mode implements Inode.Mode.
   233  func (a *InodeAttrs) Mode() linux.FileMode {
   234  	return linux.FileMode(atomic.LoadUint32(&a.mode))
   235  }
   236  
   237  // TouchAtime updates a.atime to the current time.
   238  func (a *InodeAttrs) TouchAtime(ctx context.Context, mnt *vfs.Mount) {
   239  	if mnt.Flags.NoATime || mnt.ReadOnly() {
   240  		return
   241  	}
   242  	if err := mnt.CheckBeginWrite(); err != nil {
   243  		return
   244  	}
   245  	atomic.StoreInt64(&a.atime, ktime.NowFromContext(ctx).Nanoseconds())
   246  	mnt.EndWrite()
   247  }
   248  
   249  // TouchCMtime updates a.{c/m}time to the current time. The caller should
   250  // synchronize calls to this so that ctime and mtime are updated to the same
   251  // value.
   252  func (a *InodeAttrs) TouchCMtime(ctx context.Context) {
   253  	now := ktime.NowFromContext(ctx).Nanoseconds()
   254  	atomic.StoreInt64(&a.mtime, now)
   255  	atomic.StoreInt64(&a.ctime, now)
   256  }
   257  
   258  // Stat partially implements Inode.Stat. Note that this function doesn't provide
   259  // all the stat fields, and the embedder should consider extending the result
   260  // with filesystem-specific fields.
   261  func (a *InodeAttrs) Stat(context.Context, *vfs.Filesystem, vfs.StatOptions) (linux.Statx, error) {
   262  	var stat linux.Statx
   263  	stat.Mask = linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_UID | linux.STATX_GID | linux.STATX_INO | linux.STATX_NLINK | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME
   264  	stat.DevMajor = a.devMajor
   265  	stat.DevMinor = a.devMinor
   266  	stat.Ino = atomic.LoadUint64(&a.ino)
   267  	stat.Mode = uint16(a.Mode())
   268  	stat.UID = atomic.LoadUint32(&a.uid)
   269  	stat.GID = atomic.LoadUint32(&a.gid)
   270  	stat.Nlink = atomic.LoadUint32(&a.nlink)
   271  	stat.Blksize = atomic.LoadUint32(&a.blockSize)
   272  	stat.Atime = linux.NsecToStatxTimestamp(atomic.LoadInt64(&a.atime))
   273  	stat.Mtime = linux.NsecToStatxTimestamp(atomic.LoadInt64(&a.mtime))
   274  	stat.Ctime = linux.NsecToStatxTimestamp(atomic.LoadInt64(&a.ctime))
   275  	return stat, nil
   276  }
   277  
   278  // SetStat implements Inode.SetStat.
   279  func (a *InodeAttrs) SetStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
   280  	if opts.Stat.Mask == 0 {
   281  		return nil
   282  	}
   283  
   284  	// Note that not all fields are modifiable. For example, the file type and
   285  	// inode numbers are immutable after node creation. Setting the size is often
   286  	// allowed by kernfs files but does not do anything. If some other behavior is
   287  	// needed, the embedder should consider extending SetStat.
   288  	if opts.Stat.Mask&^(linux.STATX_MODE|linux.STATX_UID|linux.STATX_GID|linux.STATX_ATIME|linux.STATX_MTIME|linux.STATX_SIZE) != 0 {
   289  		return linuxerr.EPERM
   290  	}
   291  	if opts.Stat.Mask&linux.STATX_SIZE != 0 && a.Mode().IsDir() {
   292  		return syserror.EISDIR
   293  	}
   294  	if err := vfs.CheckSetStat(ctx, creds, &opts, a.Mode(), auth.KUID(atomic.LoadUint32(&a.uid)), auth.KGID(atomic.LoadUint32(&a.gid))); err != nil {
   295  		return err
   296  	}
   297  
   298  	clearSID := false
   299  	stat := opts.Stat
   300  	if stat.Mask&linux.STATX_UID != 0 {
   301  		atomic.StoreUint32(&a.uid, stat.UID)
   302  		clearSID = true
   303  	}
   304  	if stat.Mask&linux.STATX_GID != 0 {
   305  		atomic.StoreUint32(&a.gid, stat.GID)
   306  		clearSID = true
   307  	}
   308  	if stat.Mask&linux.STATX_MODE != 0 {
   309  		for {
   310  			old := atomic.LoadUint32(&a.mode)
   311  			ft := old & linux.S_IFMT
   312  			newMode := ft | uint32(stat.Mode & ^uint16(linux.S_IFMT))
   313  			if clearSID {
   314  				newMode = vfs.ClearSUIDAndSGID(newMode)
   315  			}
   316  			if swapped := atomic.CompareAndSwapUint32(&a.mode, old, newMode); swapped {
   317  				clearSID = false
   318  				break
   319  			}
   320  		}
   321  	}
   322  
   323  	// We may have to clear the SUID/SGID bits, but didn't do so as part of
   324  	// STATX_MODE.
   325  	if clearSID {
   326  		for {
   327  			old := atomic.LoadUint32(&a.mode)
   328  			newMode := vfs.ClearSUIDAndSGID(old)
   329  			if swapped := atomic.CompareAndSwapUint32(&a.mode, old, newMode); swapped {
   330  				break
   331  			}
   332  		}
   333  	}
   334  
   335  	now := ktime.NowFromContext(ctx).Nanoseconds()
   336  	if stat.Mask&linux.STATX_ATIME != 0 {
   337  		if stat.Atime.Nsec == linux.UTIME_NOW {
   338  			stat.Atime = linux.NsecToStatxTimestamp(now)
   339  		}
   340  		atomic.StoreInt64(&a.atime, stat.Atime.ToNsec())
   341  	}
   342  	if stat.Mask&linux.STATX_MTIME != 0 {
   343  		if stat.Mtime.Nsec == linux.UTIME_NOW {
   344  			stat.Mtime = linux.NsecToStatxTimestamp(now)
   345  		}
   346  		atomic.StoreInt64(&a.mtime, stat.Mtime.ToNsec())
   347  	}
   348  
   349  	return nil
   350  }
   351  
   352  // CheckPermissions implements Inode.CheckPermissions.
   353  func (a *InodeAttrs) CheckPermissions(_ context.Context, creds *auth.Credentials, ats vfs.AccessTypes) error {
   354  	return vfs.GenericCheckPermissions(
   355  		creds,
   356  		ats,
   357  		a.Mode(),
   358  		auth.KUID(atomic.LoadUint32(&a.uid)),
   359  		auth.KGID(atomic.LoadUint32(&a.gid)),
   360  	)
   361  }
   362  
   363  // IncLinks implements Inode.IncLinks.
   364  func (a *InodeAttrs) IncLinks(n uint32) {
   365  	if atomic.AddUint32(&a.nlink, n) <= n {
   366  		panic("InodeLink.IncLinks called with no existing links")
   367  	}
   368  }
   369  
   370  // DecLinks implements Inode.DecLinks.
   371  func (a *InodeAttrs) DecLinks() {
   372  	if nlink := atomic.AddUint32(&a.nlink, ^uint32(0)); nlink == ^uint32(0) {
   373  		// Negative overflow
   374  		panic("Inode.DecLinks called at 0 links")
   375  	}
   376  }
   377  
   378  // +stateify savable
   379  type slot struct {
   380  	name   string
   381  	inode  Inode
   382  	static bool
   383  	slotEntry
   384  }
   385  
   386  // OrderedChildrenOptions contains initialization options for OrderedChildren.
   387  //
   388  // +stateify savable
   389  type OrderedChildrenOptions struct {
   390  	// Writable indicates whether vfs.FilesystemImpl methods implemented by
   391  	// OrderedChildren may modify the tracked children. This applies to
   392  	// operations related to rename, unlink and rmdir. If an OrderedChildren is
   393  	// not writable, these operations all fail with EPERM.
   394  	//
   395  	// Note that writable users must implement the sticky bit (I_SVTX).
   396  	Writable bool
   397  }
   398  
   399  // OrderedChildren partially implements the Inode interface. OrderedChildren can
   400  // be embedded in directory inodes to keep track of children in the
   401  // directory, and can then be used to implement a generic directory FD -- see
   402  // GenericDirectoryFD.
   403  //
   404  // OrderedChildren can represent a node in an Inode tree. The children inodes
   405  // might be directories themselves using OrderedChildren; hence extending the
   406  // tree. The parent inode (OrderedChildren user) holds a ref on all its static
   407  // children. This lets the static inodes outlive their associated dentry.
   408  // While the dentry might have to be regenerated via a Lookup() call, we can
   409  // keep reusing the same static inode. These static children inodes are finally
   410  // DecRef'd when this directory inode is being destroyed. This makes
   411  // OrderedChildren suitable for static directory entries as well.
   412  //
   413  // Must be initialize with Init before first use.
   414  //
   415  // +stateify savable
   416  type OrderedChildren struct {
   417  	// Can children be modified by user syscalls? It set to false, interface
   418  	// methods that would modify the children return EPERM. Immutable.
   419  	writable bool
   420  
   421  	mu    sync.RWMutex `state:"nosave"`
   422  	order slotList
   423  	set   map[string]*slot
   424  }
   425  
   426  // Init initializes an OrderedChildren.
   427  func (o *OrderedChildren) Init(opts OrderedChildrenOptions) {
   428  	o.writable = opts.Writable
   429  	o.set = make(map[string]*slot)
   430  }
   431  
   432  // Destroy clears the children stored in o. It should be called by structs
   433  // embedding OrderedChildren upon destruction, i.e. when their reference count
   434  // reaches zero.
   435  func (o *OrderedChildren) Destroy(ctx context.Context) {
   436  	o.mu.Lock()
   437  	defer o.mu.Unlock()
   438  	// Drop the ref that o owns on the static inodes it holds.
   439  	for _, s := range o.set {
   440  		if s.static {
   441  			s.inode.DecRef(ctx)
   442  		}
   443  	}
   444  	o.order.Reset()
   445  	o.set = nil
   446  }
   447  
   448  // Populate inserts static children into this OrderedChildren.
   449  // Populate returns the number of directories inserted, which the caller
   450  // may use to update the link count for the parent directory.
   451  //
   452  // Precondition:
   453  //   * d must represent a directory inode.
   454  //   * children must not contain any conflicting entries already in o.
   455  //   * Caller must hold a reference on all inodes passed.
   456  //
   457  // Postcondition: Caller's references on inodes are transferred to o.
   458  func (o *OrderedChildren) Populate(children map[string]Inode) uint32 {
   459  	var links uint32
   460  	for name, child := range children {
   461  		if child.Mode().IsDir() {
   462  			links++
   463  		}
   464  		if err := o.insert(name, child, true); err != nil {
   465  			panic(fmt.Sprintf("Collision when attempting to insert child %q (%+v)", name, child))
   466  		}
   467  	}
   468  	return links
   469  }
   470  
   471  // Lookup implements Inode.Lookup.
   472  func (o *OrderedChildren) Lookup(ctx context.Context, name string) (Inode, error) {
   473  	o.mu.RLock()
   474  	defer o.mu.RUnlock()
   475  
   476  	s, ok := o.set[name]
   477  	if !ok {
   478  		return nil, syserror.ENOENT
   479  	}
   480  
   481  	s.inode.IncRef() // This ref is passed to the dentry upon creation via Init.
   482  	return s.inode, nil
   483  }
   484  
   485  // IterDirents implements Inode.IterDirents.
   486  func (o *OrderedChildren) IterDirents(ctx context.Context, mnt *vfs.Mount, cb vfs.IterDirentsCallback, offset, relOffset int64) (newOffset int64, err error) {
   487  	// All entries from OrderedChildren have already been handled in
   488  	// GenericDirectoryFD.IterDirents.
   489  	return offset, nil
   490  }
   491  
   492  // HasChildren implements Inode.HasChildren.
   493  func (o *OrderedChildren) HasChildren() bool {
   494  	o.mu.RLock()
   495  	defer o.mu.RUnlock()
   496  	return len(o.set) > 0
   497  }
   498  
   499  // Insert inserts a dynamic child into o. This ignores the writability of o, as
   500  // this is not part of the vfs.FilesystemImpl interface, and is a lower-level operation.
   501  func (o *OrderedChildren) Insert(name string, child Inode) error {
   502  	return o.insert(name, child, false)
   503  }
   504  
   505  // insert inserts child into o.
   506  //
   507  // Precondition: Caller must be holding a ref on child if static is true.
   508  //
   509  // Postcondition: Caller's ref on child is transferred to o if static is true.
   510  func (o *OrderedChildren) insert(name string, child Inode, static bool) error {
   511  	o.mu.Lock()
   512  	defer o.mu.Unlock()
   513  	if _, ok := o.set[name]; ok {
   514  		return syserror.EEXIST
   515  	}
   516  	s := &slot{
   517  		name:   name,
   518  		inode:  child,
   519  		static: static,
   520  	}
   521  	o.order.PushBack(s)
   522  	o.set[name] = s
   523  	return nil
   524  }
   525  
   526  // Precondition: caller must hold o.mu for writing.
   527  func (o *OrderedChildren) removeLocked(name string) {
   528  	if s, ok := o.set[name]; ok {
   529  		if s.static {
   530  			panic(fmt.Sprintf("removeLocked called on a static inode: %v", s.inode))
   531  		}
   532  		delete(o.set, name)
   533  		o.order.Remove(s)
   534  	}
   535  }
   536  
   537  // Precondition: caller must hold o.mu for writing.
   538  func (o *OrderedChildren) replaceChildLocked(ctx context.Context, name string, newI Inode) {
   539  	if s, ok := o.set[name]; ok {
   540  		if s.static {
   541  			panic(fmt.Sprintf("replacing a static inode: %v", s.inode))
   542  		}
   543  
   544  		// Existing slot with given name, simply replace the dentry.
   545  		s.inode = newI
   546  	}
   547  
   548  	// No existing slot with given name, create and hash new slot.
   549  	s := &slot{
   550  		name:   name,
   551  		inode:  newI,
   552  		static: false,
   553  	}
   554  	o.order.PushBack(s)
   555  	o.set[name] = s
   556  }
   557  
   558  // Precondition: caller must hold o.mu for reading or writing.
   559  func (o *OrderedChildren) checkExistingLocked(name string, child Inode) error {
   560  	s, ok := o.set[name]
   561  	if !ok {
   562  		return syserror.ENOENT
   563  	}
   564  	if s.inode != child {
   565  		panic(fmt.Sprintf("Inode doesn't match what kernfs thinks! OrderedChild: %+v, kernfs: %+v", s.inode, child))
   566  	}
   567  	return nil
   568  }
   569  
   570  // Unlink implements Inode.Unlink.
   571  func (o *OrderedChildren) Unlink(ctx context.Context, name string, child Inode) error {
   572  	if !o.writable {
   573  		return linuxerr.EPERM
   574  	}
   575  	o.mu.Lock()
   576  	defer o.mu.Unlock()
   577  	if err := o.checkExistingLocked(name, child); err != nil {
   578  		return err
   579  	}
   580  
   581  	o.removeLocked(name)
   582  	return nil
   583  }
   584  
   585  // RmDir implements Inode.RmDir.
   586  func (o *OrderedChildren) RmDir(ctx context.Context, name string, child Inode) error {
   587  	// We're not responsible for checking that child is a directory, that it's
   588  	// empty, or updating any link counts; so this is the same as unlink.
   589  	return o.Unlink(ctx, name, child)
   590  }
   591  
   592  // Rename implements Inode.Rename.
   593  //
   594  // Precondition: Rename may only be called across two directory inodes with
   595  // identical implementations of Rename. Practically, this means filesystems that
   596  // implement Rename by embedding OrderedChildren for any directory
   597  // implementation must use OrderedChildren for all directory implementations
   598  // that will support Rename.
   599  //
   600  // Postcondition: reference on any replaced dentry transferred to caller.
   601  func (o *OrderedChildren) Rename(ctx context.Context, oldname, newname string, child, dstDir Inode) error {
   602  	if !o.writable {
   603  		return linuxerr.EPERM
   604  	}
   605  
   606  	dst, ok := dstDir.(interface{}).(*OrderedChildren)
   607  	if !ok {
   608  		return linuxerr.EXDEV
   609  	}
   610  	if !dst.writable {
   611  		return linuxerr.EPERM
   612  	}
   613  
   614  	// Note: There's a potential deadlock below if concurrent calls to Rename
   615  	// refer to the same src and dst directories in reverse. We avoid any
   616  	// ordering issues because the caller is required to serialize concurrent
   617  	// calls to Rename in accordance with the interface declaration.
   618  	o.mu.Lock()
   619  	defer o.mu.Unlock()
   620  	if dst != o {
   621  		dst.mu.Lock()
   622  		defer dst.mu.Unlock()
   623  	}
   624  	if err := o.checkExistingLocked(oldname, child); err != nil {
   625  		return err
   626  	}
   627  	o.removeLocked(oldname)
   628  
   629  	dst.replaceChildLocked(ctx, newname, child)
   630  	return nil
   631  }
   632  
   633  // nthLocked returns an iterator to the nth child tracked by this object. The
   634  // iterator is valid until the caller releases o.mu. Returns nil if the
   635  // requested index falls out of bounds.
   636  //
   637  // Preconditon: Caller must hold o.mu for reading.
   638  func (o *OrderedChildren) nthLocked(i int64) *slot {
   639  	for it := o.order.Front(); it != nil && i >= 0; it = it.Next() {
   640  		if i == 0 {
   641  			return it
   642  		}
   643  		i--
   644  	}
   645  	return nil
   646  }
   647  
   648  // InodeSymlink partially implements Inode interface for symlinks.
   649  //
   650  // +stateify savable
   651  type InodeSymlink struct {
   652  	InodeNotDirectory
   653  }
   654  
   655  // Open implements Inode.Open.
   656  func (InodeSymlink) Open(ctx context.Context, rp *vfs.ResolvingPath, d *Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
   657  	return nil, linuxerr.ELOOP
   658  }
   659  
   660  // StaticDirectory is a standard implementation of a directory with static
   661  // contents.
   662  //
   663  // +stateify savable
   664  type StaticDirectory struct {
   665  	InodeAlwaysValid
   666  	InodeAttrs
   667  	InodeDirectoryNoNewChildren
   668  	InodeNoStatFS
   669  	InodeNotSymlink
   670  	InodeTemporary
   671  	OrderedChildren
   672  	StaticDirectoryRefs
   673  
   674  	locks  vfs.FileLocks
   675  	fdOpts GenericDirectoryFDOptions
   676  }
   677  
   678  var _ Inode = (*StaticDirectory)(nil)
   679  
   680  // NewStaticDir creates a new static directory and returns its dentry.
   681  func NewStaticDir(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode, children map[string]Inode, fdOpts GenericDirectoryFDOptions) Inode {
   682  	inode := &StaticDirectory{}
   683  	inode.Init(ctx, creds, devMajor, devMinor, ino, perm, fdOpts)
   684  	inode.InitRefs()
   685  
   686  	inode.OrderedChildren.Init(OrderedChildrenOptions{})
   687  	links := inode.OrderedChildren.Populate(children)
   688  	inode.IncLinks(links)
   689  
   690  	return inode
   691  }
   692  
   693  // Init initializes StaticDirectory.
   694  func (s *StaticDirectory) Init(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode, fdOpts GenericDirectoryFDOptions) {
   695  	if perm&^linux.PermissionsMask != 0 {
   696  		panic(fmt.Sprintf("Only permission mask must be set: %x", perm&linux.PermissionsMask))
   697  	}
   698  	s.fdOpts = fdOpts
   699  	s.InodeAttrs.Init(ctx, creds, devMajor, devMinor, ino, linux.ModeDirectory|perm)
   700  }
   701  
   702  // Open implements Inode.Open.
   703  func (s *StaticDirectory) Open(ctx context.Context, rp *vfs.ResolvingPath, d *Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
   704  	fd, err := NewGenericDirectoryFD(rp.Mount(), d, &s.OrderedChildren, &s.locks, &opts, s.fdOpts)
   705  	if err != nil {
   706  		return nil, err
   707  	}
   708  	return fd.VFSFileDescription(), nil
   709  }
   710  
   711  // SetStat implements Inode.SetStat not allowing inode attributes to be changed.
   712  func (*StaticDirectory) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.SetStatOptions) error {
   713  	return linuxerr.EPERM
   714  }
   715  
   716  // DecRef implements Inode.DecRef.
   717  func (s *StaticDirectory) DecRef(ctx context.Context) {
   718  	s.StaticDirectoryRefs.DecRef(func() { s.Destroy(ctx) })
   719  }
   720  
   721  // InodeAlwaysValid partially implements Inode.
   722  //
   723  // +stateify savable
   724  type InodeAlwaysValid struct{}
   725  
   726  // Valid implements Inode.Valid.
   727  func (*InodeAlwaysValid) Valid(context.Context) bool {
   728  	return true
   729  }
   730  
   731  // InodeTemporary partially implements Inode.
   732  //
   733  // +stateify savable
   734  type InodeTemporary struct{}
   735  
   736  // Keep implements Inode.Keep.
   737  func (*InodeTemporary) Keep() bool {
   738  	return false
   739  }
   740  
   741  // InodeNoStatFS partially implements the Inode interface, where the client
   742  // filesystem doesn't support statfs(2).
   743  //
   744  // +stateify savable
   745  type InodeNoStatFS struct{}
   746  
   747  // StatFS implements Inode.StatFS.
   748  func (*InodeNoStatFS) StatFS(context.Context, *vfs.Filesystem) (linux.Statfs, error) {
   749  	return linux.Statfs{}, syserror.ENOSYS
   750  }