162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/stat.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/blkdev.h> 962306a36Sopenharmony_ci#include <linux/export.h> 1062306a36Sopenharmony_ci#include <linux/mm.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/file.h> 1362306a36Sopenharmony_ci#include <linux/highuid.h> 1462306a36Sopenharmony_ci#include <linux/fs.h> 1562306a36Sopenharmony_ci#include <linux/namei.h> 1662306a36Sopenharmony_ci#include <linux/security.h> 1762306a36Sopenharmony_ci#include <linux/cred.h> 1862306a36Sopenharmony_ci#include <linux/syscalls.h> 1962306a36Sopenharmony_ci#include <linux/pagemap.h> 2062306a36Sopenharmony_ci#include <linux/compat.h> 2162306a36Sopenharmony_ci#include <linux/iversion.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/uaccess.h> 2462306a36Sopenharmony_ci#include <asm/unistd.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "internal.h" 2762306a36Sopenharmony_ci#include "mount.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/** 3062306a36Sopenharmony_ci * generic_fillattr - Fill in the basic attributes from the inode struct 3162306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 3262306a36Sopenharmony_ci * @request_mask: statx request_mask 3362306a36Sopenharmony_ci * @inode: Inode to use as the source 3462306a36Sopenharmony_ci * @stat: Where to fill in the attributes 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * Fill in the basic attributes in the kstat structure from data that's to be 3762306a36Sopenharmony_ci * found on the VFS inode structure. This is the default if no getattr inode 3862306a36Sopenharmony_ci * operation is supplied. 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 4162306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then 4262306a36Sopenharmony_ci * take care to map the inode according to @idmap before filling in the 4362306a36Sopenharmony_ci * uid and gid filds. On non-idmapped mounts or if permission checking is to be 4462306a36Sopenharmony_ci * performed on the raw inode simply passs @nop_mnt_idmap. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_civoid generic_fillattr(struct mnt_idmap *idmap, u32 request_mask, 4762306a36Sopenharmony_ci struct inode *inode, struct kstat *stat) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode); 5062306a36Sopenharmony_ci vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci stat->dev = inode->i_sb->s_dev; 5362306a36Sopenharmony_ci stat->ino = inode->i_ino; 5462306a36Sopenharmony_ci stat->mode = inode->i_mode; 5562306a36Sopenharmony_ci stat->nlink = inode->i_nlink; 5662306a36Sopenharmony_ci stat->uid = vfsuid_into_kuid(vfsuid); 5762306a36Sopenharmony_ci stat->gid = vfsgid_into_kgid(vfsgid); 5862306a36Sopenharmony_ci stat->rdev = inode->i_rdev; 5962306a36Sopenharmony_ci stat->size = i_size_read(inode); 6062306a36Sopenharmony_ci stat->atime = inode->i_atime; 6162306a36Sopenharmony_ci stat->mtime = inode->i_mtime; 6262306a36Sopenharmony_ci stat->ctime = inode_get_ctime(inode); 6362306a36Sopenharmony_ci stat->blksize = i_blocksize(inode); 6462306a36Sopenharmony_ci stat->blocks = inode->i_blocks; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if ((request_mask & STATX_CHANGE_COOKIE) && IS_I_VERSION(inode)) { 6762306a36Sopenharmony_ci stat->result_mask |= STATX_CHANGE_COOKIE; 6862306a36Sopenharmony_ci stat->change_cookie = inode_query_iversion(inode); 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ciEXPORT_SYMBOL(generic_fillattr); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/** 7562306a36Sopenharmony_ci * generic_fill_statx_attr - Fill in the statx attributes from the inode flags 7662306a36Sopenharmony_ci * @inode: Inode to use as the source 7762306a36Sopenharmony_ci * @stat: Where to fill in the attribute flags 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * Fill in the STATX_ATTR_* flags in the kstat structure for properties of the 8062306a36Sopenharmony_ci * inode that are published on i_flags and enforced by the VFS. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_civoid generic_fill_statx_attr(struct inode *inode, struct kstat *stat) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci if (inode->i_flags & S_IMMUTABLE) 8562306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_IMMUTABLE; 8662306a36Sopenharmony_ci if (inode->i_flags & S_APPEND) 8762306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_APPEND; 8862306a36Sopenharmony_ci stat->attributes_mask |= KSTAT_ATTR_VFS_FLAGS; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ciEXPORT_SYMBOL(generic_fill_statx_attr); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/** 9362306a36Sopenharmony_ci * vfs_getattr_nosec - getattr without security checks 9462306a36Sopenharmony_ci * @path: file to get attributes from 9562306a36Sopenharmony_ci * @stat: structure to return attributes in 9662306a36Sopenharmony_ci * @request_mask: STATX_xxx flags indicating what the caller wants 9762306a36Sopenharmony_ci * @query_flags: Query mode (AT_STATX_SYNC_TYPE) 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * Get attributes without calling security_inode_getattr. 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * Currently the only caller other than vfs_getattr is internal to the 10262306a36Sopenharmony_ci * filehandle lookup code, which uses only the inode number and returns no 10362306a36Sopenharmony_ci * attributes to any user. Any other code probably wants vfs_getattr. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ciint vfs_getattr_nosec(const struct path *path, struct kstat *stat, 10662306a36Sopenharmony_ci u32 request_mask, unsigned int query_flags) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct mnt_idmap *idmap; 10962306a36Sopenharmony_ci struct inode *inode = d_backing_inode(path->dentry); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci memset(stat, 0, sizeof(*stat)); 11262306a36Sopenharmony_ci stat->result_mask |= STATX_BASIC_STATS; 11362306a36Sopenharmony_ci query_flags &= AT_STATX_SYNC_TYPE; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* allow the fs to override these if it really wants to */ 11662306a36Sopenharmony_ci /* SB_NOATIME means filesystem supplies dummy atime value */ 11762306a36Sopenharmony_ci if (inode->i_sb->s_flags & SB_NOATIME) 11862306a36Sopenharmony_ci stat->result_mask &= ~STATX_ATIME; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* 12162306a36Sopenharmony_ci * Note: If you add another clause to set an attribute flag, please 12262306a36Sopenharmony_ci * update attributes_mask below. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci if (IS_AUTOMOUNT(inode)) 12562306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_AUTOMOUNT; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (IS_DAX(inode)) 12862306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_DAX; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci stat->attributes_mask |= (STATX_ATTR_AUTOMOUNT | 13162306a36Sopenharmony_ci STATX_ATTR_DAX); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci idmap = mnt_idmap(path->mnt); 13462306a36Sopenharmony_ci if (inode->i_op->getattr) 13562306a36Sopenharmony_ci return inode->i_op->getattr(idmap, path, stat, 13662306a36Sopenharmony_ci request_mask, 13762306a36Sopenharmony_ci query_flags | AT_GETATTR_NOSEC); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci generic_fillattr(idmap, request_mask, inode, stat); 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_getattr_nosec); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* 14562306a36Sopenharmony_ci * vfs_getattr - Get the enhanced basic attributes of a file 14662306a36Sopenharmony_ci * @path: The file of interest 14762306a36Sopenharmony_ci * @stat: Where to return the statistics 14862306a36Sopenharmony_ci * @request_mask: STATX_xxx flags indicating what the caller wants 14962306a36Sopenharmony_ci * @query_flags: Query mode (AT_STATX_SYNC_TYPE) 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * Ask the filesystem for a file's attributes. The caller must indicate in 15262306a36Sopenharmony_ci * request_mask and query_flags to indicate what they want. 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci * If the file is remote, the filesystem can be forced to update the attributes 15562306a36Sopenharmony_ci * from the backing store by passing AT_STATX_FORCE_SYNC in query_flags or can 15662306a36Sopenharmony_ci * suppress the update by passing AT_STATX_DONT_SYNC. 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * Bits must have been set in request_mask to indicate which attributes the 15962306a36Sopenharmony_ci * caller wants retrieving. Any such attribute not requested may be returned 16062306a36Sopenharmony_ci * anyway, but the value may be approximate, and, if remote, may not have been 16162306a36Sopenharmony_ci * synchronised with the server. 16262306a36Sopenharmony_ci * 16362306a36Sopenharmony_ci * 0 will be returned on success, and a -ve error code if unsuccessful. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ciint vfs_getattr(const struct path *path, struct kstat *stat, 16662306a36Sopenharmony_ci u32 request_mask, unsigned int query_flags) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci int retval; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (WARN_ON_ONCE(query_flags & AT_GETATTR_NOSEC)) 17162306a36Sopenharmony_ci return -EPERM; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci retval = security_inode_getattr(path); 17462306a36Sopenharmony_ci if (retval) 17562306a36Sopenharmony_ci return retval; 17662306a36Sopenharmony_ci return vfs_getattr_nosec(path, stat, request_mask, query_flags); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_getattr); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/** 18162306a36Sopenharmony_ci * vfs_fstat - Get the basic attributes by file descriptor 18262306a36Sopenharmony_ci * @fd: The file descriptor referring to the file of interest 18362306a36Sopenharmony_ci * @stat: The result structure to fill in. 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * This function is a wrapper around vfs_getattr(). The main difference is 18662306a36Sopenharmony_ci * that it uses a file descriptor to determine the file location. 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * 0 will be returned on success, and a -ve error code if unsuccessful. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ciint vfs_fstat(int fd, struct kstat *stat) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct fd f; 19362306a36Sopenharmony_ci int error; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci f = fdget_raw(fd); 19662306a36Sopenharmony_ci if (!f.file) 19762306a36Sopenharmony_ci return -EBADF; 19862306a36Sopenharmony_ci error = vfs_getattr(&f.file->f_path, stat, STATX_BASIC_STATS, 0); 19962306a36Sopenharmony_ci fdput(f); 20062306a36Sopenharmony_ci return error; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ciint getname_statx_lookup_flags(int flags) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci int lookup_flags = 0; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (!(flags & AT_SYMLINK_NOFOLLOW)) 20862306a36Sopenharmony_ci lookup_flags |= LOOKUP_FOLLOW; 20962306a36Sopenharmony_ci if (!(flags & AT_NO_AUTOMOUNT)) 21062306a36Sopenharmony_ci lookup_flags |= LOOKUP_AUTOMOUNT; 21162306a36Sopenharmony_ci if (flags & AT_EMPTY_PATH) 21262306a36Sopenharmony_ci lookup_flags |= LOOKUP_EMPTY; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return lookup_flags; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/** 21862306a36Sopenharmony_ci * vfs_statx - Get basic and extra attributes by filename 21962306a36Sopenharmony_ci * @dfd: A file descriptor representing the base dir for a relative filename 22062306a36Sopenharmony_ci * @filename: The name of the file of interest 22162306a36Sopenharmony_ci * @flags: Flags to control the query 22262306a36Sopenharmony_ci * @stat: The result structure to fill in. 22362306a36Sopenharmony_ci * @request_mask: STATX_xxx flags indicating what the caller wants 22462306a36Sopenharmony_ci * 22562306a36Sopenharmony_ci * This function is a wrapper around vfs_getattr(). The main difference is 22662306a36Sopenharmony_ci * that it uses a filename and base directory to determine the file location. 22762306a36Sopenharmony_ci * Additionally, the use of AT_SYMLINK_NOFOLLOW in flags will prevent a symlink 22862306a36Sopenharmony_ci * at the given name from being referenced. 22962306a36Sopenharmony_ci * 23062306a36Sopenharmony_ci * 0 will be returned on success, and a -ve error code if unsuccessful. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_cistatic int vfs_statx(int dfd, struct filename *filename, int flags, 23362306a36Sopenharmony_ci struct kstat *stat, u32 request_mask) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct path path; 23662306a36Sopenharmony_ci unsigned int lookup_flags = getname_statx_lookup_flags(flags); 23762306a36Sopenharmony_ci int error; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH | 24062306a36Sopenharmony_ci AT_STATX_SYNC_TYPE)) 24162306a36Sopenharmony_ci return -EINVAL; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ciretry: 24462306a36Sopenharmony_ci error = filename_lookup(dfd, filename, lookup_flags, &path, NULL); 24562306a36Sopenharmony_ci if (error) 24662306a36Sopenharmony_ci goto out; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci error = vfs_getattr(&path, stat, request_mask, flags); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci stat->mnt_id = real_mount(path.mnt)->mnt_id; 25162306a36Sopenharmony_ci stat->result_mask |= STATX_MNT_ID; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (path.mnt->mnt_root == path.dentry) 25462306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_MOUNT_ROOT; 25562306a36Sopenharmony_ci stat->attributes_mask |= STATX_ATTR_MOUNT_ROOT; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* Handle STATX_DIOALIGN for block devices. */ 25862306a36Sopenharmony_ci if (request_mask & STATX_DIOALIGN) { 25962306a36Sopenharmony_ci struct inode *inode = d_backing_inode(path.dentry); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (S_ISBLK(inode->i_mode)) 26262306a36Sopenharmony_ci bdev_statx_dioalign(inode, stat); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci path_put(&path); 26662306a36Sopenharmony_ci if (retry_estale(error, lookup_flags)) { 26762306a36Sopenharmony_ci lookup_flags |= LOOKUP_REVAL; 26862306a36Sopenharmony_ci goto retry; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ciout: 27162306a36Sopenharmony_ci return error; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ciint vfs_fstatat(int dfd, const char __user *filename, 27562306a36Sopenharmony_ci struct kstat *stat, int flags) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci int ret; 27862306a36Sopenharmony_ci int statx_flags = flags | AT_NO_AUTOMOUNT; 27962306a36Sopenharmony_ci struct filename *name; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* 28262306a36Sopenharmony_ci * Work around glibc turning fstat() into fstatat(AT_EMPTY_PATH) 28362306a36Sopenharmony_ci * 28462306a36Sopenharmony_ci * If AT_EMPTY_PATH is set, we expect the common case to be that 28562306a36Sopenharmony_ci * empty path, and avoid doing all the extra pathname work. 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ci if (dfd >= 0 && flags == AT_EMPTY_PATH) { 28862306a36Sopenharmony_ci char c; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci ret = get_user(c, filename); 29162306a36Sopenharmony_ci if (unlikely(ret)) 29262306a36Sopenharmony_ci return ret; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (likely(!c)) 29562306a36Sopenharmony_ci return vfs_fstat(dfd, stat); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci name = getname_flags(filename, getname_statx_lookup_flags(statx_flags), NULL); 29962306a36Sopenharmony_ci ret = vfs_statx(dfd, name, statx_flags, stat, STATX_BASIC_STATS); 30062306a36Sopenharmony_ci putname(name); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return ret; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci#ifdef __ARCH_WANT_OLD_STAT 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/* 30862306a36Sopenharmony_ci * For backward compatibility? Maybe this should be moved 30962306a36Sopenharmony_ci * into arch/i386 instead? 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_cistatic int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * statbuf) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci static int warncount = 5; 31462306a36Sopenharmony_ci struct __old_kernel_stat tmp; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (warncount > 0) { 31762306a36Sopenharmony_ci warncount--; 31862306a36Sopenharmony_ci printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", 31962306a36Sopenharmony_ci current->comm); 32062306a36Sopenharmony_ci } else if (warncount < 0) { 32162306a36Sopenharmony_ci /* it's laughable, but... */ 32262306a36Sopenharmony_ci warncount = 0; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci memset(&tmp, 0, sizeof(struct __old_kernel_stat)); 32662306a36Sopenharmony_ci tmp.st_dev = old_encode_dev(stat->dev); 32762306a36Sopenharmony_ci tmp.st_ino = stat->ino; 32862306a36Sopenharmony_ci if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 32962306a36Sopenharmony_ci return -EOVERFLOW; 33062306a36Sopenharmony_ci tmp.st_mode = stat->mode; 33162306a36Sopenharmony_ci tmp.st_nlink = stat->nlink; 33262306a36Sopenharmony_ci if (tmp.st_nlink != stat->nlink) 33362306a36Sopenharmony_ci return -EOVERFLOW; 33462306a36Sopenharmony_ci SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); 33562306a36Sopenharmony_ci SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); 33662306a36Sopenharmony_ci tmp.st_rdev = old_encode_dev(stat->rdev); 33762306a36Sopenharmony_ci#if BITS_PER_LONG == 32 33862306a36Sopenharmony_ci if (stat->size > MAX_NON_LFS) 33962306a36Sopenharmony_ci return -EOVERFLOW; 34062306a36Sopenharmony_ci#endif 34162306a36Sopenharmony_ci tmp.st_size = stat->size; 34262306a36Sopenharmony_ci tmp.st_atime = stat->atime.tv_sec; 34362306a36Sopenharmony_ci tmp.st_mtime = stat->mtime.tv_sec; 34462306a36Sopenharmony_ci tmp.st_ctime = stat->ctime.tv_sec; 34562306a36Sopenharmony_ci return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ciSYSCALL_DEFINE2(stat, const char __user *, filename, 34962306a36Sopenharmony_ci struct __old_kernel_stat __user *, statbuf) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct kstat stat; 35262306a36Sopenharmony_ci int error; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci error = vfs_stat(filename, &stat); 35562306a36Sopenharmony_ci if (error) 35662306a36Sopenharmony_ci return error; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return cp_old_stat(&stat, statbuf); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ciSYSCALL_DEFINE2(lstat, const char __user *, filename, 36262306a36Sopenharmony_ci struct __old_kernel_stat __user *, statbuf) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct kstat stat; 36562306a36Sopenharmony_ci int error; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci error = vfs_lstat(filename, &stat); 36862306a36Sopenharmony_ci if (error) 36962306a36Sopenharmony_ci return error; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return cp_old_stat(&stat, statbuf); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ciSYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, statbuf) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct kstat stat; 37762306a36Sopenharmony_ci int error = vfs_fstat(fd, &stat); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (!error) 38062306a36Sopenharmony_ci error = cp_old_stat(&stat, statbuf); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return error; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci#endif /* __ARCH_WANT_OLD_STAT */ 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci#ifdef __ARCH_WANT_NEW_STAT 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci#ifndef INIT_STRUCT_STAT_PADDING 39062306a36Sopenharmony_ci# define INIT_STRUCT_STAT_PADDING(st) memset(&st, 0, sizeof(st)) 39162306a36Sopenharmony_ci#endif 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct stat tmp; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (sizeof(tmp.st_dev) < 4 && !old_valid_dev(stat->dev)) 39862306a36Sopenharmony_ci return -EOVERFLOW; 39962306a36Sopenharmony_ci if (sizeof(tmp.st_rdev) < 4 && !old_valid_dev(stat->rdev)) 40062306a36Sopenharmony_ci return -EOVERFLOW; 40162306a36Sopenharmony_ci#if BITS_PER_LONG == 32 40262306a36Sopenharmony_ci if (stat->size > MAX_NON_LFS) 40362306a36Sopenharmony_ci return -EOVERFLOW; 40462306a36Sopenharmony_ci#endif 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci INIT_STRUCT_STAT_PADDING(tmp); 40762306a36Sopenharmony_ci tmp.st_dev = new_encode_dev(stat->dev); 40862306a36Sopenharmony_ci tmp.st_ino = stat->ino; 40962306a36Sopenharmony_ci if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 41062306a36Sopenharmony_ci return -EOVERFLOW; 41162306a36Sopenharmony_ci tmp.st_mode = stat->mode; 41262306a36Sopenharmony_ci tmp.st_nlink = stat->nlink; 41362306a36Sopenharmony_ci if (tmp.st_nlink != stat->nlink) 41462306a36Sopenharmony_ci return -EOVERFLOW; 41562306a36Sopenharmony_ci SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); 41662306a36Sopenharmony_ci SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); 41762306a36Sopenharmony_ci tmp.st_rdev = new_encode_dev(stat->rdev); 41862306a36Sopenharmony_ci tmp.st_size = stat->size; 41962306a36Sopenharmony_ci tmp.st_atime = stat->atime.tv_sec; 42062306a36Sopenharmony_ci tmp.st_mtime = stat->mtime.tv_sec; 42162306a36Sopenharmony_ci tmp.st_ctime = stat->ctime.tv_sec; 42262306a36Sopenharmony_ci#ifdef STAT_HAVE_NSEC 42362306a36Sopenharmony_ci tmp.st_atime_nsec = stat->atime.tv_nsec; 42462306a36Sopenharmony_ci tmp.st_mtime_nsec = stat->mtime.tv_nsec; 42562306a36Sopenharmony_ci tmp.st_ctime_nsec = stat->ctime.tv_nsec; 42662306a36Sopenharmony_ci#endif 42762306a36Sopenharmony_ci tmp.st_blocks = stat->blocks; 42862306a36Sopenharmony_ci tmp.st_blksize = stat->blksize; 42962306a36Sopenharmony_ci return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ciSYSCALL_DEFINE2(newstat, const char __user *, filename, 43362306a36Sopenharmony_ci struct stat __user *, statbuf) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct kstat stat; 43662306a36Sopenharmony_ci int error = vfs_stat(filename, &stat); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (error) 43962306a36Sopenharmony_ci return error; 44062306a36Sopenharmony_ci return cp_new_stat(&stat, statbuf); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ciSYSCALL_DEFINE2(newlstat, const char __user *, filename, 44462306a36Sopenharmony_ci struct stat __user *, statbuf) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct kstat stat; 44762306a36Sopenharmony_ci int error; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci error = vfs_lstat(filename, &stat); 45062306a36Sopenharmony_ci if (error) 45162306a36Sopenharmony_ci return error; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return cp_new_stat(&stat, statbuf); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci#if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT) 45762306a36Sopenharmony_ciSYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename, 45862306a36Sopenharmony_ci struct stat __user *, statbuf, int, flag) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct kstat stat; 46162306a36Sopenharmony_ci int error; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci error = vfs_fstatat(dfd, filename, &stat, flag); 46462306a36Sopenharmony_ci if (error) 46562306a36Sopenharmony_ci return error; 46662306a36Sopenharmony_ci return cp_new_stat(&stat, statbuf); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci#endif 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ciSYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci struct kstat stat; 47362306a36Sopenharmony_ci int error = vfs_fstat(fd, &stat); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (!error) 47662306a36Sopenharmony_ci error = cp_new_stat(&stat, statbuf); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return error; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci#endif 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic int do_readlinkat(int dfd, const char __user *pathname, 48362306a36Sopenharmony_ci char __user *buf, int bufsiz) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct path path; 48662306a36Sopenharmony_ci int error; 48762306a36Sopenharmony_ci int empty = 0; 48862306a36Sopenharmony_ci unsigned int lookup_flags = LOOKUP_EMPTY; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (bufsiz <= 0) 49162306a36Sopenharmony_ci return -EINVAL; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ciretry: 49462306a36Sopenharmony_ci error = user_path_at_empty(dfd, pathname, lookup_flags, &path, &empty); 49562306a36Sopenharmony_ci if (!error) { 49662306a36Sopenharmony_ci struct inode *inode = d_backing_inode(path.dentry); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci error = empty ? -ENOENT : -EINVAL; 49962306a36Sopenharmony_ci /* 50062306a36Sopenharmony_ci * AFS mountpoints allow readlink(2) but are not symlinks 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci if (d_is_symlink(path.dentry) || inode->i_op->readlink) { 50362306a36Sopenharmony_ci error = security_inode_readlink(path.dentry); 50462306a36Sopenharmony_ci if (!error) { 50562306a36Sopenharmony_ci touch_atime(&path); 50662306a36Sopenharmony_ci error = vfs_readlink(path.dentry, buf, bufsiz); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci path_put(&path); 51062306a36Sopenharmony_ci if (retry_estale(error, lookup_flags)) { 51162306a36Sopenharmony_ci lookup_flags |= LOOKUP_REVAL; 51262306a36Sopenharmony_ci goto retry; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci return error; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ciSYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, 51962306a36Sopenharmony_ci char __user *, buf, int, bufsiz) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci return do_readlinkat(dfd, pathname, buf, bufsiz); 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ciSYSCALL_DEFINE3(readlink, const char __user *, path, char __user *, buf, 52562306a36Sopenharmony_ci int, bufsiz) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci return do_readlinkat(AT_FDCWD, path, buf, bufsiz); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci/* ---------- LFS-64 ----------- */ 53262306a36Sopenharmony_ci#if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64) 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci#ifndef INIT_STRUCT_STAT64_PADDING 53562306a36Sopenharmony_ci# define INIT_STRUCT_STAT64_PADDING(st) memset(&st, 0, sizeof(st)) 53662306a36Sopenharmony_ci#endif 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct stat64 tmp; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci INIT_STRUCT_STAT64_PADDING(tmp); 54362306a36Sopenharmony_ci#ifdef CONFIG_MIPS 54462306a36Sopenharmony_ci /* mips has weird padding, so we don't get 64 bits there */ 54562306a36Sopenharmony_ci tmp.st_dev = new_encode_dev(stat->dev); 54662306a36Sopenharmony_ci tmp.st_rdev = new_encode_dev(stat->rdev); 54762306a36Sopenharmony_ci#else 54862306a36Sopenharmony_ci tmp.st_dev = huge_encode_dev(stat->dev); 54962306a36Sopenharmony_ci tmp.st_rdev = huge_encode_dev(stat->rdev); 55062306a36Sopenharmony_ci#endif 55162306a36Sopenharmony_ci tmp.st_ino = stat->ino; 55262306a36Sopenharmony_ci if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 55362306a36Sopenharmony_ci return -EOVERFLOW; 55462306a36Sopenharmony_ci#ifdef STAT64_HAS_BROKEN_ST_INO 55562306a36Sopenharmony_ci tmp.__st_ino = stat->ino; 55662306a36Sopenharmony_ci#endif 55762306a36Sopenharmony_ci tmp.st_mode = stat->mode; 55862306a36Sopenharmony_ci tmp.st_nlink = stat->nlink; 55962306a36Sopenharmony_ci tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid); 56062306a36Sopenharmony_ci tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid); 56162306a36Sopenharmony_ci tmp.st_atime = stat->atime.tv_sec; 56262306a36Sopenharmony_ci tmp.st_atime_nsec = stat->atime.tv_nsec; 56362306a36Sopenharmony_ci tmp.st_mtime = stat->mtime.tv_sec; 56462306a36Sopenharmony_ci tmp.st_mtime_nsec = stat->mtime.tv_nsec; 56562306a36Sopenharmony_ci tmp.st_ctime = stat->ctime.tv_sec; 56662306a36Sopenharmony_ci tmp.st_ctime_nsec = stat->ctime.tv_nsec; 56762306a36Sopenharmony_ci tmp.st_size = stat->size; 56862306a36Sopenharmony_ci tmp.st_blocks = stat->blocks; 56962306a36Sopenharmony_ci tmp.st_blksize = stat->blksize; 57062306a36Sopenharmony_ci return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ciSYSCALL_DEFINE2(stat64, const char __user *, filename, 57462306a36Sopenharmony_ci struct stat64 __user *, statbuf) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct kstat stat; 57762306a36Sopenharmony_ci int error = vfs_stat(filename, &stat); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (!error) 58062306a36Sopenharmony_ci error = cp_new_stat64(&stat, statbuf); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return error; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ciSYSCALL_DEFINE2(lstat64, const char __user *, filename, 58662306a36Sopenharmony_ci struct stat64 __user *, statbuf) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct kstat stat; 58962306a36Sopenharmony_ci int error = vfs_lstat(filename, &stat); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (!error) 59262306a36Sopenharmony_ci error = cp_new_stat64(&stat, statbuf); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci return error; 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ciSYSCALL_DEFINE2(fstat64, unsigned long, fd, struct stat64 __user *, statbuf) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci struct kstat stat; 60062306a36Sopenharmony_ci int error = vfs_fstat(fd, &stat); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (!error) 60362306a36Sopenharmony_ci error = cp_new_stat64(&stat, statbuf); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci return error; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ciSYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename, 60962306a36Sopenharmony_ci struct stat64 __user *, statbuf, int, flag) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct kstat stat; 61262306a36Sopenharmony_ci int error; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci error = vfs_fstatat(dfd, filename, &stat, flag); 61562306a36Sopenharmony_ci if (error) 61662306a36Sopenharmony_ci return error; 61762306a36Sopenharmony_ci return cp_new_stat64(&stat, statbuf); 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci#endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */ 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic noinline_for_stack int 62262306a36Sopenharmony_cicp_statx(const struct kstat *stat, struct statx __user *buffer) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci struct statx tmp; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci memset(&tmp, 0, sizeof(tmp)); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* STATX_CHANGE_COOKIE is kernel-only for now */ 62962306a36Sopenharmony_ci tmp.stx_mask = stat->result_mask & ~STATX_CHANGE_COOKIE; 63062306a36Sopenharmony_ci tmp.stx_blksize = stat->blksize; 63162306a36Sopenharmony_ci /* STATX_ATTR_CHANGE_MONOTONIC is kernel-only for now */ 63262306a36Sopenharmony_ci tmp.stx_attributes = stat->attributes & ~STATX_ATTR_CHANGE_MONOTONIC; 63362306a36Sopenharmony_ci tmp.stx_nlink = stat->nlink; 63462306a36Sopenharmony_ci tmp.stx_uid = from_kuid_munged(current_user_ns(), stat->uid); 63562306a36Sopenharmony_ci tmp.stx_gid = from_kgid_munged(current_user_ns(), stat->gid); 63662306a36Sopenharmony_ci tmp.stx_mode = stat->mode; 63762306a36Sopenharmony_ci tmp.stx_ino = stat->ino; 63862306a36Sopenharmony_ci tmp.stx_size = stat->size; 63962306a36Sopenharmony_ci tmp.stx_blocks = stat->blocks; 64062306a36Sopenharmony_ci tmp.stx_attributes_mask = stat->attributes_mask; 64162306a36Sopenharmony_ci tmp.stx_atime.tv_sec = stat->atime.tv_sec; 64262306a36Sopenharmony_ci tmp.stx_atime.tv_nsec = stat->atime.tv_nsec; 64362306a36Sopenharmony_ci tmp.stx_btime.tv_sec = stat->btime.tv_sec; 64462306a36Sopenharmony_ci tmp.stx_btime.tv_nsec = stat->btime.tv_nsec; 64562306a36Sopenharmony_ci tmp.stx_ctime.tv_sec = stat->ctime.tv_sec; 64662306a36Sopenharmony_ci tmp.stx_ctime.tv_nsec = stat->ctime.tv_nsec; 64762306a36Sopenharmony_ci tmp.stx_mtime.tv_sec = stat->mtime.tv_sec; 64862306a36Sopenharmony_ci tmp.stx_mtime.tv_nsec = stat->mtime.tv_nsec; 64962306a36Sopenharmony_ci tmp.stx_rdev_major = MAJOR(stat->rdev); 65062306a36Sopenharmony_ci tmp.stx_rdev_minor = MINOR(stat->rdev); 65162306a36Sopenharmony_ci tmp.stx_dev_major = MAJOR(stat->dev); 65262306a36Sopenharmony_ci tmp.stx_dev_minor = MINOR(stat->dev); 65362306a36Sopenharmony_ci tmp.stx_mnt_id = stat->mnt_id; 65462306a36Sopenharmony_ci tmp.stx_dio_mem_align = stat->dio_mem_align; 65562306a36Sopenharmony_ci tmp.stx_dio_offset_align = stat->dio_offset_align; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ciint do_statx(int dfd, struct filename *filename, unsigned int flags, 66162306a36Sopenharmony_ci unsigned int mask, struct statx __user *buffer) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct kstat stat; 66462306a36Sopenharmony_ci int error; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (mask & STATX__RESERVED) 66762306a36Sopenharmony_ci return -EINVAL; 66862306a36Sopenharmony_ci if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE) 66962306a36Sopenharmony_ci return -EINVAL; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* STATX_CHANGE_COOKIE is kernel-only for now. Ignore requests 67262306a36Sopenharmony_ci * from userland. 67362306a36Sopenharmony_ci */ 67462306a36Sopenharmony_ci mask &= ~STATX_CHANGE_COOKIE; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci error = vfs_statx(dfd, filename, flags, &stat, mask); 67762306a36Sopenharmony_ci if (error) 67862306a36Sopenharmony_ci return error; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return cp_statx(&stat, buffer); 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci/** 68462306a36Sopenharmony_ci * sys_statx - System call to get enhanced stats 68562306a36Sopenharmony_ci * @dfd: Base directory to pathwalk from *or* fd to stat. 68662306a36Sopenharmony_ci * @filename: File to stat or "" with AT_EMPTY_PATH 68762306a36Sopenharmony_ci * @flags: AT_* flags to control pathwalk. 68862306a36Sopenharmony_ci * @mask: Parts of statx struct actually required. 68962306a36Sopenharmony_ci * @buffer: Result buffer. 69062306a36Sopenharmony_ci * 69162306a36Sopenharmony_ci * Note that fstat() can be emulated by setting dfd to the fd of interest, 69262306a36Sopenharmony_ci * supplying "" as the filename and setting AT_EMPTY_PATH in the flags. 69362306a36Sopenharmony_ci */ 69462306a36Sopenharmony_ciSYSCALL_DEFINE5(statx, 69562306a36Sopenharmony_ci int, dfd, const char __user *, filename, unsigned, flags, 69662306a36Sopenharmony_ci unsigned int, mask, 69762306a36Sopenharmony_ci struct statx __user *, buffer) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci int ret; 70062306a36Sopenharmony_ci struct filename *name; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci name = getname_flags(filename, getname_statx_lookup_flags(flags), NULL); 70362306a36Sopenharmony_ci ret = do_statx(dfd, name, flags, mask, buffer); 70462306a36Sopenharmony_ci putname(name); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci return ret; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_STAT) 71062306a36Sopenharmony_cistatic int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci struct compat_stat tmp; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (sizeof(tmp.st_dev) < 4 && !old_valid_dev(stat->dev)) 71562306a36Sopenharmony_ci return -EOVERFLOW; 71662306a36Sopenharmony_ci if (sizeof(tmp.st_rdev) < 4 && !old_valid_dev(stat->rdev)) 71762306a36Sopenharmony_ci return -EOVERFLOW; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci memset(&tmp, 0, sizeof(tmp)); 72062306a36Sopenharmony_ci tmp.st_dev = new_encode_dev(stat->dev); 72162306a36Sopenharmony_ci tmp.st_ino = stat->ino; 72262306a36Sopenharmony_ci if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 72362306a36Sopenharmony_ci return -EOVERFLOW; 72462306a36Sopenharmony_ci tmp.st_mode = stat->mode; 72562306a36Sopenharmony_ci tmp.st_nlink = stat->nlink; 72662306a36Sopenharmony_ci if (tmp.st_nlink != stat->nlink) 72762306a36Sopenharmony_ci return -EOVERFLOW; 72862306a36Sopenharmony_ci SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); 72962306a36Sopenharmony_ci SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); 73062306a36Sopenharmony_ci tmp.st_rdev = new_encode_dev(stat->rdev); 73162306a36Sopenharmony_ci if ((u64) stat->size > MAX_NON_LFS) 73262306a36Sopenharmony_ci return -EOVERFLOW; 73362306a36Sopenharmony_ci tmp.st_size = stat->size; 73462306a36Sopenharmony_ci tmp.st_atime = stat->atime.tv_sec; 73562306a36Sopenharmony_ci tmp.st_atime_nsec = stat->atime.tv_nsec; 73662306a36Sopenharmony_ci tmp.st_mtime = stat->mtime.tv_sec; 73762306a36Sopenharmony_ci tmp.st_mtime_nsec = stat->mtime.tv_nsec; 73862306a36Sopenharmony_ci tmp.st_ctime = stat->ctime.tv_sec; 73962306a36Sopenharmony_ci tmp.st_ctime_nsec = stat->ctime.tv_nsec; 74062306a36Sopenharmony_ci tmp.st_blocks = stat->blocks; 74162306a36Sopenharmony_ci tmp.st_blksize = stat->blksize; 74262306a36Sopenharmony_ci return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE2(newstat, const char __user *, filename, 74662306a36Sopenharmony_ci struct compat_stat __user *, statbuf) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci struct kstat stat; 74962306a36Sopenharmony_ci int error; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci error = vfs_stat(filename, &stat); 75262306a36Sopenharmony_ci if (error) 75362306a36Sopenharmony_ci return error; 75462306a36Sopenharmony_ci return cp_compat_stat(&stat, statbuf); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE2(newlstat, const char __user *, filename, 75862306a36Sopenharmony_ci struct compat_stat __user *, statbuf) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci struct kstat stat; 76162306a36Sopenharmony_ci int error; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci error = vfs_lstat(filename, &stat); 76462306a36Sopenharmony_ci if (error) 76562306a36Sopenharmony_ci return error; 76662306a36Sopenharmony_ci return cp_compat_stat(&stat, statbuf); 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci#ifndef __ARCH_WANT_STAT64 77062306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE4(newfstatat, unsigned int, dfd, 77162306a36Sopenharmony_ci const char __user *, filename, 77262306a36Sopenharmony_ci struct compat_stat __user *, statbuf, int, flag) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci struct kstat stat; 77562306a36Sopenharmony_ci int error; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci error = vfs_fstatat(dfd, filename, &stat, flag); 77862306a36Sopenharmony_ci if (error) 77962306a36Sopenharmony_ci return error; 78062306a36Sopenharmony_ci return cp_compat_stat(&stat, statbuf); 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci#endif 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd, 78562306a36Sopenharmony_ci struct compat_stat __user *, statbuf) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci struct kstat stat; 78862306a36Sopenharmony_ci int error = vfs_fstat(fd, &stat); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (!error) 79162306a36Sopenharmony_ci error = cp_compat_stat(&stat, statbuf); 79262306a36Sopenharmony_ci return error; 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci#endif 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci/* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ 79762306a36Sopenharmony_civoid __inode_add_bytes(struct inode *inode, loff_t bytes) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci inode->i_blocks += bytes >> 9; 80062306a36Sopenharmony_ci bytes &= 511; 80162306a36Sopenharmony_ci inode->i_bytes += bytes; 80262306a36Sopenharmony_ci if (inode->i_bytes >= 512) { 80362306a36Sopenharmony_ci inode->i_blocks++; 80462306a36Sopenharmony_ci inode->i_bytes -= 512; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ciEXPORT_SYMBOL(__inode_add_bytes); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_civoid inode_add_bytes(struct inode *inode, loff_t bytes) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci spin_lock(&inode->i_lock); 81262306a36Sopenharmony_ci __inode_add_bytes(inode, bytes); 81362306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ciEXPORT_SYMBOL(inode_add_bytes); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_civoid __inode_sub_bytes(struct inode *inode, loff_t bytes) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci inode->i_blocks -= bytes >> 9; 82162306a36Sopenharmony_ci bytes &= 511; 82262306a36Sopenharmony_ci if (inode->i_bytes < bytes) { 82362306a36Sopenharmony_ci inode->i_blocks--; 82462306a36Sopenharmony_ci inode->i_bytes += 512; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci inode->i_bytes -= bytes; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ciEXPORT_SYMBOL(__inode_sub_bytes); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_civoid inode_sub_bytes(struct inode *inode, loff_t bytes) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci spin_lock(&inode->i_lock); 83462306a36Sopenharmony_ci __inode_sub_bytes(inode, bytes); 83562306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ciEXPORT_SYMBOL(inode_sub_bytes); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ciloff_t inode_get_bytes(struct inode *inode) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci loff_t ret; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci spin_lock(&inode->i_lock); 84562306a36Sopenharmony_ci ret = __inode_get_bytes(inode); 84662306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 84762306a36Sopenharmony_ci return ret; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ciEXPORT_SYMBOL(inode_get_bytes); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_civoid inode_set_bytes(struct inode *inode, loff_t bytes) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci /* Caller is here responsible for sufficient locking 85562306a36Sopenharmony_ci * (ie. inode->i_lock) */ 85662306a36Sopenharmony_ci inode->i_blocks = bytes >> 9; 85762306a36Sopenharmony_ci inode->i_bytes = bytes & 511; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ciEXPORT_SYMBOL(inode_set_bytes); 861