github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/sys_stat.go (about) 1 // Copyright 2018 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 linux 16 17 import ( 18 "github.com/SagerNet/gvisor/pkg/abi/linux" 19 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 20 "github.com/SagerNet/gvisor/pkg/hostarch" 21 "github.com/SagerNet/gvisor/pkg/sentry/arch" 22 "github.com/SagerNet/gvisor/pkg/sentry/fs" 23 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 24 "github.com/SagerNet/gvisor/pkg/syserror" 25 ) 26 27 // LINT.IfChange 28 29 // Stat implements linux syscall stat(2). 30 func Stat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 31 addr := args[0].Pointer() 32 statAddr := args[1].Pointer() 33 34 path, dirPath, err := copyInPath(t, addr, false /* allowEmpty */) 35 if err != nil { 36 return 0, nil, err 37 } 38 39 return 0, nil, fileOpOn(t, linux.AT_FDCWD, path, true /* resolve */, func(root *fs.Dirent, d *fs.Dirent, _ uint) error { 40 return stat(t, d, dirPath, statAddr) 41 }) 42 } 43 44 // Fstatat implements linux syscall newfstatat, i.e. fstatat(2). 45 func Fstatat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 46 fd := args[0].Int() 47 addr := args[1].Pointer() 48 statAddr := args[2].Pointer() 49 flags := args[3].Int() 50 51 path, dirPath, err := copyInPath(t, addr, flags&linux.AT_EMPTY_PATH != 0) 52 if err != nil { 53 return 0, nil, err 54 } 55 56 if path == "" { 57 // Annoying. What's wrong with fstat? 58 file := t.GetFile(fd) 59 if file == nil { 60 return 0, nil, linuxerr.EBADF 61 } 62 defer file.DecRef(t) 63 64 return 0, nil, fstat(t, file, statAddr) 65 } 66 67 // If the path ends in a slash (i.e. dirPath is true) or if AT_SYMLINK_NOFOLLOW is unset, 68 // then we must resolve the final component. 69 resolve := dirPath || flags&linux.AT_SYMLINK_NOFOLLOW == 0 70 71 return 0, nil, fileOpOn(t, fd, path, resolve, func(root *fs.Dirent, d *fs.Dirent, _ uint) error { 72 return stat(t, d, dirPath, statAddr) 73 }) 74 } 75 76 // Lstat implements linux syscall lstat(2). 77 func Lstat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 78 addr := args[0].Pointer() 79 statAddr := args[1].Pointer() 80 81 path, dirPath, err := copyInPath(t, addr, false /* allowEmpty */) 82 if err != nil { 83 return 0, nil, err 84 } 85 86 // If the path ends in a slash (i.e. dirPath is true), then we *do* 87 // want to resolve the final component. 88 resolve := dirPath 89 90 return 0, nil, fileOpOn(t, linux.AT_FDCWD, path, resolve, func(root *fs.Dirent, d *fs.Dirent, _ uint) error { 91 return stat(t, d, dirPath, statAddr) 92 }) 93 } 94 95 // Fstat implements linux syscall fstat(2). 96 func Fstat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 97 fd := args[0].Int() 98 statAddr := args[1].Pointer() 99 100 file := t.GetFile(fd) 101 if file == nil { 102 return 0, nil, linuxerr.EBADF 103 } 104 defer file.DecRef(t) 105 106 return 0, nil, fstat(t, file, statAddr) 107 } 108 109 // stat implements stat from the given *fs.Dirent. 110 func stat(t *kernel.Task, d *fs.Dirent, dirPath bool, statAddr hostarch.Addr) error { 111 if dirPath && !fs.IsDir(d.Inode.StableAttr) { 112 return syserror.ENOTDIR 113 } 114 uattr, err := d.Inode.UnstableAttr(t) 115 if err != nil { 116 return err 117 } 118 s := statFromAttrs(t, d.Inode.StableAttr, uattr) 119 _, err = s.CopyOut(t, statAddr) 120 return err 121 } 122 123 // fstat implements fstat for the given *fs.File. 124 func fstat(t *kernel.Task, f *fs.File, statAddr hostarch.Addr) error { 125 uattr, err := f.UnstableAttr(t) 126 if err != nil { 127 return err 128 } 129 s := statFromAttrs(t, f.Dirent.Inode.StableAttr, uattr) 130 _, err = s.CopyOut(t, statAddr) 131 return err 132 } 133 134 // Statx implements linux syscall statx(2). 135 func Statx(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 136 fd := args[0].Int() 137 pathAddr := args[1].Pointer() 138 flags := args[2].Int() 139 mask := args[3].Uint() 140 statxAddr := args[4].Pointer() 141 142 if mask&linux.STATX__RESERVED != 0 { 143 return 0, nil, linuxerr.EINVAL 144 } 145 if flags&^(linux.AT_SYMLINK_NOFOLLOW|linux.AT_EMPTY_PATH|linux.AT_STATX_SYNC_TYPE) != 0 { 146 return 0, nil, linuxerr.EINVAL 147 } 148 if flags&linux.AT_STATX_SYNC_TYPE == linux.AT_STATX_SYNC_TYPE { 149 return 0, nil, linuxerr.EINVAL 150 } 151 152 path, dirPath, err := copyInPath(t, pathAddr, flags&linux.AT_EMPTY_PATH != 0) 153 if err != nil { 154 return 0, nil, err 155 } 156 157 if path == "" { 158 file := t.GetFile(fd) 159 if file == nil { 160 return 0, nil, linuxerr.EBADF 161 } 162 defer file.DecRef(t) 163 uattr, err := file.UnstableAttr(t) 164 if err != nil { 165 return 0, nil, err 166 } 167 return 0, nil, statx(t, file.Dirent.Inode.StableAttr, uattr, statxAddr) 168 } 169 170 resolve := dirPath || flags&linux.AT_SYMLINK_NOFOLLOW == 0 171 172 return 0, nil, fileOpOn(t, fd, path, resolve, func(root *fs.Dirent, d *fs.Dirent, _ uint) error { 173 if dirPath && !fs.IsDir(d.Inode.StableAttr) { 174 return syserror.ENOTDIR 175 } 176 uattr, err := d.Inode.UnstableAttr(t) 177 if err != nil { 178 return err 179 } 180 return statx(t, d.Inode.StableAttr, uattr, statxAddr) 181 }) 182 } 183 184 func statx(t *kernel.Task, sattr fs.StableAttr, uattr fs.UnstableAttr, statxAddr hostarch.Addr) error { 185 // "[T]he kernel may return fields that weren't requested and may fail to 186 // return fields that were requested, depending on what the backing 187 // filesystem supports. 188 // [...] 189 // A filesystem may also fill in fields that the caller didn't ask for 190 // if it has values for them available and the information is available 191 // at no extra cost. If this happens, the corresponding bits will be 192 // set in stx_mask." -- statx(2) 193 // 194 // We fill in all the values we have (which currently does not include 195 // btime, see b/135608823), regardless of what the user asked for. The 196 // STATX_BASIC_STATS mask indicates that all fields are present except 197 // for btime. 198 199 devMajor, devMinor := linux.DecodeDeviceID(uint32(sattr.DeviceID)) 200 s := linux.Statx{ 201 // TODO(b/135608823): Support btime, and then change this to 202 // STATX_ALL to indicate presence of btime. 203 Mask: linux.STATX_BASIC_STATS, 204 205 // No attributes, and none supported. 206 Attributes: 0, 207 AttributesMask: 0, 208 209 Blksize: uint32(sattr.BlockSize), 210 Nlink: uint32(uattr.Links), 211 UID: uint32(uattr.Owner.UID.In(t.UserNamespace()).OrOverflow()), 212 GID: uint32(uattr.Owner.GID.In(t.UserNamespace()).OrOverflow()), 213 Mode: uint16(sattr.Type.LinuxType()) | uint16(uattr.Perms.LinuxMode()), 214 Ino: sattr.InodeID, 215 Size: uint64(uattr.Size), 216 Blocks: uint64(uattr.Usage) / 512, 217 Atime: uattr.AccessTime.StatxTimestamp(), 218 Ctime: uattr.StatusChangeTime.StatxTimestamp(), 219 Mtime: uattr.ModificationTime.StatxTimestamp(), 220 RdevMajor: uint32(sattr.DeviceFileMajor), 221 RdevMinor: sattr.DeviceFileMinor, 222 DevMajor: uint32(devMajor), 223 DevMinor: devMinor, 224 } 225 _, err := s.CopyOut(t, statxAddr) 226 return err 227 } 228 229 // Statfs implements linux syscall statfs(2). 230 func Statfs(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 231 addr := args[0].Pointer() 232 statfsAddr := args[1].Pointer() 233 234 path, _, err := copyInPath(t, addr, false /* allowEmpty */) 235 if err != nil { 236 return 0, nil, err 237 } 238 239 return 0, nil, fileOpOn(t, linux.AT_FDCWD, path, true /* resolve */, func(root *fs.Dirent, d *fs.Dirent, _ uint) error { 240 return statfsImpl(t, d, statfsAddr) 241 }) 242 } 243 244 // Fstatfs implements linux syscall fstatfs(2). 245 func Fstatfs(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 246 fd := args[0].Int() 247 statfsAddr := args[1].Pointer() 248 249 file := t.GetFile(fd) 250 if file == nil { 251 return 0, nil, linuxerr.EBADF 252 } 253 defer file.DecRef(t) 254 255 return 0, nil, statfsImpl(t, file.Dirent, statfsAddr) 256 } 257 258 // statfsImpl implements the linux syscall statfs and fstatfs based on a Dirent, 259 // copying the statfs structure out to addr on success, otherwise an error is 260 // returned. 261 func statfsImpl(t *kernel.Task, d *fs.Dirent, addr hostarch.Addr) error { 262 info, err := d.Inode.StatFS(t) 263 if err != nil { 264 return err 265 } 266 // Construct the statfs structure and copy it out. 267 statfs := linux.Statfs{ 268 Type: info.Type, 269 // Treat block size and fragment size as the same, as 270 // most consumers of this structure will expect one 271 // or the other to be filled in. 272 BlockSize: d.Inode.StableAttr.BlockSize, 273 Blocks: info.TotalBlocks, 274 // We don't have the concept of reserved blocks, so 275 // report blocks free the same as available blocks. 276 // This is a normal thing for filesystems, to do, see 277 // udf, hugetlbfs, tmpfs, among others. 278 BlocksFree: info.FreeBlocks, 279 BlocksAvailable: info.FreeBlocks, 280 Files: info.TotalFiles, 281 FilesFree: info.FreeFiles, 282 // Same as Linux for simple_statfs, see fs/libfs.c. 283 NameLength: linux.NAME_MAX, 284 FragmentSize: d.Inode.StableAttr.BlockSize, 285 // Leave other fields 0 like simple_statfs does. 286 } 287 _, err = statfs.CopyOut(t, addr) 288 return err 289 } 290 291 // LINT.ThenChange(vfs2/stat.go)