github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/ext/regular_file.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 "io" 19 20 "github.com/SagerNet/gvisor/pkg/abi/linux" 21 "github.com/SagerNet/gvisor/pkg/context" 22 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 23 "github.com/SagerNet/gvisor/pkg/safemem" 24 "github.com/SagerNet/gvisor/pkg/sentry/memmap" 25 "github.com/SagerNet/gvisor/pkg/sentry/vfs" 26 "github.com/SagerNet/gvisor/pkg/sync" 27 "github.com/SagerNet/gvisor/pkg/syserror" 28 "github.com/SagerNet/gvisor/pkg/usermem" 29 ) 30 31 // regularFile represents a regular file's inode. This too follows the 32 // inheritance pattern prevelant in the vfs layer described in 33 // pkg/sentry/vfs/README.md. 34 // 35 // +stateify savable 36 type regularFile struct { 37 inode inode 38 39 // This is immutable. The first field of fileReader implementations must be 40 // regularFile to ensure temporality. 41 // io.ReaderAt is more strict than io.Reader in the sense that a partial read 42 // is always accompanied by an error. If a read spans past the end of file, a 43 // partial read (within file range) is done and io.EOF is returned. 44 impl io.ReaderAt 45 } 46 47 // newRegularFile is the regularFile constructor. It figures out what kind of 48 // file this is and initializes the fileReader. 49 func newRegularFile(args inodeArgs) (*regularFile, error) { 50 if args.diskInode.Flags().Extents { 51 file, err := newExtentFile(args) 52 if err != nil { 53 return nil, err 54 } 55 return &file.regFile, nil 56 } 57 58 file, err := newBlockMapFile(args) 59 if err != nil { 60 return nil, err 61 } 62 return &file.regFile, nil 63 } 64 65 func (in *inode) isRegular() bool { 66 _, ok := in.impl.(*regularFile) 67 return ok 68 } 69 70 // directoryFD represents a directory file description. It implements 71 // vfs.FileDescriptionImpl. 72 // 73 // +stateify savable 74 type regularFileFD struct { 75 fileDescription 76 vfs.LockFD 77 78 // off is the file offset. off is accessed using atomic memory operations. 79 off int64 80 81 // offMu serializes operations that may mutate off. 82 offMu sync.Mutex `state:"nosave"` 83 } 84 85 // Release implements vfs.FileDescriptionImpl.Release. 86 func (fd *regularFileFD) Release(context.Context) {} 87 88 // PRead implements vfs.FileDescriptionImpl.PRead. 89 func (fd *regularFileFD) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts vfs.ReadOptions) (int64, error) { 90 safeReader := safemem.FromIOReaderAt{ 91 ReaderAt: fd.inode().impl.(*regularFile).impl, 92 Offset: offset, 93 } 94 95 // Copies data from disk directly into usermem without any intermediate 96 // allocations (if dst is converted into BlockSeq such that it does not need 97 // safe copying). 98 return dst.CopyOutFrom(ctx, safeReader) 99 } 100 101 // Read implements vfs.FileDescriptionImpl.Read. 102 func (fd *regularFileFD) Read(ctx context.Context, dst usermem.IOSequence, opts vfs.ReadOptions) (int64, error) { 103 n, err := fd.PRead(ctx, dst, fd.off, opts) 104 fd.offMu.Lock() 105 fd.off += n 106 fd.offMu.Unlock() 107 return n, err 108 } 109 110 // PWrite implements vfs.FileDescriptionImpl.PWrite. 111 func (fd *regularFileFD) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts vfs.WriteOptions) (int64, error) { 112 // write(2) specifies that EBADF must be returned if the fd is not open for 113 // writing. 114 return 0, linuxerr.EBADF 115 } 116 117 // Write implements vfs.FileDescriptionImpl.Write. 118 func (fd *regularFileFD) Write(ctx context.Context, src usermem.IOSequence, opts vfs.WriteOptions) (int64, error) { 119 n, err := fd.PWrite(ctx, src, fd.off, opts) 120 fd.offMu.Lock() 121 fd.off += n 122 fd.offMu.Unlock() 123 return n, err 124 } 125 126 // IterDirents implements vfs.FileDescriptionImpl.IterDirents. 127 func (fd *regularFileFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback) error { 128 return syserror.ENOTDIR 129 } 130 131 // Seek implements vfs.FileDescriptionImpl.Seek. 132 func (fd *regularFileFD) Seek(ctx context.Context, offset int64, whence int32) (int64, error) { 133 fd.offMu.Lock() 134 defer fd.offMu.Unlock() 135 switch whence { 136 case linux.SEEK_SET: 137 // Use offset as specified. 138 case linux.SEEK_CUR: 139 offset += fd.off 140 case linux.SEEK_END: 141 offset += int64(fd.inode().diskInode.Size()) 142 default: 143 return 0, linuxerr.EINVAL 144 } 145 if offset < 0 { 146 return 0, linuxerr.EINVAL 147 } 148 fd.off = offset 149 return offset, nil 150 } 151 152 // ConfigureMMap implements vfs.FileDescriptionImpl.ConfigureMMap. 153 func (fd *regularFileFD) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error { 154 // TODO(b/134676337): Implement mmap(2). 155 return linuxerr.ENODEV 156 }