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

     1  // Copyright 2020 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 genericfstree provides tools for implementing vfs.FilesystemImpls
    16  // where a single statically-determined lock or set of locks is sufficient to
    17  // ensure that a Dentry's name and parent are contextually immutable.
    18  //
    19  // Clients using this package must use the go_template_instance rule in
    20  // tools/go_generics/defs.bzl to create an instantiation of this template
    21  // package, providing types to use in place of Dentry.
    22  package genericfstree
    23  
    24  import (
    25  	"github.com/SagerNet/gvisor/pkg/fspath"
    26  	"github.com/SagerNet/gvisor/pkg/sentry/vfs"
    27  )
    28  
    29  // Dentry is a required type parameter that is a struct with the given fields.
    30  //
    31  // +stateify savable
    32  type Dentry struct {
    33  	// vfsd is the embedded vfs.Dentry corresponding to this vfs.DentryImpl.
    34  	vfsd vfs.Dentry
    35  
    36  	// parent is the parent of this Dentry in the filesystem's tree. If this
    37  	// Dentry is a filesystem root, parent is nil.
    38  	parent *Dentry
    39  
    40  	// name is the name of this Dentry in its parent. If this Dentry is a
    41  	// filesystem root, name is unspecified.
    42  	name string
    43  }
    44  
    45  // IsAncestorDentry returns true if d is an ancestor of d2; that is, d is
    46  // either d2's parent or an ancestor of d2's parent.
    47  func IsAncestorDentry(d, d2 *Dentry) bool {
    48  	for d2 != nil { // Stop at root, where d2.parent == nil.
    49  		if d2.parent == d {
    50  			return true
    51  		}
    52  		if d2.parent == d2 {
    53  			return false
    54  		}
    55  		d2 = d2.parent
    56  	}
    57  	return false
    58  }
    59  
    60  // ParentOrSelf returns d.parent. If d.parent is nil, ParentOrSelf returns d.
    61  func ParentOrSelf(d *Dentry) *Dentry {
    62  	if d.parent != nil {
    63  		return d.parent
    64  	}
    65  	return d
    66  }
    67  
    68  // PrependPath is a generic implementation of FilesystemImpl.PrependPath().
    69  func PrependPath(vfsroot vfs.VirtualDentry, mnt *vfs.Mount, d *Dentry, b *fspath.Builder) error {
    70  	for {
    71  		if mnt == vfsroot.Mount() && &d.vfsd == vfsroot.Dentry() {
    72  			return vfs.PrependPathAtVFSRootError{}
    73  		}
    74  		if mnt != nil && &d.vfsd == mnt.Root() {
    75  			return nil
    76  		}
    77  		if d.parent == nil {
    78  			return vfs.PrependPathAtNonMountRootError{}
    79  		}
    80  		b.PrependComponent(d.name)
    81  		d = d.parent
    82  	}
    83  }
    84  
    85  // DebugPathname returns a pathname to d relative to its filesystem root.
    86  // DebugPathname does not correspond to any Linux function; it's used to
    87  // generate dentry pathnames for debugging.
    88  func DebugPathname(d *Dentry) string {
    89  	var b fspath.Builder
    90  	_ = PrependPath(vfs.VirtualDentry{}, nil, d, &b)
    91  	return b.String()
    92  }