1 #include <linux/syscalls.h> 2 #include <linux/module.h> 3 #include <linux/fs.h> 4 #include <linux/file.h> 5 #include <linux/namei.h> 6 #include <linux/statfs.h> 7 #include <linux/security.h> 8 #include <linux/uaccess.h> 9 10 int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) 11 { 12 int retval = -ENODEV; 13 14 if (dentry) { 15 retval = -ENOSYS; 16 if (dentry->d_sb->s_op->statfs) { 17 memset(buf, 0, sizeof(*buf)); 18 retval = security_sb_statfs(dentry); 19 if (retval) 20 return retval; 21 retval = dentry->d_sb->s_op->statfs(dentry, buf); 22 if (retval == 0 && buf->f_frsize == 0) 23 buf->f_frsize = buf->f_bsize; 24 } 25 } 26 return retval; 27 } 28 29 EXPORT_SYMBOL(vfs_statfs); 30 31 static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf) 32 { 33 struct kstatfs st; 34 int retval; 35 36 retval = vfs_statfs(dentry, &st); 37 if (retval) 38 return retval; 39 40 if (sizeof(*buf) == sizeof(st)) 41 memcpy(buf, &st, sizeof(st)); 42 else { 43 if (sizeof buf->f_blocks == 4) { 44 if ((st.f_blocks | st.f_bfree | st.f_bavail | 45 st.f_bsize | st.f_frsize) & 46 0xffffffff00000000ULL) 47 return -EOVERFLOW; 48 /* 49 * f_files and f_ffree may be -1; it's okay to stuff 50 * that into 32 bits 51 */ 52 if (st.f_files != -1 && 53 (st.f_files & 0xffffffff00000000ULL)) 54 return -EOVERFLOW; 55 if (st.f_ffree != -1 && 56 (st.f_ffree & 0xffffffff00000000ULL)) 57 return -EOVERFLOW; 58 } 59 60 buf->f_type = st.f_type; 61 buf->f_bsize = st.f_bsize; 62 buf->f_blocks = st.f_blocks; 63 buf->f_bfree = st.f_bfree; 64 buf->f_bavail = st.f_bavail; 65 buf->f_files = st.f_files; 66 buf->f_ffree = st.f_ffree; 67 buf->f_fsid = st.f_fsid; 68 buf->f_namelen = st.f_namelen; 69 buf->f_frsize = st.f_frsize; 70 memset(buf->f_spare, 0, sizeof(buf->f_spare)); 71 } 72 return 0; 73 } 74 75 static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf) 76 { 77 struct kstatfs st; 78 int retval; 79 80 retval = vfs_statfs(dentry, &st); 81 if (retval) 82 return retval; 83 84 if (sizeof(*buf) == sizeof(st)) 85 memcpy(buf, &st, sizeof(st)); 86 else { 87 buf->f_type = st.f_type; 88 buf->f_bsize = st.f_bsize; 89 buf->f_blocks = st.f_blocks; 90 buf->f_bfree = st.f_bfree; 91 buf->f_bavail = st.f_bavail; 92 buf->f_files = st.f_files; 93 buf->f_ffree = st.f_ffree; 94 buf->f_fsid = st.f_fsid; 95 buf->f_namelen = st.f_namelen; 96 buf->f_frsize = st.f_frsize; 97 memset(buf->f_spare, 0, sizeof(buf->f_spare)); 98 } 99 return 0; 100 } 101 102 SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf) 103 { 104 struct path path; 105 int error; 106 107 error = user_path(pathname, &path); 108 if (!error) { 109 struct statfs tmp; 110 error = vfs_statfs_native(path.dentry, &tmp); 111 if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) 112 error = -EFAULT; 113 path_put(&path); 114 } 115 return error; 116 } 117 118 SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf) 119 { 120 struct path path; 121 long error; 122 123 if (sz != sizeof(*buf)) 124 return -EINVAL; 125 error = user_path(pathname, &path); 126 if (!error) { 127 struct statfs64 tmp; 128 error = vfs_statfs64(path.dentry, &tmp); 129 if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) 130 error = -EFAULT; 131 path_put(&path); 132 } 133 return error; 134 } 135 136 SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf) 137 { 138 struct file *file; 139 struct statfs tmp; 140 int error; 141 142 error = -EBADF; 143 file = fget(fd); 144 if (!file) 145 goto out; 146 error = vfs_statfs_native(file->f_path.dentry, &tmp); 147 if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) 148 error = -EFAULT; 149 fput(file); 150 out: 151 return error; 152 } 153 154 SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf) 155 { 156 struct file *file; 157 struct statfs64 tmp; 158 int error; 159 160 if (sz != sizeof(*buf)) 161 return -EINVAL; 162 163 error = -EBADF; 164 file = fget(fd); 165 if (!file) 166 goto out; 167 error = vfs_statfs64(file->f_path.dentry, &tmp); 168 if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) 169 error = -EFAULT; 170 fput(file); 171 out: 172 return error; 173 } 174 175 SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf) 176 { 177 struct super_block *s; 178 struct ustat tmp; 179 struct kstatfs sbuf; 180 int err; 181 182 s = user_get_super(new_decode_dev(dev)); 183 if (!s) 184 return -EINVAL; 185 186 err = vfs_statfs(s->s_root, &sbuf); 187 drop_super(s); 188 if (err) 189 return err; 190 191 memset(&tmp,0,sizeof(struct ustat)); 192 tmp.f_tfree = sbuf.f_bfree; 193 tmp.f_tinode = sbuf.f_ffree; 194 195 return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0; 196 } 197