github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/ext/symlink.go (about)

     1  // Copyright 2019 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 ext
    16  
    17  import (
    18  	"github.com/SagerNet/gvisor/pkg/context"
    19  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    20  	"github.com/SagerNet/gvisor/pkg/sentry/memmap"
    21  	"github.com/SagerNet/gvisor/pkg/sentry/vfs"
    22  	"github.com/SagerNet/gvisor/pkg/syserror"
    23  	"github.com/SagerNet/gvisor/pkg/usermem"
    24  )
    25  
    26  // symlink represents a symlink inode.
    27  //
    28  // +stateify savable
    29  type symlink struct {
    30  	inode  inode
    31  	target string // immutable
    32  }
    33  
    34  // newSymlink is the symlink constructor. It reads out the symlink target from
    35  // the inode (however it might have been stored).
    36  func newSymlink(args inodeArgs) (*symlink, error) {
    37  	var link []byte
    38  
    39  	// If the symlink target is lesser than 60 bytes, its stores in inode.Data().
    40  	// Otherwise either extents or block maps will be used to store the link.
    41  	size := args.diskInode.Size()
    42  	if size < 60 {
    43  		link = args.diskInode.Data()[:size]
    44  	} else {
    45  		// Create a regular file out of this inode and read out the target.
    46  		regFile, err := newRegularFile(args)
    47  		if err != nil {
    48  			return nil, err
    49  		}
    50  
    51  		link = make([]byte, size)
    52  		if n, err := regFile.impl.ReadAt(link, 0); uint64(n) < size {
    53  			return nil, err
    54  		}
    55  	}
    56  
    57  	file := &symlink{target: string(link)}
    58  	file.inode.init(args, file)
    59  	return file, nil
    60  }
    61  
    62  func (in *inode) isSymlink() bool {
    63  	_, ok := in.impl.(*symlink)
    64  	return ok
    65  }
    66  
    67  // symlinkFD represents a symlink file description and implements
    68  // vfs.FileDescriptionImpl. which may only be used if open options contains
    69  // O_PATH. For this reason most of the functions return EBADF.
    70  //
    71  // +stateify savable
    72  type symlinkFD struct {
    73  	fileDescription
    74  	vfs.NoLockFD
    75  }
    76  
    77  // Compiles only if symlinkFD implements vfs.FileDescriptionImpl.
    78  var _ vfs.FileDescriptionImpl = (*symlinkFD)(nil)
    79  
    80  // Release implements vfs.FileDescriptionImpl.Release.
    81  func (fd *symlinkFD) Release(context.Context) {}
    82  
    83  // PRead implements vfs.FileDescriptionImpl.PRead.
    84  func (fd *symlinkFD) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts vfs.ReadOptions) (int64, error) {
    85  	return 0, linuxerr.EBADF
    86  }
    87  
    88  // Read implements vfs.FileDescriptionImpl.Read.
    89  func (fd *symlinkFD) Read(ctx context.Context, dst usermem.IOSequence, opts vfs.ReadOptions) (int64, error) {
    90  	return 0, linuxerr.EBADF
    91  }
    92  
    93  // PWrite implements vfs.FileDescriptionImpl.PWrite.
    94  func (fd *symlinkFD) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts vfs.WriteOptions) (int64, error) {
    95  	return 0, linuxerr.EBADF
    96  }
    97  
    98  // Write implements vfs.FileDescriptionImpl.Write.
    99  func (fd *symlinkFD) Write(ctx context.Context, src usermem.IOSequence, opts vfs.WriteOptions) (int64, error) {
   100  	return 0, linuxerr.EBADF
   101  }
   102  
   103  // IterDirents implements vfs.FileDescriptionImpl.IterDirents.
   104  func (fd *symlinkFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback) error {
   105  	return syserror.ENOTDIR
   106  }
   107  
   108  // Seek implements vfs.FileDescriptionImpl.Seek.
   109  func (fd *symlinkFD) Seek(ctx context.Context, offset int64, whence int32) (int64, error) {
   110  	return 0, linuxerr.EBADF
   111  }
   112  
   113  // ConfigureMMap implements vfs.FileDescriptionImpl.ConfigureMMap.
   114  func (fd *symlinkFD) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error {
   115  	return linuxerr.EBADF
   116  }