diff options
Diffstat (limited to 'pkg/sentry/fs/ramfs/tree.go')
-rw-r--r-- | pkg/sentry/fs/ramfs/tree.go | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/pkg/sentry/fs/ramfs/tree.go b/pkg/sentry/fs/ramfs/tree.go new file mode 100644 index 000000000..8c6b31f70 --- /dev/null +++ b/pkg/sentry/fs/ramfs/tree.go @@ -0,0 +1,77 @@ +// Copyright 2018 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ramfs + +import ( + "fmt" + "path" + "strings" + + "gvisor.googlesource.com/gvisor/pkg/sentry/context" + "gvisor.googlesource.com/gvisor/pkg/sentry/fs" + "gvisor.googlesource.com/gvisor/pkg/sentry/fs/anon" + "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" +) + +// MakeDirectoryTree constructs a ramfs tree of all directories containing +// subdirs. Each element of subdir must be a clean path, and cannot be empty or +// "/". +// +// All directories in the created tree will have full (read-write-execute) +// permissions, but note that file creation inside the directories is not +// actually supported because ramfs.Dir.CreateOpts == nil. However, these +// directory trees are normally "underlayed" under another filesystem (possibly +// the root), and file creation inside these directories in the overlay will be +// possible if the upper is writeable. +func MakeDirectoryTree(ctx context.Context, msrc *fs.MountSource, subdirs []string) (*fs.Inode, error) { + root := emptyDir(ctx, msrc) + for _, subdir := range subdirs { + if path.Clean(subdir) != subdir { + return nil, fmt.Errorf("cannot add subdir at an unclean path: %q", subdir) + } + if subdir == "" || subdir == "/" { + return nil, fmt.Errorf("cannot add subdir at %q", subdir) + } + makeSubdir(ctx, msrc, root.InodeOperations.(*Dir), subdir) + } + return root, nil +} + +// makeSubdir installs into root each component of subdir. The final component is +// a *ramfs.Dir. +func makeSubdir(ctx context.Context, msrc *fs.MountSource, root *Dir, subdir string) { + for _, c := range strings.Split(subdir, "/") { + if len(c) == 0 { + continue + } + child, ok := root.FindChild(c) + if !ok { + child = emptyDir(ctx, msrc) + root.AddChild(ctx, c, child) + } + root = child.InodeOperations.(*Dir) + } +} + +// emptyDir returns an empty *ramfs.Dir with all permissions granted. +func emptyDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode { + dir := NewDir(ctx, make(map[string]*fs.Inode), fs.RootOwner, fs.FilePermsFromMode(0777)) + return fs.NewInode(dir, msrc, fs.StableAttr{ + DeviceID: anon.PseudoDevice.DeviceID(), + InodeID: anon.PseudoDevice.NextIno(), + BlockSize: usermem.PageSize, + Type: fs.Directory, + }) +} |