github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/ramfs/tree.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 ramfs 16 17 import ( 18 "fmt" 19 "path" 20 "strings" 21 22 "github.com/SagerNet/gvisor/pkg/context" 23 "github.com/SagerNet/gvisor/pkg/hostarch" 24 "github.com/SagerNet/gvisor/pkg/sentry/fs" 25 "github.com/SagerNet/gvisor/pkg/sentry/fs/anon" 26 ) 27 28 // MakeDirectoryTree constructs a ramfs tree of all directories containing 29 // subdirs. Each element of subdir must be a clean path, and cannot be empty or 30 // "/". 31 // 32 // All directories in the created tree will have full (read-write-execute) 33 // permissions, but note that file creation inside the directories is not 34 // actually supported because ramfs.Dir.CreateOpts == nil. However, these 35 // directory trees are normally "underlayed" under another filesystem (possibly 36 // the root), and file creation inside these directories in the overlay will be 37 // possible if the upper is writeable. 38 func MakeDirectoryTree(ctx context.Context, msrc *fs.MountSource, subdirs []string) (*fs.Inode, error) { 39 root := emptyDir(ctx, msrc) 40 for _, subdir := range subdirs { 41 if path.Clean(subdir) != subdir { 42 return nil, fmt.Errorf("cannot add subdir at an unclean path: %q", subdir) 43 } 44 if subdir == "" || subdir == "/" { 45 return nil, fmt.Errorf("cannot add subdir at %q", subdir) 46 } 47 makeSubdir(ctx, msrc, root.InodeOperations.(*Dir), subdir) 48 } 49 return root, nil 50 } 51 52 // makeSubdir installs into root each component of subdir. The final component is 53 // a *ramfs.Dir. 54 func makeSubdir(ctx context.Context, msrc *fs.MountSource, root *Dir, subdir string) { 55 for _, c := range strings.Split(subdir, "/") { 56 if len(c) == 0 { 57 continue 58 } 59 child, ok := root.FindChild(c) 60 if !ok { 61 child = emptyDir(ctx, msrc) 62 root.AddChild(ctx, c, child) 63 } 64 root = child.InodeOperations.(*Dir) 65 } 66 } 67 68 // emptyDir returns an empty *ramfs.Dir with all permissions granted. 69 func emptyDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode { 70 dir := NewDir(ctx, make(map[string]*fs.Inode), fs.RootOwner, fs.FilePermsFromMode(0777)) 71 return fs.NewInode(ctx, dir, msrc, fs.StableAttr{ 72 DeviceID: anon.PseudoDevice.DeviceID(), 73 InodeID: anon.PseudoDevice.NextIno(), 74 BlockSize: hostarch.PageSize, 75 Type: fs.Directory, 76 }) 77 }