github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsbridge/vfs.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 fsbridge 16 17 import ( 18 "io" 19 20 "github.com/SagerNet/gvisor/pkg/abi/linux" 21 "github.com/SagerNet/gvisor/pkg/context" 22 "github.com/SagerNet/gvisor/pkg/fspath" 23 "github.com/SagerNet/gvisor/pkg/sentry/kernel/auth" 24 "github.com/SagerNet/gvisor/pkg/sentry/memmap" 25 "github.com/SagerNet/gvisor/pkg/sentry/vfs" 26 "github.com/SagerNet/gvisor/pkg/usermem" 27 ) 28 29 // VFSFile implements File interface over vfs.FileDescription. 30 // 31 // +stateify savable 32 type VFSFile struct { 33 file *vfs.FileDescription 34 } 35 36 var _ File = (*VFSFile)(nil) 37 38 // NewVFSFile creates a new File over fs.File. 39 func NewVFSFile(file *vfs.FileDescription) File { 40 return &VFSFile{file: file} 41 } 42 43 // PathnameWithDeleted implements File. 44 func (f *VFSFile) PathnameWithDeleted(ctx context.Context) string { 45 root := vfs.RootFromContext(ctx) 46 defer root.DecRef(ctx) 47 48 vfsObj := f.file.VirtualDentry().Mount().Filesystem().VirtualFilesystem() 49 name, _ := vfsObj.PathnameWithDeleted(ctx, root, f.file.VirtualDentry()) 50 return name 51 } 52 53 // ReadFull implements File. 54 func (f *VFSFile) ReadFull(ctx context.Context, dst usermem.IOSequence, offset int64) (int64, error) { 55 var total int64 56 for dst.NumBytes() > 0 { 57 n, err := f.file.PRead(ctx, dst, offset+total, vfs.ReadOptions{}) 58 total += n 59 if err == io.EOF && total != 0 { 60 return total, io.ErrUnexpectedEOF 61 } else if err != nil { 62 return total, err 63 } 64 dst = dst.DropFirst64(n) 65 } 66 return total, nil 67 } 68 69 // ConfigureMMap implements File. 70 func (f *VFSFile) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error { 71 return f.file.ConfigureMMap(ctx, opts) 72 } 73 74 // Type implements File. 75 func (f *VFSFile) Type(ctx context.Context) (linux.FileMode, error) { 76 stat, err := f.file.Stat(ctx, vfs.StatOptions{}) 77 if err != nil { 78 return 0, err 79 } 80 return linux.FileMode(stat.Mode).FileType(), nil 81 } 82 83 // IncRef implements File. 84 func (f *VFSFile) IncRef() { 85 f.file.IncRef() 86 } 87 88 // DecRef implements File. 89 func (f *VFSFile) DecRef(ctx context.Context) { 90 f.file.DecRef(ctx) 91 } 92 93 // FileDescription returns the FileDescription represented by f. It does not 94 // take an additional reference on the returned FileDescription. 95 func (f *VFSFile) FileDescription() *vfs.FileDescription { 96 return f.file 97 } 98 99 // fsLookup implements Lookup interface using fs.File. 100 // 101 // +stateify savable 102 type vfsLookup struct { 103 mntns *vfs.MountNamespace 104 105 root vfs.VirtualDentry 106 workingDir vfs.VirtualDentry 107 } 108 109 var _ Lookup = (*vfsLookup)(nil) 110 111 // NewVFSLookup creates a new Lookup using VFS2. 112 func NewVFSLookup(mntns *vfs.MountNamespace, root, workingDir vfs.VirtualDentry) Lookup { 113 return &vfsLookup{ 114 mntns: mntns, 115 root: root, 116 workingDir: workingDir, 117 } 118 } 119 120 // OpenPath implements Lookup. 121 // 122 // remainingTraversals is not configurable in VFS2, all callers are using the 123 // default anyways. 124 func (l *vfsLookup) OpenPath(ctx context.Context, pathname string, opts vfs.OpenOptions, _ *uint, resolveFinal bool) (File, error) { 125 vfsObj := l.root.Mount().Filesystem().VirtualFilesystem() 126 creds := auth.CredentialsFromContext(ctx) 127 path := fspath.Parse(pathname) 128 pop := &vfs.PathOperation{ 129 Root: l.root, 130 Start: l.workingDir, 131 Path: path, 132 FollowFinalSymlink: resolveFinal, 133 } 134 if path.Absolute { 135 pop.Start = l.root 136 } 137 fd, err := vfsObj.OpenAt(ctx, creds, pop, &opts) 138 if err != nil { 139 return nil, err 140 } 141 return &VFSFile{file: fd}, nil 142 }