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  }