Root/fs/statfs.c

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
76int user_statfs(const char __user *pathname, struct kstatfs *st)
77{
78    struct path path;
79    int error = user_path(pathname, &path);
80    if (!error) {
81        error = vfs_statfs(&path, st);
82        path_put(&path);
83    }
84    return error;
85}
86
87int fd_statfs(int fd, struct kstatfs *st)
88{
89    struct file *file = fget(fd);
90    int error = -EBADF;
91    if (file) {
92        error = vfs_statfs(&file->f_path, st);
93        fput(file);
94    }
95    return error;
96}
97
98static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
99{
100    struct statfs buf;
101
102    if (sizeof(buf) == sizeof(*st))
103        memcpy(&buf, st, sizeof(*st));
104    else {
105        if (sizeof buf.f_blocks == 4) {
106            if ((st->f_blocks | st->f_bfree | st->f_bavail |
107                 st->f_bsize | st->f_frsize) &
108                0xffffffff00000000ULL)
109                return -EOVERFLOW;
110            /*
111             * f_files and f_ffree may be -1; it's okay to stuff
112             * that into 32 bits
113             */
114            if (st->f_files != -1 &&
115                (st->f_files & 0xffffffff00000000ULL))
116                return -EOVERFLOW;
117            if (st->f_ffree != -1 &&
118                (st->f_ffree & 0xffffffff00000000ULL))
119                return -EOVERFLOW;
120        }
121
122        buf.f_type = st->f_type;
123        buf.f_bsize = st->f_bsize;
124        buf.f_blocks = st->f_blocks;
125        buf.f_bfree = st->f_bfree;
126        buf.f_bavail = st->f_bavail;
127        buf.f_files = st->f_files;
128        buf.f_ffree = st->f_ffree;
129        buf.f_fsid = st->f_fsid;
130        buf.f_namelen = st->f_namelen;
131        buf.f_frsize = st->f_frsize;
132        buf.f_flags = st->f_flags;
133        memset(buf.f_spare, 0, sizeof(buf.f_spare));
134    }
135    if (copy_to_user(p, &buf, sizeof(buf)))
136        return -EFAULT;
137    return 0;
138}
139
140static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
141{
142    struct statfs64 buf;
143    if (sizeof(buf) == sizeof(*st))
144        memcpy(&buf, st, sizeof(*st));
145    else {
146        buf.f_type = st->f_type;
147        buf.f_bsize = st->f_bsize;
148        buf.f_blocks = st->f_blocks;
149        buf.f_bfree = st->f_bfree;
150        buf.f_bavail = st->f_bavail;
151        buf.f_files = st->f_files;
152        buf.f_ffree = st->f_ffree;
153        buf.f_fsid = st->f_fsid;
154        buf.f_namelen = st->f_namelen;
155        buf.f_frsize = st->f_frsize;
156        buf.f_flags = st->f_flags;
157        memset(buf.f_spare, 0, sizeof(buf.f_spare));
158    }
159    if (copy_to_user(p, &buf, sizeof(buf)))
160        return -EFAULT;
161    return 0;
162}
163
164SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
165{
166    struct kstatfs st;
167    int error = user_statfs(pathname, &st);
168    if (!error)
169        error = do_statfs_native(&st, buf);
170    return error;
171}
172
173SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
174{
175    struct kstatfs st;
176    int error;
177    if (sz != sizeof(*buf))
178        return -EINVAL;
179    error = user_statfs(pathname, &st);
180    if (!error)
181        error = do_statfs64(&st, buf);
182    return error;
183}
184
185SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
186{
187    struct kstatfs st;
188    int error = fd_statfs(fd, &st);
189    if (!error)
190        error = do_statfs_native(&st, buf);
191    return error;
192}
193
194SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
195{
196    struct kstatfs st;
197    int error;
198
199    if (sz != sizeof(*buf))
200        return -EINVAL;
201
202    error = fd_statfs(fd, &st);
203    if (!error)
204        error = do_statfs64(&st, buf);
205    return error;
206}
207
208SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
209{
210    struct super_block *s;
211    struct ustat tmp;
212    struct kstatfs sbuf;
213    int err;
214
215    s = user_get_super(new_decode_dev(dev));
216    if (!s)
217        return -EINVAL;
218
219    err = statfs_by_dentry(s->s_root, &sbuf);
220    drop_super(s);
221    if (err)
222        return err;
223
224    memset(&tmp,0,sizeof(struct ustat));
225    tmp.f_tfree = sbuf.f_bfree;
226    tmp.f_tinode = sbuf.f_ffree;
227
228    return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0;
229}
230

Archive Download this file



interactive