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 }