1#include <linux/syscalls.h>
2#include <linux/module.h>
3#include <linux/fs.h>
4#include <linux/file.h>
5#include <linux/mount.h>
6#include <linux/namei.h>
7#include <linux/statfs.h>
8#include <linux/security.h>
9#include <linux/uaccess.h>
10
11static int flags_by_mnt(int mnt_flags)
12{
13	int flags = 0;
14
15	if (mnt_flags & MNT_READONLY)
16		flags |= ST_RDONLY;
17	if (mnt_flags & MNT_NOSUID)
18		flags |= ST_NOSUID;
19	if (mnt_flags & MNT_NODEV)
20		flags |= ST_NODEV;
21	if (mnt_flags & MNT_NOEXEC)
22		flags |= ST_NOEXEC;
23	if (mnt_flags & MNT_NOATIME)
24		flags |= ST_NOATIME;
25	if (mnt_flags & MNT_NODIRATIME)
26		flags |= ST_NODIRATIME;
27	if (mnt_flags & MNT_RELATIME)
28		flags |= ST_RELATIME;
29	return flags;
30}
31
32static int flags_by_sb(int s_flags)
33{
34	int flags = 0;
35	if (s_flags & MS_SYNCHRONOUS)
36		flags |= ST_SYNCHRONOUS;
37	if (s_flags & MS_MANDLOCK)
38		flags |= ST_MANDLOCK;
39	return flags;
40}
41
42static int calculate_f_flags(struct vfsmount *mnt)
43{
44	return ST_VALID | flags_by_mnt(mnt->mnt_flags) |
45		flags_by_sb(mnt->mnt_sb->s_flags);
46}
47
48int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf)
49{
50	int retval;
51
52	if (!dentry->d_sb->s_op->statfs)
53		return -ENOSYS;
54
55	memset(buf, 0, sizeof(*buf));
56	retval = security_sb_statfs(dentry);
57	if (retval)
58		return retval;
59	retval = dentry->d_sb->s_op->statfs(dentry, buf);
60	if (retval == 0 && buf->f_frsize == 0)
61		buf->f_frsize = buf->f_bsize;
62	return retval;
63}
64
65int vfs_statfs(struct path *path, struct kstatfs *buf)
66{
67	int error;
68
69	error = statfs_by_dentry(path->dentry, buf);
70	if (!error)
71		buf->f_flags = calculate_f_flags(path->mnt);
72	return error;
73}
74EXPORT_SYMBOL(vfs_statfs);
75
76static int do_statfs_native(struct path *path, struct statfs *buf)
77{
78	struct kstatfs st;
79	int retval;
80
81	retval = vfs_statfs(path, &st);
82	if (retval)
83		return retval;
84
85	if (sizeof(*buf) == sizeof(st))
86		memcpy(buf, &st, sizeof(st));
87	else {
88		if (sizeof buf->f_blocks == 4) {
89			if ((st.f_blocks | st.f_bfree | st.f_bavail |
90			     st.f_bsize | st.f_frsize) &
91			    0xffffffff00000000ULL)
92				return -EOVERFLOW;
93			/*
94			 * f_files and f_ffree may be -1; it's okay to stuff
95			 * that into 32 bits
96			 */
97			if (st.f_files != -1 &&
98			    (st.f_files & 0xffffffff00000000ULL))
99				return -EOVERFLOW;
100			if (st.f_ffree != -1 &&
101			    (st.f_ffree & 0xffffffff00000000ULL))
102				return -EOVERFLOW;
103		}
104
105		buf->f_type = st.f_type;
106		buf->f_bsize = st.f_bsize;
107		buf->f_blocks = st.f_blocks;
108		buf->f_bfree = st.f_bfree;
109		buf->f_bavail = st.f_bavail;
110		buf->f_files = st.f_files;
111		buf->f_ffree = st.f_ffree;
112		buf->f_fsid = st.f_fsid;
113		buf->f_namelen = st.f_namelen;
114		buf->f_frsize = st.f_frsize;
115		buf->f_flags = st.f_flags;
116		memset(buf->f_spare, 0, sizeof(buf->f_spare));
117	}
118	return 0;
119}
120
121static int do_statfs64(struct path *path, struct statfs64 *buf)
122{
123	struct kstatfs st;
124	int retval;
125
126	retval = vfs_statfs(path, &st);
127	if (retval)
128		return retval;
129
130	if (sizeof(*buf) == sizeof(st))
131		memcpy(buf, &st, sizeof(st));
132	else {
133		buf->f_type = st.f_type;
134		buf->f_bsize = st.f_bsize;
135		buf->f_blocks = st.f_blocks;
136		buf->f_bfree = st.f_bfree;
137		buf->f_bavail = st.f_bavail;
138		buf->f_files = st.f_files;
139		buf->f_ffree = st.f_ffree;
140		buf->f_fsid = st.f_fsid;
141		buf->f_namelen = st.f_namelen;
142		buf->f_frsize = st.f_frsize;
143		buf->f_flags = st.f_flags;
144		memset(buf->f_spare, 0, sizeof(buf->f_spare));
145	}
146	return 0;
147}
148
149SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
150{
151	struct path path;
152	int error;
153
154	error = user_path(pathname, &path);
155	if (!error) {
156		struct statfs tmp;
157		error = do_statfs_native(&path, &tmp);
158		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
159			error = -EFAULT;
160		path_put(&path);
161	}
162	return error;
163}
164
165SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
166{
167	struct path path;
168	long error;
169
170	if (sz != sizeof(*buf))
171		return -EINVAL;
172	error = user_path(pathname, &path);
173	if (!error) {
174		struct statfs64 tmp;
175		error = do_statfs64(&path, &tmp);
176		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
177			error = -EFAULT;
178		path_put(&path);
179	}
180	return error;
181}
182
183SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
184{
185	struct file *file;
186	struct statfs tmp;
187	int error;
188
189	error = -EBADF;
190	file = fget(fd);
191	if (!file)
192		goto out;
193	error = do_statfs_native(&file->f_path, &tmp);
194	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
195		error = -EFAULT;
196	fput(file);
197out:
198	return error;
199}
200
201SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
202{
203	struct file *file;
204	struct statfs64 tmp;
205	int error;
206
207	if (sz != sizeof(*buf))
208		return -EINVAL;
209
210	error = -EBADF;
211	file = fget(fd);
212	if (!file)
213		goto out;
214	error = do_statfs64(&file->f_path, &tmp);
215	if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
216		error = -EFAULT;
217	fput(file);
218out:
219	return error;
220}
221
222SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
223{
224	struct super_block *s;
225	struct ustat tmp;
226	struct kstatfs sbuf;
227	int err;
228
229	s = user_get_super(new_decode_dev(dev));
230	if (!s)
231		return -EINVAL;
232
233	err = statfs_by_dentry(s->s_root, &sbuf);
234	drop_super(s);
235	if (err)
236		return err;
237
238	memset(&tmp,0,sizeof(struct ustat));
239	tmp.f_tfree = sbuf.f_bfree;
240	tmp.f_tinode = sbuf.f_ffree;
241
242	return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
243}
244