162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/syscalls.h> 362306a36Sopenharmony_ci#include <linux/export.h> 462306a36Sopenharmony_ci#include <linux/fs.h> 562306a36Sopenharmony_ci#include <linux/file.h> 662306a36Sopenharmony_ci#include <linux/mount.h> 762306a36Sopenharmony_ci#include <linux/namei.h> 862306a36Sopenharmony_ci#include <linux/statfs.h> 962306a36Sopenharmony_ci#include <linux/security.h> 1062306a36Sopenharmony_ci#include <linux/uaccess.h> 1162306a36Sopenharmony_ci#include <linux/compat.h> 1262306a36Sopenharmony_ci#include "internal.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic int flags_by_mnt(int mnt_flags) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci int flags = 0; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci if (mnt_flags & MNT_READONLY) 1962306a36Sopenharmony_ci flags |= ST_RDONLY; 2062306a36Sopenharmony_ci if (mnt_flags & MNT_NOSUID) 2162306a36Sopenharmony_ci flags |= ST_NOSUID; 2262306a36Sopenharmony_ci if (mnt_flags & MNT_NODEV) 2362306a36Sopenharmony_ci flags |= ST_NODEV; 2462306a36Sopenharmony_ci if (mnt_flags & MNT_NOEXEC) 2562306a36Sopenharmony_ci flags |= ST_NOEXEC; 2662306a36Sopenharmony_ci if (mnt_flags & MNT_NOATIME) 2762306a36Sopenharmony_ci flags |= ST_NOATIME; 2862306a36Sopenharmony_ci if (mnt_flags & MNT_NODIRATIME) 2962306a36Sopenharmony_ci flags |= ST_NODIRATIME; 3062306a36Sopenharmony_ci if (mnt_flags & MNT_RELATIME) 3162306a36Sopenharmony_ci flags |= ST_RELATIME; 3262306a36Sopenharmony_ci if (mnt_flags & MNT_NOSYMFOLLOW) 3362306a36Sopenharmony_ci flags |= ST_NOSYMFOLLOW; 3462306a36Sopenharmony_ci return flags; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic int flags_by_sb(int s_flags) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci int flags = 0; 4062306a36Sopenharmony_ci if (s_flags & SB_SYNCHRONOUS) 4162306a36Sopenharmony_ci flags |= ST_SYNCHRONOUS; 4262306a36Sopenharmony_ci if (s_flags & SB_MANDLOCK) 4362306a36Sopenharmony_ci flags |= ST_MANDLOCK; 4462306a36Sopenharmony_ci if (s_flags & SB_RDONLY) 4562306a36Sopenharmony_ci flags |= ST_RDONLY; 4662306a36Sopenharmony_ci return flags; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int calculate_f_flags(struct vfsmount *mnt) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci return ST_VALID | flags_by_mnt(mnt->mnt_flags) | 5262306a36Sopenharmony_ci flags_by_sb(mnt->mnt_sb->s_flags); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci int retval; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (!dentry->d_sb->s_op->statfs) 6062306a36Sopenharmony_ci return -ENOSYS; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci memset(buf, 0, sizeof(*buf)); 6362306a36Sopenharmony_ci retval = security_sb_statfs(dentry); 6462306a36Sopenharmony_ci if (retval) 6562306a36Sopenharmony_ci return retval; 6662306a36Sopenharmony_ci retval = dentry->d_sb->s_op->statfs(dentry, buf); 6762306a36Sopenharmony_ci if (retval == 0 && buf->f_frsize == 0) 6862306a36Sopenharmony_ci buf->f_frsize = buf->f_bsize; 6962306a36Sopenharmony_ci return retval; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ciint vfs_get_fsid(struct dentry *dentry, __kernel_fsid_t *fsid) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct kstatfs st; 7562306a36Sopenharmony_ci int error; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci error = statfs_by_dentry(dentry, &st); 7862306a36Sopenharmony_ci if (error) 7962306a36Sopenharmony_ci return error; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci *fsid = st.f_fsid; 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_get_fsid); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciint vfs_statfs(const struct path *path, struct kstatfs *buf) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci int error; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci error = statfs_by_dentry(path->dentry, buf); 9162306a36Sopenharmony_ci if (!error) 9262306a36Sopenharmony_ci buf->f_flags = calculate_f_flags(path->mnt); 9362306a36Sopenharmony_ci return error; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_statfs); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciint user_statfs(const char __user *pathname, struct kstatfs *st) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct path path; 10062306a36Sopenharmony_ci int error; 10162306a36Sopenharmony_ci unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT; 10262306a36Sopenharmony_ciretry: 10362306a36Sopenharmony_ci error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); 10462306a36Sopenharmony_ci if (!error) { 10562306a36Sopenharmony_ci error = vfs_statfs(&path, st); 10662306a36Sopenharmony_ci path_put(&path); 10762306a36Sopenharmony_ci if (retry_estale(error, lookup_flags)) { 10862306a36Sopenharmony_ci lookup_flags |= LOOKUP_REVAL; 10962306a36Sopenharmony_ci goto retry; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci return error; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ciint fd_statfs(int fd, struct kstatfs *st) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct fd f = fdget_raw(fd); 11862306a36Sopenharmony_ci int error = -EBADF; 11962306a36Sopenharmony_ci if (f.file) { 12062306a36Sopenharmony_ci error = vfs_statfs(&f.file->f_path, st); 12162306a36Sopenharmony_ci fdput(f); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci return error; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int do_statfs_native(struct kstatfs *st, struct statfs __user *p) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct statfs buf; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (sizeof(buf) == sizeof(*st)) 13162306a36Sopenharmony_ci memcpy(&buf, st, sizeof(*st)); 13262306a36Sopenharmony_ci else { 13362306a36Sopenharmony_ci memset(&buf, 0, sizeof(buf)); 13462306a36Sopenharmony_ci if (sizeof buf.f_blocks == 4) { 13562306a36Sopenharmony_ci if ((st->f_blocks | st->f_bfree | st->f_bavail | 13662306a36Sopenharmony_ci st->f_bsize | st->f_frsize) & 13762306a36Sopenharmony_ci 0xffffffff00000000ULL) 13862306a36Sopenharmony_ci return -EOVERFLOW; 13962306a36Sopenharmony_ci /* 14062306a36Sopenharmony_ci * f_files and f_ffree may be -1; it's okay to stuff 14162306a36Sopenharmony_ci * that into 32 bits 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci if (st->f_files != -1 && 14462306a36Sopenharmony_ci (st->f_files & 0xffffffff00000000ULL)) 14562306a36Sopenharmony_ci return -EOVERFLOW; 14662306a36Sopenharmony_ci if (st->f_ffree != -1 && 14762306a36Sopenharmony_ci (st->f_ffree & 0xffffffff00000000ULL)) 14862306a36Sopenharmony_ci return -EOVERFLOW; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci buf.f_type = st->f_type; 15262306a36Sopenharmony_ci buf.f_bsize = st->f_bsize; 15362306a36Sopenharmony_ci buf.f_blocks = st->f_blocks; 15462306a36Sopenharmony_ci buf.f_bfree = st->f_bfree; 15562306a36Sopenharmony_ci buf.f_bavail = st->f_bavail; 15662306a36Sopenharmony_ci buf.f_files = st->f_files; 15762306a36Sopenharmony_ci buf.f_ffree = st->f_ffree; 15862306a36Sopenharmony_ci buf.f_fsid = st->f_fsid; 15962306a36Sopenharmony_ci buf.f_namelen = st->f_namelen; 16062306a36Sopenharmony_ci buf.f_frsize = st->f_frsize; 16162306a36Sopenharmony_ci buf.f_flags = st->f_flags; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci if (copy_to_user(p, &buf, sizeof(buf))) 16462306a36Sopenharmony_ci return -EFAULT; 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int do_statfs64(struct kstatfs *st, struct statfs64 __user *p) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct statfs64 buf; 17162306a36Sopenharmony_ci if (sizeof(buf) == sizeof(*st)) 17262306a36Sopenharmony_ci memcpy(&buf, st, sizeof(*st)); 17362306a36Sopenharmony_ci else { 17462306a36Sopenharmony_ci memset(&buf, 0, sizeof(buf)); 17562306a36Sopenharmony_ci buf.f_type = st->f_type; 17662306a36Sopenharmony_ci buf.f_bsize = st->f_bsize; 17762306a36Sopenharmony_ci buf.f_blocks = st->f_blocks; 17862306a36Sopenharmony_ci buf.f_bfree = st->f_bfree; 17962306a36Sopenharmony_ci buf.f_bavail = st->f_bavail; 18062306a36Sopenharmony_ci buf.f_files = st->f_files; 18162306a36Sopenharmony_ci buf.f_ffree = st->f_ffree; 18262306a36Sopenharmony_ci buf.f_fsid = st->f_fsid; 18362306a36Sopenharmony_ci buf.f_namelen = st->f_namelen; 18462306a36Sopenharmony_ci buf.f_frsize = st->f_frsize; 18562306a36Sopenharmony_ci buf.f_flags = st->f_flags; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci if (copy_to_user(p, &buf, sizeof(buf))) 18862306a36Sopenharmony_ci return -EFAULT; 18962306a36Sopenharmony_ci return 0; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciSYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct kstatfs st; 19562306a36Sopenharmony_ci int error = user_statfs(pathname, &st); 19662306a36Sopenharmony_ci if (!error) 19762306a36Sopenharmony_ci error = do_statfs_native(&st, buf); 19862306a36Sopenharmony_ci return error; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ciSYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct kstatfs st; 20462306a36Sopenharmony_ci int error; 20562306a36Sopenharmony_ci if (sz != sizeof(*buf)) 20662306a36Sopenharmony_ci return -EINVAL; 20762306a36Sopenharmony_ci error = user_statfs(pathname, &st); 20862306a36Sopenharmony_ci if (!error) 20962306a36Sopenharmony_ci error = do_statfs64(&st, buf); 21062306a36Sopenharmony_ci return error; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ciSYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct kstatfs st; 21662306a36Sopenharmony_ci int error = fd_statfs(fd, &st); 21762306a36Sopenharmony_ci if (!error) 21862306a36Sopenharmony_ci error = do_statfs_native(&st, buf); 21962306a36Sopenharmony_ci return error; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ciSYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct kstatfs st; 22562306a36Sopenharmony_ci int error; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (sz != sizeof(*buf)) 22862306a36Sopenharmony_ci return -EINVAL; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci error = fd_statfs(fd, &st); 23162306a36Sopenharmony_ci if (!error) 23262306a36Sopenharmony_ci error = do_statfs64(&st, buf); 23362306a36Sopenharmony_ci return error; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int vfs_ustat(dev_t dev, struct kstatfs *sbuf) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct super_block *s = user_get_super(dev, false); 23962306a36Sopenharmony_ci int err; 24062306a36Sopenharmony_ci if (!s) 24162306a36Sopenharmony_ci return -EINVAL; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci err = statfs_by_dentry(s->s_root, sbuf); 24462306a36Sopenharmony_ci drop_super(s); 24562306a36Sopenharmony_ci return err; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ciSYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct ustat tmp; 25162306a36Sopenharmony_ci struct kstatfs sbuf; 25262306a36Sopenharmony_ci int err = vfs_ustat(new_decode_dev(dev), &sbuf); 25362306a36Sopenharmony_ci if (err) 25462306a36Sopenharmony_ci return err; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci memset(&tmp,0,sizeof(struct ustat)); 25762306a36Sopenharmony_ci tmp.f_tfree = sbuf.f_bfree; 25862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ARCH_32BIT_USTAT_F_TINODE)) 25962306a36Sopenharmony_ci tmp.f_tinode = min_t(u64, sbuf.f_ffree, UINT_MAX); 26062306a36Sopenharmony_ci else 26162306a36Sopenharmony_ci tmp.f_tinode = sbuf.f_ffree; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 26762306a36Sopenharmony_cistatic int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct compat_statfs buf; 27062306a36Sopenharmony_ci if (sizeof ubuf->f_blocks == 4) { 27162306a36Sopenharmony_ci if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail | 27262306a36Sopenharmony_ci kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL) 27362306a36Sopenharmony_ci return -EOVERFLOW; 27462306a36Sopenharmony_ci /* f_files and f_ffree may be -1; it's okay 27562306a36Sopenharmony_ci * to stuff that into 32 bits */ 27662306a36Sopenharmony_ci if (kbuf->f_files != 0xffffffffffffffffULL 27762306a36Sopenharmony_ci && (kbuf->f_files & 0xffffffff00000000ULL)) 27862306a36Sopenharmony_ci return -EOVERFLOW; 27962306a36Sopenharmony_ci if (kbuf->f_ffree != 0xffffffffffffffffULL 28062306a36Sopenharmony_ci && (kbuf->f_ffree & 0xffffffff00000000ULL)) 28162306a36Sopenharmony_ci return -EOVERFLOW; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci memset(&buf, 0, sizeof(struct compat_statfs)); 28462306a36Sopenharmony_ci buf.f_type = kbuf->f_type; 28562306a36Sopenharmony_ci buf.f_bsize = kbuf->f_bsize; 28662306a36Sopenharmony_ci buf.f_blocks = kbuf->f_blocks; 28762306a36Sopenharmony_ci buf.f_bfree = kbuf->f_bfree; 28862306a36Sopenharmony_ci buf.f_bavail = kbuf->f_bavail; 28962306a36Sopenharmony_ci buf.f_files = kbuf->f_files; 29062306a36Sopenharmony_ci buf.f_ffree = kbuf->f_ffree; 29162306a36Sopenharmony_ci buf.f_namelen = kbuf->f_namelen; 29262306a36Sopenharmony_ci buf.f_fsid.val[0] = kbuf->f_fsid.val[0]; 29362306a36Sopenharmony_ci buf.f_fsid.val[1] = kbuf->f_fsid.val[1]; 29462306a36Sopenharmony_ci buf.f_frsize = kbuf->f_frsize; 29562306a36Sopenharmony_ci buf.f_flags = kbuf->f_flags; 29662306a36Sopenharmony_ci if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs))) 29762306a36Sopenharmony_ci return -EFAULT; 29862306a36Sopenharmony_ci return 0; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/* 30262306a36Sopenharmony_ci * The following statfs calls are copies of code from fs/statfs.c and 30362306a36Sopenharmony_ci * should be checked against those from time to time 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct compat_statfs __user *, buf) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct kstatfs tmp; 30862306a36Sopenharmony_ci int error = user_statfs(pathname, &tmp); 30962306a36Sopenharmony_ci if (!error) 31062306a36Sopenharmony_ci error = put_compat_statfs(buf, &tmp); 31162306a36Sopenharmony_ci return error; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct compat_statfs __user *, buf) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct kstatfs tmp; 31762306a36Sopenharmony_ci int error = fd_statfs(fd, &tmp); 31862306a36Sopenharmony_ci if (!error) 31962306a36Sopenharmony_ci error = put_compat_statfs(buf, &tmp); 32062306a36Sopenharmony_ci return error; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct compat_statfs64 buf; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if ((kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL) 32862306a36Sopenharmony_ci return -EOVERFLOW; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci memset(&buf, 0, sizeof(struct compat_statfs64)); 33162306a36Sopenharmony_ci buf.f_type = kbuf->f_type; 33262306a36Sopenharmony_ci buf.f_bsize = kbuf->f_bsize; 33362306a36Sopenharmony_ci buf.f_blocks = kbuf->f_blocks; 33462306a36Sopenharmony_ci buf.f_bfree = kbuf->f_bfree; 33562306a36Sopenharmony_ci buf.f_bavail = kbuf->f_bavail; 33662306a36Sopenharmony_ci buf.f_files = kbuf->f_files; 33762306a36Sopenharmony_ci buf.f_ffree = kbuf->f_ffree; 33862306a36Sopenharmony_ci buf.f_namelen = kbuf->f_namelen; 33962306a36Sopenharmony_ci buf.f_fsid.val[0] = kbuf->f_fsid.val[0]; 34062306a36Sopenharmony_ci buf.f_fsid.val[1] = kbuf->f_fsid.val[1]; 34162306a36Sopenharmony_ci buf.f_frsize = kbuf->f_frsize; 34262306a36Sopenharmony_ci buf.f_flags = kbuf->f_flags; 34362306a36Sopenharmony_ci if (copy_to_user(ubuf, &buf, sizeof(struct compat_statfs64))) 34462306a36Sopenharmony_ci return -EFAULT; 34562306a36Sopenharmony_ci return 0; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ciint kcompat_sys_statfs64(const char __user * pathname, compat_size_t sz, struct compat_statfs64 __user * buf) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct kstatfs tmp; 35162306a36Sopenharmony_ci int error; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (sz != sizeof(*buf)) 35462306a36Sopenharmony_ci return -EINVAL; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci error = user_statfs(pathname, &tmp); 35762306a36Sopenharmony_ci if (!error) 35862306a36Sopenharmony_ci error = put_compat_statfs64(buf, &tmp); 35962306a36Sopenharmony_ci return error; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(statfs64, const char __user *, pathname, compat_size_t, sz, struct compat_statfs64 __user *, buf) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci return kcompat_sys_statfs64(pathname, sz, buf); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ciint kcompat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user * buf) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct kstatfs tmp; 37062306a36Sopenharmony_ci int error; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (sz != sizeof(*buf)) 37362306a36Sopenharmony_ci return -EINVAL; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci error = fd_statfs(fd, &tmp); 37662306a36Sopenharmony_ci if (!error) 37762306a36Sopenharmony_ci error = put_compat_statfs64(buf, &tmp); 37862306a36Sopenharmony_ci return error; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, compat_size_t, sz, struct compat_statfs64 __user *, buf) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci return kcompat_sys_fstatfs64(fd, sz, buf); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci/* 38762306a36Sopenharmony_ci * This is a copy of sys_ustat, just dealing with a structure layout. 38862306a36Sopenharmony_ci * Given how simple this syscall is that apporach is more maintainable 38962306a36Sopenharmony_ci * than the various conversion hacks. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct compat_ustat tmp; 39462306a36Sopenharmony_ci struct kstatfs sbuf; 39562306a36Sopenharmony_ci int err = vfs_ustat(new_decode_dev(dev), &sbuf); 39662306a36Sopenharmony_ci if (err) 39762306a36Sopenharmony_ci return err; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci memset(&tmp, 0, sizeof(struct compat_ustat)); 40062306a36Sopenharmony_ci tmp.f_tfree = sbuf.f_bfree; 40162306a36Sopenharmony_ci tmp.f_tinode = sbuf.f_ffree; 40262306a36Sopenharmony_ci if (copy_to_user(u, &tmp, sizeof(struct compat_ustat))) 40362306a36Sopenharmony_ci return -EFAULT; 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci#endif 407