1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/fs/stat.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 82d985f8cSEric Biggers #include <linux/blkdev.h> 9630d9c47SPaul Gortmaker #include <linux/export.h> 101da177e4SLinus Torvalds #include <linux/mm.h> 111da177e4SLinus Torvalds #include <linux/errno.h> 121da177e4SLinus Torvalds #include <linux/file.h> 131da177e4SLinus Torvalds #include <linux/highuid.h> 141da177e4SLinus Torvalds #include <linux/fs.h> 151da177e4SLinus Torvalds #include <linux/namei.h> 161da177e4SLinus Torvalds #include <linux/security.h> 175b825c3aSIngo Molnar #include <linux/cred.h> 181da177e4SLinus Torvalds #include <linux/syscalls.h> 19ba52de12STheodore Ts'o #include <linux/pagemap.h> 20ac565de3SAl Viro #include <linux/compat.h> 21a1175d6bSJeff Layton #include <linux/iversion.h> 221da177e4SLinus Torvalds 237c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 241da177e4SLinus Torvalds #include <asm/unistd.h> 251da177e4SLinus Torvalds 263934e36fSJens Axboe #include "internal.h" 27fa2fcf4fSMiklos Szeredi #include "mount.h" 283934e36fSJens Axboe 29a528d35eSDavid Howells /** 30a528d35eSDavid Howells * generic_fillattr - Fill in the basic attributes from the inode struct 31b74d24f7SChristian Brauner * @idmap: idmap of the mount the inode was found from 320d72b928SJeff Layton * @request_mask: statx request_mask 33a528d35eSDavid Howells * @inode: Inode to use as the source 34a528d35eSDavid Howells * @stat: Where to fill in the attributes 35a528d35eSDavid Howells * 36a528d35eSDavid Howells * Fill in the basic attributes in the kstat structure from data that's to be 37a528d35eSDavid Howells * found on the VFS inode structure. This is the default if no getattr inode 38a528d35eSDavid Howells * operation is supplied. 390d56a451SChristian Brauner * 40b74d24f7SChristian Brauner * If the inode has been found through an idmapped mount the idmap of 41b74d24f7SChristian Brauner * the vfsmount must be passed through @idmap. This function will then 42b74d24f7SChristian Brauner * take care to map the inode according to @idmap before filling in the 430d56a451SChristian Brauner * uid and gid filds. On non-idmapped mounts or if permission checking is to be 44b74d24f7SChristian Brauner * performed on the raw inode simply passs @nop_mnt_idmap. 45a528d35eSDavid Howells */ 460d72b928SJeff Layton void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask, 470d72b928SJeff Layton struct inode *inode, struct kstat *stat) 481da177e4SLinus Torvalds { 49e67fe633SChristian Brauner vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode); 50e67fe633SChristian Brauner vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode); 51a2bd096fSChristian Brauner 521da177e4SLinus Torvalds stat->dev = inode->i_sb->s_dev; 531da177e4SLinus Torvalds stat->ino = inode->i_ino; 541da177e4SLinus Torvalds stat->mode = inode->i_mode; 551da177e4SLinus Torvalds stat->nlink = inode->i_nlink; 56a2bd096fSChristian Brauner stat->uid = vfsuid_into_kuid(vfsuid); 57a2bd096fSChristian Brauner stat->gid = vfsgid_into_kgid(vfsgid); 581da177e4SLinus Torvalds stat->rdev = inode->i_rdev; 593ddcd056SLinus Torvalds stat->size = i_size_read(inode); 601da177e4SLinus Torvalds stat->atime = inode->i_atime; 611da177e4SLinus Torvalds stat->mtime = inode->i_mtime; 622276e5baSJeff Layton stat->ctime = inode_get_ctime(inode); 6393407472SFabian Frederick stat->blksize = i_blocksize(inode); 643ddcd056SLinus Torvalds stat->blocks = inode->i_blocks; 650d72b928SJeff Layton 660d72b928SJeff Layton if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) { 670d72b928SJeff Layton stat->result_mask |= STATX_CHANGE_COOKIE; 680d72b928SJeff Layton stat->change_cookie = inode_query_iversion(inode); 690d72b928SJeff Layton } 700d72b928SJeff Layton 71a528d35eSDavid Howells } 721da177e4SLinus Torvalds EXPORT_SYMBOL(generic_fillattr); 731da177e4SLinus Torvalds 74b7a6ec52SJ. Bruce Fields /** 754f911138SAmir Goldstein * generic_fill_statx_attr - Fill in the statx attributes from the inode flags 764f911138SAmir Goldstein * @inode: Inode to use as the source 774f911138SAmir Goldstein * @stat: Where to fill in the attribute flags 784f911138SAmir Goldstein * 794f911138SAmir Goldstein * Fill in the STATX_ATTR_* flags in the kstat structure for properties of the 804f911138SAmir Goldstein * inode that are published on i_flags and enforced by the VFS. 814f911138SAmir Goldstein */ 824f911138SAmir Goldstein void generic_fill_statx_attr(struct inode *inode, struct kstat *stat) 834f911138SAmir Goldstein { 844f911138SAmir Goldstein if (inode->i_flags & S_IMMUTABLE) 854f911138SAmir Goldstein stat->attributes |= STATX_ATTR_IMMUTABLE; 864f911138SAmir Goldstein if (inode->i_flags & S_APPEND) 874f911138SAmir Goldstein stat->attributes |= STATX_ATTR_APPEND; 884f911138SAmir Goldstein stat->attributes_mask |= KSTAT_ATTR_VFS_FLAGS; 894f911138SAmir Goldstein } 904f911138SAmir Goldstein EXPORT_SYMBOL(generic_fill_statx_attr); 914f911138SAmir Goldstein 924f911138SAmir Goldstein /** 93b7a6ec52SJ. Bruce Fields * vfs_getattr_nosec - getattr without security checks 94b7a6ec52SJ. Bruce Fields * @path: file to get attributes from 95b7a6ec52SJ. Bruce Fields * @stat: structure to return attributes in 96a528d35eSDavid Howells * @request_mask: STATX_xxx flags indicating what the caller wants 97f2d077ffSChristoph Hellwig * @query_flags: Query mode (AT_STATX_SYNC_TYPE) 98b7a6ec52SJ. Bruce Fields * 99b7a6ec52SJ. Bruce Fields * Get attributes without calling security_inode_getattr. 100b7a6ec52SJ. Bruce Fields * 101b7a6ec52SJ. Bruce Fields * Currently the only caller other than vfs_getattr is internal to the 102a528d35eSDavid Howells * filehandle lookup code, which uses only the inode number and returns no 103a528d35eSDavid Howells * attributes to any user. Any other code probably wants vfs_getattr. 104b7a6ec52SJ. Bruce Fields */ 105a528d35eSDavid Howells int vfs_getattr_nosec(const struct path *path, struct kstat *stat, 106a528d35eSDavid Howells u32 request_mask, unsigned int query_flags) 1071da177e4SLinus Torvalds { 108b74d24f7SChristian Brauner struct mnt_idmap *idmap; 109bb668734SDavid Howells struct inode *inode = d_backing_inode(path->dentry); 1101da177e4SLinus Torvalds 111a528d35eSDavid Howells memset(stat, 0, sizeof(*stat)); 112a528d35eSDavid Howells stat->result_mask |= STATX_BASIC_STATS; 113f2d077ffSChristoph Hellwig query_flags &= AT_STATX_SYNC_TYPE; 114801e5237SChristoph Hellwig 115801e5237SChristoph Hellwig /* allow the fs to override these if it really wants to */ 116761e28faSMiklos Szeredi /* SB_NOATIME means filesystem supplies dummy atime value */ 117761e28faSMiklos Szeredi if (inode->i_sb->s_flags & SB_NOATIME) 118801e5237SChristoph Hellwig stat->result_mask &= ~STATX_ATIME; 1195afa7e8bSTheodore Ts'o 1205afa7e8bSTheodore Ts'o /* 1215afa7e8bSTheodore Ts'o * Note: If you add another clause to set an attribute flag, please 1225afa7e8bSTheodore Ts'o * update attributes_mask below. 1235afa7e8bSTheodore Ts'o */ 124801e5237SChristoph Hellwig if (IS_AUTOMOUNT(inode)) 125801e5237SChristoph Hellwig stat->attributes |= STATX_ATTR_AUTOMOUNT; 126801e5237SChristoph Hellwig 127712b2698SIra Weiny if (IS_DAX(inode)) 128712b2698SIra Weiny stat->attributes |= STATX_ATTR_DAX; 129712b2698SIra Weiny 1305afa7e8bSTheodore Ts'o stat->attributes_mask |= (STATX_ATTR_AUTOMOUNT | 1315afa7e8bSTheodore Ts'o STATX_ATTR_DAX); 1325afa7e8bSTheodore Ts'o 133b74d24f7SChristian Brauner idmap = mnt_idmap(path->mnt); 1341da177e4SLinus Torvalds if (inode->i_op->getattr) 135b74d24f7SChristian Brauner return inode->i_op->getattr(idmap, path, stat, 136*3fb0fa08SStefan Berger request_mask, 137*3fb0fa08SStefan Berger query_flags | AT_GETATTR_NOSEC); 1381da177e4SLinus Torvalds 1390d72b928SJeff Layton generic_fillattr(idmap, request_mask, inode, stat); 1401da177e4SLinus Torvalds return 0; 1411da177e4SLinus Torvalds } 142b7a6ec52SJ. Bruce Fields EXPORT_SYMBOL(vfs_getattr_nosec); 143b7a6ec52SJ. Bruce Fields 144a528d35eSDavid Howells /* 145a528d35eSDavid Howells * vfs_getattr - Get the enhanced basic attributes of a file 146a528d35eSDavid Howells * @path: The file of interest 147a528d35eSDavid Howells * @stat: Where to return the statistics 148a528d35eSDavid Howells * @request_mask: STATX_xxx flags indicating what the caller wants 149f2d077ffSChristoph Hellwig * @query_flags: Query mode (AT_STATX_SYNC_TYPE) 150a528d35eSDavid Howells * 151a528d35eSDavid Howells * Ask the filesystem for a file's attributes. The caller must indicate in 152a528d35eSDavid Howells * request_mask and query_flags to indicate what they want. 153a528d35eSDavid Howells * 154a528d35eSDavid Howells * If the file is remote, the filesystem can be forced to update the attributes 155a528d35eSDavid Howells * from the backing store by passing AT_STATX_FORCE_SYNC in query_flags or can 156a528d35eSDavid Howells * suppress the update by passing AT_STATX_DONT_SYNC. 157a528d35eSDavid Howells * 158a528d35eSDavid Howells * Bits must have been set in request_mask to indicate which attributes the 159a528d35eSDavid Howells * caller wants retrieving. Any such attribute not requested may be returned 160a528d35eSDavid Howells * anyway, but the value may be approximate, and, if remote, may not have been 161a528d35eSDavid Howells * synchronised with the server. 162a528d35eSDavid Howells * 163a528d35eSDavid Howells * 0 will be returned on success, and a -ve error code if unsuccessful. 164a528d35eSDavid Howells */ 165a528d35eSDavid Howells int vfs_getattr(const struct path *path, struct kstat *stat, 166a528d35eSDavid Howells u32 request_mask, unsigned int query_flags) 167b7a6ec52SJ. Bruce Fields { 168b7a6ec52SJ. Bruce Fields int retval; 169b7a6ec52SJ. Bruce Fields 170*3fb0fa08SStefan Berger if (WARN_ON_ONCE(query_flags & AT_GETATTR_NOSEC)) 171*3fb0fa08SStefan Berger return -EPERM; 172*3fb0fa08SStefan Berger 1733f7036a0SAl Viro retval = security_inode_getattr(path); 174b7a6ec52SJ. Bruce Fields if (retval) 175b7a6ec52SJ. Bruce Fields return retval; 176a528d35eSDavid Howells return vfs_getattr_nosec(path, stat, request_mask, query_flags); 177b7a6ec52SJ. Bruce Fields } 1781da177e4SLinus Torvalds EXPORT_SYMBOL(vfs_getattr); 1791da177e4SLinus Torvalds 180a528d35eSDavid Howells /** 181da9aa5d9SChristoph Hellwig * vfs_fstat - Get the basic attributes by file descriptor 182a528d35eSDavid Howells * @fd: The file descriptor referring to the file of interest 183a528d35eSDavid Howells * @stat: The result structure to fill in. 184a528d35eSDavid Howells * 185a528d35eSDavid Howells * This function is a wrapper around vfs_getattr(). The main difference is 186a528d35eSDavid Howells * that it uses a file descriptor to determine the file location. 187a528d35eSDavid Howells * 188a528d35eSDavid Howells * 0 will be returned on success, and a -ve error code if unsuccessful. 189a528d35eSDavid Howells */ 190da9aa5d9SChristoph Hellwig int vfs_fstat(int fd, struct kstat *stat) 1911da177e4SLinus Torvalds { 1928c7493aaSEric Biggers struct fd f; 193da9aa5d9SChristoph Hellwig int error; 1948c7493aaSEric Biggers 1958c7493aaSEric Biggers f = fdget_raw(fd); 196da9aa5d9SChristoph Hellwig if (!f.file) 197da9aa5d9SChristoph Hellwig return -EBADF; 198da9aa5d9SChristoph Hellwig error = vfs_getattr(&f.file->f_path, stat, STATX_BASIC_STATS, 0); 1992903ff01SAl Viro fdput(f); 2001da177e4SLinus Torvalds return error; 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 2031b6fe6e0SStefan Roesch int getname_statx_lookup_flags(int flags) 2041b6fe6e0SStefan Roesch { 2051b6fe6e0SStefan Roesch int lookup_flags = 0; 2061b6fe6e0SStefan Roesch 2071b6fe6e0SStefan Roesch if (!(flags & AT_SYMLINK_NOFOLLOW)) 2081b6fe6e0SStefan Roesch lookup_flags |= LOOKUP_FOLLOW; 2091b6fe6e0SStefan Roesch if (!(flags & AT_NO_AUTOMOUNT)) 2101b6fe6e0SStefan Roesch lookup_flags |= LOOKUP_AUTOMOUNT; 2111b6fe6e0SStefan Roesch if (flags & AT_EMPTY_PATH) 2121b6fe6e0SStefan Roesch lookup_flags |= LOOKUP_EMPTY; 2131b6fe6e0SStefan Roesch 2141b6fe6e0SStefan Roesch return lookup_flags; 2151b6fe6e0SStefan Roesch } 2161b6fe6e0SStefan Roesch 217a528d35eSDavid Howells /** 218a528d35eSDavid Howells * vfs_statx - Get basic and extra attributes by filename 219a528d35eSDavid Howells * @dfd: A file descriptor representing the base dir for a relative filename 220a528d35eSDavid Howells * @filename: The name of the file of interest 221a528d35eSDavid Howells * @flags: Flags to control the query 222a528d35eSDavid Howells * @stat: The result structure to fill in. 223a528d35eSDavid Howells * @request_mask: STATX_xxx flags indicating what the caller wants 224a528d35eSDavid Howells * 225a528d35eSDavid Howells * This function is a wrapper around vfs_getattr(). The main difference is 226a528d35eSDavid Howells * that it uses a filename and base directory to determine the file location. 227a528d35eSDavid Howells * Additionally, the use of AT_SYMLINK_NOFOLLOW in flags will prevent a symlink 228a528d35eSDavid Howells * at the given name from being referenced. 229a528d35eSDavid Howells * 230a528d35eSDavid Howells * 0 will be returned on success, and a -ve error code if unsuccessful. 231a528d35eSDavid Howells */ 2321b6fe6e0SStefan Roesch static int vfs_statx(int dfd, struct filename *filename, int flags, 233a528d35eSDavid Howells struct kstat *stat, u32 request_mask) 2340112fc22SOleg Drokin { 2352eae7a18SChristoph Hellwig struct path path; 2361b6fe6e0SStefan Roesch unsigned int lookup_flags = getname_statx_lookup_flags(flags); 237b3f05150SChristoph Hellwig int error; 2380112fc22SOleg Drokin 239b3f05150SChristoph Hellwig if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH | 240f2d077ffSChristoph Hellwig AT_STATX_SYNC_TYPE)) 241a528d35eSDavid Howells return -EINVAL; 242b3f05150SChristoph Hellwig 243836fb7e7SJeff Layton retry: 2441b6fe6e0SStefan Roesch error = filename_lookup(dfd, filename, lookup_flags, &path, NULL); 2452eae7a18SChristoph Hellwig if (error) 2462eae7a18SChristoph Hellwig goto out; 2472eae7a18SChristoph Hellwig 248a528d35eSDavid Howells error = vfs_getattr(&path, stat, request_mask, flags); 2492d985f8cSEric Biggers 250fa2fcf4fSMiklos Szeredi stat->mnt_id = real_mount(path.mnt)->mnt_id; 251fa2fcf4fSMiklos Szeredi stat->result_mask |= STATX_MNT_ID; 2522d985f8cSEric Biggers 25380340fe3SMiklos Szeredi if (path.mnt->mnt_root == path.dentry) 25480340fe3SMiklos Szeredi stat->attributes |= STATX_ATTR_MOUNT_ROOT; 25580340fe3SMiklos Szeredi stat->attributes_mask |= STATX_ATTR_MOUNT_ROOT; 2562d985f8cSEric Biggers 2572d985f8cSEric Biggers /* Handle STATX_DIOALIGN for block devices. */ 2582d985f8cSEric Biggers if (request_mask & STATX_DIOALIGN) { 2592d985f8cSEric Biggers struct inode *inode = d_backing_inode(path.dentry); 2602d985f8cSEric Biggers 2612d985f8cSEric Biggers if (S_ISBLK(inode->i_mode)) 2622d985f8cSEric Biggers bdev_statx_dioalign(inode, stat); 2632d985f8cSEric Biggers } 2642d985f8cSEric Biggers 2652eae7a18SChristoph Hellwig path_put(&path); 266836fb7e7SJeff Layton if (retry_estale(error, lookup_flags)) { 267836fb7e7SJeff Layton lookup_flags |= LOOKUP_REVAL; 268836fb7e7SJeff Layton goto retry; 269836fb7e7SJeff Layton } 2700112fc22SOleg Drokin out: 2710112fc22SOleg Drokin return error; 2720112fc22SOleg Drokin } 2732eae7a18SChristoph Hellwig 27409f1bde4SChristoph Hellwig int vfs_fstatat(int dfd, const char __user *filename, 27509f1bde4SChristoph Hellwig struct kstat *stat, int flags) 27609f1bde4SChristoph Hellwig { 2771b6fe6e0SStefan Roesch int ret; 2781b6fe6e0SStefan Roesch int statx_flags = flags | AT_NO_AUTOMOUNT; 2791b6fe6e0SStefan Roesch struct filename *name; 2801b6fe6e0SStefan Roesch 2819013c51cSLinus Torvalds /* 2829013c51cSLinus Torvalds * Work around glibc turning fstat() into fstatat(AT_EMPTY_PATH) 2839013c51cSLinus Torvalds * 2849013c51cSLinus Torvalds * If AT_EMPTY_PATH is set, we expect the common case to be that 2859013c51cSLinus Torvalds * empty path, and avoid doing all the extra pathname work. 2869013c51cSLinus Torvalds */ 2879013c51cSLinus Torvalds if (dfd >= 0 && flags == AT_EMPTY_PATH) { 2889013c51cSLinus Torvalds char c; 2899013c51cSLinus Torvalds 2909013c51cSLinus Torvalds ret = get_user(c, filename); 2919013c51cSLinus Torvalds if (unlikely(ret)) 2929013c51cSLinus Torvalds return ret; 2939013c51cSLinus Torvalds 2949013c51cSLinus Torvalds if (likely(!c)) 2959013c51cSLinus Torvalds return vfs_fstat(dfd, stat); 2969013c51cSLinus Torvalds } 2979013c51cSLinus Torvalds 2981b6fe6e0SStefan Roesch name = getname_flags(filename, getname_statx_lookup_flags(statx_flags), NULL); 2991b6fe6e0SStefan Roesch ret = vfs_statx(dfd, name, statx_flags, stat, STATX_BASIC_STATS); 3001b6fe6e0SStefan Roesch putname(name); 3011b6fe6e0SStefan Roesch 3021b6fe6e0SStefan Roesch return ret; 30309f1bde4SChristoph Hellwig } 3040112fc22SOleg Drokin 3051da177e4SLinus Torvalds #ifdef __ARCH_WANT_OLD_STAT 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds /* 3081da177e4SLinus Torvalds * For backward compatibility? Maybe this should be moved 3091da177e4SLinus Torvalds * into arch/i386 instead? 3101da177e4SLinus Torvalds */ 3111da177e4SLinus Torvalds static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * statbuf) 3121da177e4SLinus Torvalds { 3131da177e4SLinus Torvalds static int warncount = 5; 3141da177e4SLinus Torvalds struct __old_kernel_stat tmp; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds if (warncount > 0) { 3171da177e4SLinus Torvalds warncount--; 3181da177e4SLinus Torvalds printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", 3191da177e4SLinus Torvalds current->comm); 3201da177e4SLinus Torvalds } else if (warncount < 0) { 3211da177e4SLinus Torvalds /* it's laughable, but... */ 3221da177e4SLinus Torvalds warncount = 0; 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds memset(&tmp, 0, sizeof(struct __old_kernel_stat)); 3261da177e4SLinus Torvalds tmp.st_dev = old_encode_dev(stat->dev); 3271da177e4SLinus Torvalds tmp.st_ino = stat->ino; 328afefdbb2SDavid Howells if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 329afefdbb2SDavid Howells return -EOVERFLOW; 3301da177e4SLinus Torvalds tmp.st_mode = stat->mode; 3311da177e4SLinus Torvalds tmp.st_nlink = stat->nlink; 3321da177e4SLinus Torvalds if (tmp.st_nlink != stat->nlink) 3331da177e4SLinus Torvalds return -EOVERFLOW; 334a7c1938eSEric W. Biederman SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); 335a7c1938eSEric W. Biederman SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); 3361da177e4SLinus Torvalds tmp.st_rdev = old_encode_dev(stat->rdev); 3371da177e4SLinus Torvalds #if BITS_PER_LONG == 32 3381da177e4SLinus Torvalds if (stat->size > MAX_NON_LFS) 3391da177e4SLinus Torvalds return -EOVERFLOW; 3401da177e4SLinus Torvalds #endif 3411da177e4SLinus Torvalds tmp.st_size = stat->size; 3421da177e4SLinus Torvalds tmp.st_atime = stat->atime.tv_sec; 3431da177e4SLinus Torvalds tmp.st_mtime = stat->mtime.tv_sec; 3441da177e4SLinus Torvalds tmp.st_ctime = stat->ctime.tv_sec; 3451da177e4SLinus Torvalds return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 3461da177e4SLinus Torvalds } 3471da177e4SLinus Torvalds 348c7887325SDavid Howells SYSCALL_DEFINE2(stat, const char __user *, filename, 349c7887325SDavid Howells struct __old_kernel_stat __user *, statbuf) 3501da177e4SLinus Torvalds { 3511da177e4SLinus Torvalds struct kstat stat; 3522eae7a18SChristoph Hellwig int error; 3531da177e4SLinus Torvalds 3542eae7a18SChristoph Hellwig error = vfs_stat(filename, &stat); 3552eae7a18SChristoph Hellwig if (error) 3561da177e4SLinus Torvalds return error; 3572eae7a18SChristoph Hellwig 3582eae7a18SChristoph Hellwig return cp_old_stat(&stat, statbuf); 3591da177e4SLinus Torvalds } 360257ac264SHeiko Carstens 361c7887325SDavid Howells SYSCALL_DEFINE2(lstat, const char __user *, filename, 362c7887325SDavid Howells struct __old_kernel_stat __user *, statbuf) 3631da177e4SLinus Torvalds { 3641da177e4SLinus Torvalds struct kstat stat; 3652eae7a18SChristoph Hellwig int error; 3661da177e4SLinus Torvalds 3672eae7a18SChristoph Hellwig error = vfs_lstat(filename, &stat); 3682eae7a18SChristoph Hellwig if (error) 3691da177e4SLinus Torvalds return error; 3702eae7a18SChristoph Hellwig 3712eae7a18SChristoph Hellwig return cp_old_stat(&stat, statbuf); 3721da177e4SLinus Torvalds } 373257ac264SHeiko Carstens 374257ac264SHeiko Carstens SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, statbuf) 3751da177e4SLinus Torvalds { 3761da177e4SLinus Torvalds struct kstat stat; 3771da177e4SLinus Torvalds int error = vfs_fstat(fd, &stat); 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds if (!error) 3801da177e4SLinus Torvalds error = cp_old_stat(&stat, statbuf); 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds return error; 3831da177e4SLinus Torvalds } 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds #endif /* __ARCH_WANT_OLD_STAT */ 3861da177e4SLinus Torvalds 38782b355d1SArnd Bergmann #ifdef __ARCH_WANT_NEW_STAT 38882b355d1SArnd Bergmann 3898529f613SLinus Torvalds #ifndef INIT_STRUCT_STAT_PADDING 3908529f613SLinus Torvalds # define INIT_STRUCT_STAT_PADDING(st) memset(&st, 0, sizeof(st)) 3918529f613SLinus Torvalds #endif 3928529f613SLinus Torvalds 3931da177e4SLinus Torvalds static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) 3941da177e4SLinus Torvalds { 3951da177e4SLinus Torvalds struct stat tmp; 3961da177e4SLinus Torvalds 397932aba1eSMikulas Patocka if (sizeof(tmp.st_dev) < 4 && !old_valid_dev(stat->dev)) 398932aba1eSMikulas Patocka return -EOVERFLOW; 399932aba1eSMikulas Patocka if (sizeof(tmp.st_rdev) < 4 && !old_valid_dev(stat->rdev)) 4001da177e4SLinus Torvalds return -EOVERFLOW; 401a52dd971SLinus Torvalds #if BITS_PER_LONG == 32 402a52dd971SLinus Torvalds if (stat->size > MAX_NON_LFS) 4031da177e4SLinus Torvalds return -EOVERFLOW; 4041da177e4SLinus Torvalds #endif 4051da177e4SLinus Torvalds 4068529f613SLinus Torvalds INIT_STRUCT_STAT_PADDING(tmp); 407932aba1eSMikulas Patocka tmp.st_dev = new_encode_dev(stat->dev); 4081da177e4SLinus Torvalds tmp.st_ino = stat->ino; 409afefdbb2SDavid Howells if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 410afefdbb2SDavid Howells return -EOVERFLOW; 4111da177e4SLinus Torvalds tmp.st_mode = stat->mode; 4121da177e4SLinus Torvalds tmp.st_nlink = stat->nlink; 4131da177e4SLinus Torvalds if (tmp.st_nlink != stat->nlink) 4141da177e4SLinus Torvalds return -EOVERFLOW; 415a7c1938eSEric W. Biederman SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); 416a7c1938eSEric W. Biederman SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); 417932aba1eSMikulas Patocka tmp.st_rdev = new_encode_dev(stat->rdev); 4181da177e4SLinus Torvalds tmp.st_size = stat->size; 4191da177e4SLinus Torvalds tmp.st_atime = stat->atime.tv_sec; 4201da177e4SLinus Torvalds tmp.st_mtime = stat->mtime.tv_sec; 4211da177e4SLinus Torvalds tmp.st_ctime = stat->ctime.tv_sec; 4221da177e4SLinus Torvalds #ifdef STAT_HAVE_NSEC 4231da177e4SLinus Torvalds tmp.st_atime_nsec = stat->atime.tv_nsec; 4241da177e4SLinus Torvalds tmp.st_mtime_nsec = stat->mtime.tv_nsec; 4251da177e4SLinus Torvalds tmp.st_ctime_nsec = stat->ctime.tv_nsec; 4261da177e4SLinus Torvalds #endif 4271da177e4SLinus Torvalds tmp.st_blocks = stat->blocks; 4281da177e4SLinus Torvalds tmp.st_blksize = stat->blksize; 4291da177e4SLinus Torvalds return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 4301da177e4SLinus Torvalds } 4311da177e4SLinus Torvalds 432c7887325SDavid Howells SYSCALL_DEFINE2(newstat, const char __user *, filename, 433c7887325SDavid Howells struct stat __user *, statbuf) 4341da177e4SLinus Torvalds { 4351da177e4SLinus Torvalds struct kstat stat; 4362eae7a18SChristoph Hellwig int error = vfs_stat(filename, &stat); 4371da177e4SLinus Torvalds 4382eae7a18SChristoph Hellwig if (error) 4391da177e4SLinus Torvalds return error; 4402eae7a18SChristoph Hellwig return cp_new_stat(&stat, statbuf); 4411da177e4SLinus Torvalds } 4425590ff0dSUlrich Drepper 443c7887325SDavid Howells SYSCALL_DEFINE2(newlstat, const char __user *, filename, 444c7887325SDavid Howells struct stat __user *, statbuf) 4451da177e4SLinus Torvalds { 4461da177e4SLinus Torvalds struct kstat stat; 4472eae7a18SChristoph Hellwig int error; 4481da177e4SLinus Torvalds 4492eae7a18SChristoph Hellwig error = vfs_lstat(filename, &stat); 4502eae7a18SChristoph Hellwig if (error) 4511da177e4SLinus Torvalds return error; 4522eae7a18SChristoph Hellwig 4532eae7a18SChristoph Hellwig return cp_new_stat(&stat, statbuf); 4541da177e4SLinus Torvalds } 4555590ff0dSUlrich Drepper 4562833c28aSAndreas Schwab #if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT) 457c7887325SDavid Howells SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename, 4586559eed8SHeiko Carstens struct stat __user *, statbuf, int, flag) 4595590ff0dSUlrich Drepper { 4605590ff0dSUlrich Drepper struct kstat stat; 4610112fc22SOleg Drokin int error; 4625590ff0dSUlrich Drepper 4630112fc22SOleg Drokin error = vfs_fstatat(dfd, filename, &stat, flag); 4640112fc22SOleg Drokin if (error) 4655590ff0dSUlrich Drepper return error; 4660112fc22SOleg Drokin return cp_new_stat(&stat, statbuf); 4675590ff0dSUlrich Drepper } 468cff2b760SUlrich Drepper #endif 4695590ff0dSUlrich Drepper 470257ac264SHeiko Carstens SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf) 4711da177e4SLinus Torvalds { 4721da177e4SLinus Torvalds struct kstat stat; 4731da177e4SLinus Torvalds int error = vfs_fstat(fd, &stat); 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds if (!error) 4761da177e4SLinus Torvalds error = cp_new_stat(&stat, statbuf); 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds return error; 4791da177e4SLinus Torvalds } 48082b355d1SArnd Bergmann #endif 4811da177e4SLinus Torvalds 4822dae0248SDominik Brodowski static int do_readlinkat(int dfd, const char __user *pathname, 4832dae0248SDominik Brodowski char __user *buf, int bufsiz) 4841da177e4SLinus Torvalds { 4852d8f3038SAl Viro struct path path; 4861da177e4SLinus Torvalds int error; 4871fa1e7f6SAndy Whitcroft int empty = 0; 4887955119eSJeff Layton unsigned int lookup_flags = LOOKUP_EMPTY; 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds if (bufsiz <= 0) 4911da177e4SLinus Torvalds return -EINVAL; 4921da177e4SLinus Torvalds 4937955119eSJeff Layton retry: 4947955119eSJeff Layton error = user_path_at_empty(dfd, pathname, lookup_flags, &path, &empty); 4951da177e4SLinus Torvalds if (!error) { 496bb668734SDavid Howells struct inode *inode = d_backing_inode(path.dentry); 4971da177e4SLinus Torvalds 4981fa1e7f6SAndy Whitcroft error = empty ? -ENOENT : -EINVAL; 499fd4a0edfSMiklos Szeredi /* 500fd4a0edfSMiklos Szeredi * AFS mountpoints allow readlink(2) but are not symlinks 501fd4a0edfSMiklos Szeredi */ 502fd4a0edfSMiklos Szeredi if (d_is_symlink(path.dentry) || inode->i_op->readlink) { 5032d8f3038SAl Viro error = security_inode_readlink(path.dentry); 5041da177e4SLinus Torvalds if (!error) { 50568ac1234SAl Viro touch_atime(&path); 506fd4a0edfSMiklos Szeredi error = vfs_readlink(path.dentry, buf, bufsiz); 5071da177e4SLinus Torvalds } 5081da177e4SLinus Torvalds } 5092d8f3038SAl Viro path_put(&path); 5107955119eSJeff Layton if (retry_estale(error, lookup_flags)) { 5117955119eSJeff Layton lookup_flags |= LOOKUP_REVAL; 5127955119eSJeff Layton goto retry; 5137955119eSJeff Layton } 5141da177e4SLinus Torvalds } 5151da177e4SLinus Torvalds return error; 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds 5182dae0248SDominik Brodowski SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, 5192dae0248SDominik Brodowski char __user *, buf, int, bufsiz) 5202dae0248SDominik Brodowski { 5212dae0248SDominik Brodowski return do_readlinkat(dfd, pathname, buf, bufsiz); 5222dae0248SDominik Brodowski } 5232dae0248SDominik Brodowski 524002c8976SHeiko Carstens SYSCALL_DEFINE3(readlink, const char __user *, path, char __user *, buf, 525002c8976SHeiko Carstens int, bufsiz) 5265590ff0dSUlrich Drepper { 5272dae0248SDominik Brodowski return do_readlinkat(AT_FDCWD, path, buf, bufsiz); 5285590ff0dSUlrich Drepper } 5295590ff0dSUlrich Drepper 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds /* ---------- LFS-64 ----------- */ 5320753f70fSCatalin Marinas #if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64) 5331da177e4SLinus Torvalds 5348529f613SLinus Torvalds #ifndef INIT_STRUCT_STAT64_PADDING 5358529f613SLinus Torvalds # define INIT_STRUCT_STAT64_PADDING(st) memset(&st, 0, sizeof(st)) 5368529f613SLinus Torvalds #endif 5378529f613SLinus Torvalds 5381da177e4SLinus Torvalds static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) 5391da177e4SLinus Torvalds { 5401da177e4SLinus Torvalds struct stat64 tmp; 5411da177e4SLinus Torvalds 5428529f613SLinus Torvalds INIT_STRUCT_STAT64_PADDING(tmp); 5431da177e4SLinus Torvalds #ifdef CONFIG_MIPS 5441da177e4SLinus Torvalds /* mips has weird padding, so we don't get 64 bits there */ 5451da177e4SLinus Torvalds tmp.st_dev = new_encode_dev(stat->dev); 5461da177e4SLinus Torvalds tmp.st_rdev = new_encode_dev(stat->rdev); 5471da177e4SLinus Torvalds #else 5481da177e4SLinus Torvalds tmp.st_dev = huge_encode_dev(stat->dev); 5491da177e4SLinus Torvalds tmp.st_rdev = huge_encode_dev(stat->rdev); 5501da177e4SLinus Torvalds #endif 5511da177e4SLinus Torvalds tmp.st_ino = stat->ino; 552afefdbb2SDavid Howells if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 553afefdbb2SDavid Howells return -EOVERFLOW; 5541da177e4SLinus Torvalds #ifdef STAT64_HAS_BROKEN_ST_INO 5551da177e4SLinus Torvalds tmp.__st_ino = stat->ino; 5561da177e4SLinus Torvalds #endif 5571da177e4SLinus Torvalds tmp.st_mode = stat->mode; 5581da177e4SLinus Torvalds tmp.st_nlink = stat->nlink; 559a7c1938eSEric W. Biederman tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid); 560a7c1938eSEric W. Biederman tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid); 5611da177e4SLinus Torvalds tmp.st_atime = stat->atime.tv_sec; 5621da177e4SLinus Torvalds tmp.st_atime_nsec = stat->atime.tv_nsec; 5631da177e4SLinus Torvalds tmp.st_mtime = stat->mtime.tv_sec; 5641da177e4SLinus Torvalds tmp.st_mtime_nsec = stat->mtime.tv_nsec; 5651da177e4SLinus Torvalds tmp.st_ctime = stat->ctime.tv_sec; 5661da177e4SLinus Torvalds tmp.st_ctime_nsec = stat->ctime.tv_nsec; 5671da177e4SLinus Torvalds tmp.st_size = stat->size; 5681da177e4SLinus Torvalds tmp.st_blocks = stat->blocks; 5691da177e4SLinus Torvalds tmp.st_blksize = stat->blksize; 5701da177e4SLinus Torvalds return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds 573c7887325SDavid Howells SYSCALL_DEFINE2(stat64, const char __user *, filename, 574c7887325SDavid Howells struct stat64 __user *, statbuf) 5751da177e4SLinus Torvalds { 5761da177e4SLinus Torvalds struct kstat stat; 5771da177e4SLinus Torvalds int error = vfs_stat(filename, &stat); 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds if (!error) 5801da177e4SLinus Torvalds error = cp_new_stat64(&stat, statbuf); 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds return error; 5831da177e4SLinus Torvalds } 584257ac264SHeiko Carstens 585c7887325SDavid Howells SYSCALL_DEFINE2(lstat64, const char __user *, filename, 586c7887325SDavid Howells struct stat64 __user *, statbuf) 5871da177e4SLinus Torvalds { 5881da177e4SLinus Torvalds struct kstat stat; 5891da177e4SLinus Torvalds int error = vfs_lstat(filename, &stat); 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds if (!error) 5921da177e4SLinus Torvalds error = cp_new_stat64(&stat, statbuf); 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds return error; 5951da177e4SLinus Torvalds } 596257ac264SHeiko Carstens 597257ac264SHeiko Carstens SYSCALL_DEFINE2(fstat64, unsigned long, fd, struct stat64 __user *, statbuf) 5981da177e4SLinus Torvalds { 5991da177e4SLinus Torvalds struct kstat stat; 6001da177e4SLinus Torvalds int error = vfs_fstat(fd, &stat); 6011da177e4SLinus Torvalds 6021da177e4SLinus Torvalds if (!error) 6031da177e4SLinus Torvalds error = cp_new_stat64(&stat, statbuf); 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds return error; 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds 608c7887325SDavid Howells SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename, 6096559eed8SHeiko Carstens struct stat64 __user *, statbuf, int, flag) 610cff2b760SUlrich Drepper { 611cff2b760SUlrich Drepper struct kstat stat; 6120112fc22SOleg Drokin int error; 613cff2b760SUlrich Drepper 6140112fc22SOleg Drokin error = vfs_fstatat(dfd, filename, &stat, flag); 6150112fc22SOleg Drokin if (error) 616cff2b760SUlrich Drepper return error; 6170112fc22SOleg Drokin return cp_new_stat64(&stat, statbuf); 618cff2b760SUlrich Drepper } 6190753f70fSCatalin Marinas #endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */ 6201da177e4SLinus Torvalds 6216f88cc17SBijan Mottahedeh static noinline_for_stack int 62264bd7204SEric Biggers cp_statx(const struct kstat *stat, struct statx __user *buffer) 623a528d35eSDavid Howells { 62464bd7204SEric Biggers struct statx tmp; 625a528d35eSDavid Howells 62664bd7204SEric Biggers memset(&tmp, 0, sizeof(tmp)); 627a528d35eSDavid Howells 628a1175d6bSJeff Layton /* STATX_CHANGE_COOKIE is kernel-only for now */ 629a1175d6bSJeff Layton tmp.stx_mask = stat->result_mask & ~STATX_CHANGE_COOKIE; 63064bd7204SEric Biggers tmp.stx_blksize = stat->blksize; 631a1175d6bSJeff Layton /* STATX_ATTR_CHANGE_MONOTONIC is kernel-only for now */ 632a1175d6bSJeff Layton tmp.stx_attributes = stat->attributes & ~STATX_ATTR_CHANGE_MONOTONIC; 63364bd7204SEric Biggers tmp.stx_nlink = stat->nlink; 63464bd7204SEric Biggers tmp.stx_uid = from_kuid_munged(current_user_ns(), stat->uid); 63564bd7204SEric Biggers tmp.stx_gid = from_kgid_munged(current_user_ns(), stat->gid); 63664bd7204SEric Biggers tmp.stx_mode = stat->mode; 63764bd7204SEric Biggers tmp.stx_ino = stat->ino; 63864bd7204SEric Biggers tmp.stx_size = stat->size; 63964bd7204SEric Biggers tmp.stx_blocks = stat->blocks; 6403209f68bSDavid Howells tmp.stx_attributes_mask = stat->attributes_mask; 64164bd7204SEric Biggers tmp.stx_atime.tv_sec = stat->atime.tv_sec; 64264bd7204SEric Biggers tmp.stx_atime.tv_nsec = stat->atime.tv_nsec; 64364bd7204SEric Biggers tmp.stx_btime.tv_sec = stat->btime.tv_sec; 64464bd7204SEric Biggers tmp.stx_btime.tv_nsec = stat->btime.tv_nsec; 64564bd7204SEric Biggers tmp.stx_ctime.tv_sec = stat->ctime.tv_sec; 64664bd7204SEric Biggers tmp.stx_ctime.tv_nsec = stat->ctime.tv_nsec; 64764bd7204SEric Biggers tmp.stx_mtime.tv_sec = stat->mtime.tv_sec; 64864bd7204SEric Biggers tmp.stx_mtime.tv_nsec = stat->mtime.tv_nsec; 64964bd7204SEric Biggers tmp.stx_rdev_major = MAJOR(stat->rdev); 65064bd7204SEric Biggers tmp.stx_rdev_minor = MINOR(stat->rdev); 65164bd7204SEric Biggers tmp.stx_dev_major = MAJOR(stat->dev); 65264bd7204SEric Biggers tmp.stx_dev_minor = MINOR(stat->dev); 653fa2fcf4fSMiklos Szeredi tmp.stx_mnt_id = stat->mnt_id; 654825cf206SEric Biggers tmp.stx_dio_mem_align = stat->dio_mem_align; 655825cf206SEric Biggers tmp.stx_dio_offset_align = stat->dio_offset_align; 656a528d35eSDavid Howells 65764bd7204SEric Biggers return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0; 658a528d35eSDavid Howells } 659a528d35eSDavid Howells 6601b6fe6e0SStefan Roesch int do_statx(int dfd, struct filename *filename, unsigned int flags, 6610018784fSBijan Mottahedeh unsigned int mask, struct statx __user *buffer) 6620018784fSBijan Mottahedeh { 6630018784fSBijan Mottahedeh struct kstat stat; 6640018784fSBijan Mottahedeh int error; 6650018784fSBijan Mottahedeh 6660018784fSBijan Mottahedeh if (mask & STATX__RESERVED) 6670018784fSBijan Mottahedeh return -EINVAL; 6680018784fSBijan Mottahedeh if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE) 6690018784fSBijan Mottahedeh return -EINVAL; 6700018784fSBijan Mottahedeh 671a1175d6bSJeff Layton /* STATX_CHANGE_COOKIE is kernel-only for now. Ignore requests 672a1175d6bSJeff Layton * from userland. 673a1175d6bSJeff Layton */ 674a1175d6bSJeff Layton mask &= ~STATX_CHANGE_COOKIE; 675a1175d6bSJeff Layton 6760018784fSBijan Mottahedeh error = vfs_statx(dfd, filename, flags, &stat, mask); 6770018784fSBijan Mottahedeh if (error) 6780018784fSBijan Mottahedeh return error; 6790018784fSBijan Mottahedeh 6800018784fSBijan Mottahedeh return cp_statx(&stat, buffer); 6810018784fSBijan Mottahedeh } 6820018784fSBijan Mottahedeh 683a528d35eSDavid Howells /** 684a528d35eSDavid Howells * sys_statx - System call to get enhanced stats 685a528d35eSDavid Howells * @dfd: Base directory to pathwalk from *or* fd to stat. 6861e2f82d1SDavid Howells * @filename: File to stat or "" with AT_EMPTY_PATH 687a528d35eSDavid Howells * @flags: AT_* flags to control pathwalk. 688a528d35eSDavid Howells * @mask: Parts of statx struct actually required. 689a528d35eSDavid Howells * @buffer: Result buffer. 690a528d35eSDavid Howells * 6911e2f82d1SDavid Howells * Note that fstat() can be emulated by setting dfd to the fd of interest, 6921e2f82d1SDavid Howells * supplying "" as the filename and setting AT_EMPTY_PATH in the flags. 693a528d35eSDavid Howells */ 694a528d35eSDavid Howells SYSCALL_DEFINE5(statx, 695a528d35eSDavid Howells int, dfd, const char __user *, filename, unsigned, flags, 696a528d35eSDavid Howells unsigned int, mask, 697a528d35eSDavid Howells struct statx __user *, buffer) 698a528d35eSDavid Howells { 6991b6fe6e0SStefan Roesch int ret; 7001b6fe6e0SStefan Roesch struct filename *name; 7011b6fe6e0SStefan Roesch 7021b6fe6e0SStefan Roesch name = getname_flags(filename, getname_statx_lookup_flags(flags), NULL); 7031b6fe6e0SStefan Roesch ret = do_statx(dfd, name, flags, mask, buffer); 7041b6fe6e0SStefan Roesch putname(name); 7051b6fe6e0SStefan Roesch 7061b6fe6e0SStefan Roesch return ret; 707a528d35eSDavid Howells } 708a528d35eSDavid Howells 709f18ed30dSGuo Ren #if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_STAT) 710ac565de3SAl Viro static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) 711ac565de3SAl Viro { 712ac565de3SAl Viro struct compat_stat tmp; 713ac565de3SAl Viro 714932aba1eSMikulas Patocka if (sizeof(tmp.st_dev) < 4 && !old_valid_dev(stat->dev)) 715932aba1eSMikulas Patocka return -EOVERFLOW; 716932aba1eSMikulas Patocka if (sizeof(tmp.st_rdev) < 4 && !old_valid_dev(stat->rdev)) 717ac565de3SAl Viro return -EOVERFLOW; 718ac565de3SAl Viro 719ac565de3SAl Viro memset(&tmp, 0, sizeof(tmp)); 720932aba1eSMikulas Patocka tmp.st_dev = new_encode_dev(stat->dev); 721ac565de3SAl Viro tmp.st_ino = stat->ino; 722ac565de3SAl Viro if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 723ac565de3SAl Viro return -EOVERFLOW; 724ac565de3SAl Viro tmp.st_mode = stat->mode; 725ac565de3SAl Viro tmp.st_nlink = stat->nlink; 726ac565de3SAl Viro if (tmp.st_nlink != stat->nlink) 727ac565de3SAl Viro return -EOVERFLOW; 728ac565de3SAl Viro SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); 729ac565de3SAl Viro SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); 730932aba1eSMikulas Patocka tmp.st_rdev = new_encode_dev(stat->rdev); 731ac565de3SAl Viro if ((u64) stat->size > MAX_NON_LFS) 732ac565de3SAl Viro return -EOVERFLOW; 733ac565de3SAl Viro tmp.st_size = stat->size; 734ac565de3SAl Viro tmp.st_atime = stat->atime.tv_sec; 735ac565de3SAl Viro tmp.st_atime_nsec = stat->atime.tv_nsec; 736ac565de3SAl Viro tmp.st_mtime = stat->mtime.tv_sec; 737ac565de3SAl Viro tmp.st_mtime_nsec = stat->mtime.tv_nsec; 738ac565de3SAl Viro tmp.st_ctime = stat->ctime.tv_sec; 739ac565de3SAl Viro tmp.st_ctime_nsec = stat->ctime.tv_nsec; 740ac565de3SAl Viro tmp.st_blocks = stat->blocks; 741ac565de3SAl Viro tmp.st_blksize = stat->blksize; 742ac565de3SAl Viro return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0; 743ac565de3SAl Viro } 744ac565de3SAl Viro 745ac565de3SAl Viro COMPAT_SYSCALL_DEFINE2(newstat, const char __user *, filename, 746ac565de3SAl Viro struct compat_stat __user *, statbuf) 747ac565de3SAl Viro { 748ac565de3SAl Viro struct kstat stat; 749ac565de3SAl Viro int error; 750ac565de3SAl Viro 751ac565de3SAl Viro error = vfs_stat(filename, &stat); 752ac565de3SAl Viro if (error) 753ac565de3SAl Viro return error; 754ac565de3SAl Viro return cp_compat_stat(&stat, statbuf); 755ac565de3SAl Viro } 756ac565de3SAl Viro 757ac565de3SAl Viro COMPAT_SYSCALL_DEFINE2(newlstat, const char __user *, filename, 758ac565de3SAl Viro struct compat_stat __user *, statbuf) 759ac565de3SAl Viro { 760ac565de3SAl Viro struct kstat stat; 761ac565de3SAl Viro int error; 762ac565de3SAl Viro 763ac565de3SAl Viro error = vfs_lstat(filename, &stat); 764ac565de3SAl Viro if (error) 765ac565de3SAl Viro return error; 766ac565de3SAl Viro return cp_compat_stat(&stat, statbuf); 767ac565de3SAl Viro } 768ac565de3SAl Viro 769ac565de3SAl Viro #ifndef __ARCH_WANT_STAT64 770ac565de3SAl Viro COMPAT_SYSCALL_DEFINE4(newfstatat, unsigned int, dfd, 771ac565de3SAl Viro const char __user *, filename, 772ac565de3SAl Viro struct compat_stat __user *, statbuf, int, flag) 773ac565de3SAl Viro { 774ac565de3SAl Viro struct kstat stat; 775ac565de3SAl Viro int error; 776ac565de3SAl Viro 777ac565de3SAl Viro error = vfs_fstatat(dfd, filename, &stat, flag); 778ac565de3SAl Viro if (error) 779ac565de3SAl Viro return error; 780ac565de3SAl Viro return cp_compat_stat(&stat, statbuf); 781ac565de3SAl Viro } 782ac565de3SAl Viro #endif 783ac565de3SAl Viro 784ac565de3SAl Viro COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd, 785ac565de3SAl Viro struct compat_stat __user *, statbuf) 786ac565de3SAl Viro { 787ac565de3SAl Viro struct kstat stat; 788ac565de3SAl Viro int error = vfs_fstat(fd, &stat); 789ac565de3SAl Viro 790ac565de3SAl Viro if (!error) 791ac565de3SAl Viro error = cp_compat_stat(&stat, statbuf); 792ac565de3SAl Viro return error; 793ac565de3SAl Viro } 794ac565de3SAl Viro #endif 795ac565de3SAl Viro 796b462707eSDmitry Monakhov /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ 797b462707eSDmitry Monakhov void __inode_add_bytes(struct inode *inode, loff_t bytes) 7981da177e4SLinus Torvalds { 7991da177e4SLinus Torvalds inode->i_blocks += bytes >> 9; 8001da177e4SLinus Torvalds bytes &= 511; 8011da177e4SLinus Torvalds inode->i_bytes += bytes; 8021da177e4SLinus Torvalds if (inode->i_bytes >= 512) { 8031da177e4SLinus Torvalds inode->i_blocks++; 8041da177e4SLinus Torvalds inode->i_bytes -= 512; 8051da177e4SLinus Torvalds } 806b462707eSDmitry Monakhov } 807eb315d2aSAl Viro EXPORT_SYMBOL(__inode_add_bytes); 808b462707eSDmitry Monakhov 809b462707eSDmitry Monakhov void inode_add_bytes(struct inode *inode, loff_t bytes) 810b462707eSDmitry Monakhov { 811b462707eSDmitry Monakhov spin_lock(&inode->i_lock); 812b462707eSDmitry Monakhov __inode_add_bytes(inode, bytes); 8131da177e4SLinus Torvalds spin_unlock(&inode->i_lock); 8141da177e4SLinus Torvalds } 8151da177e4SLinus Torvalds 8161da177e4SLinus Torvalds EXPORT_SYMBOL(inode_add_bytes); 8171da177e4SLinus Torvalds 8181c8924ebSJan Kara void __inode_sub_bytes(struct inode *inode, loff_t bytes) 8191da177e4SLinus Torvalds { 8201da177e4SLinus Torvalds inode->i_blocks -= bytes >> 9; 8211da177e4SLinus Torvalds bytes &= 511; 8221da177e4SLinus Torvalds if (inode->i_bytes < bytes) { 8231da177e4SLinus Torvalds inode->i_blocks--; 8241da177e4SLinus Torvalds inode->i_bytes += 512; 8251da177e4SLinus Torvalds } 8261da177e4SLinus Torvalds inode->i_bytes -= bytes; 8271c8924ebSJan Kara } 8281c8924ebSJan Kara 8291c8924ebSJan Kara EXPORT_SYMBOL(__inode_sub_bytes); 8301c8924ebSJan Kara 8311c8924ebSJan Kara void inode_sub_bytes(struct inode *inode, loff_t bytes) 8321c8924ebSJan Kara { 8331c8924ebSJan Kara spin_lock(&inode->i_lock); 8341c8924ebSJan Kara __inode_sub_bytes(inode, bytes); 8351da177e4SLinus Torvalds spin_unlock(&inode->i_lock); 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds EXPORT_SYMBOL(inode_sub_bytes); 8391da177e4SLinus Torvalds 8401da177e4SLinus Torvalds loff_t inode_get_bytes(struct inode *inode) 8411da177e4SLinus Torvalds { 8421da177e4SLinus Torvalds loff_t ret; 8431da177e4SLinus Torvalds 8441da177e4SLinus Torvalds spin_lock(&inode->i_lock); 845f4a8116aSJan Kara ret = __inode_get_bytes(inode); 8461da177e4SLinus Torvalds spin_unlock(&inode->i_lock); 8471da177e4SLinus Torvalds return ret; 8481da177e4SLinus Torvalds } 8491da177e4SLinus Torvalds 8501da177e4SLinus Torvalds EXPORT_SYMBOL(inode_get_bytes); 8511da177e4SLinus Torvalds 8521da177e4SLinus Torvalds void inode_set_bytes(struct inode *inode, loff_t bytes) 8531da177e4SLinus Torvalds { 8541da177e4SLinus Torvalds /* Caller is here responsible for sufficient locking 8551da177e4SLinus Torvalds * (ie. inode->i_lock) */ 8561da177e4SLinus Torvalds inode->i_blocks = bytes >> 9; 8571da177e4SLinus Torvalds inode->i_bytes = bytes & 511; 8581da177e4SLinus Torvalds } 8591da177e4SLinus Torvalds 8601da177e4SLinus Torvalds EXPORT_SYMBOL(inode_set_bytes); 861