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 }