OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [readdir.c] - Blame information for rev 79

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *  linux/fs/readdir.c
3
 *
4
 *  Copyright (C) 1995  Linus Torvalds
5
 */
6
 
7
#include <linux/kernel.h>
8
#include <linux/module.h>
9
#include <linux/time.h>
10
#include <linux/mm.h>
11
#include <linux/errno.h>
12
#include <linux/stat.h>
13
#include <linux/file.h>
14
#include <linux/fs.h>
15
#include <linux/dirent.h>
16
#include <linux/security.h>
17
#include <linux/syscalls.h>
18
#include <linux/unistd.h>
19
 
20
#include <asm/uaccess.h>
21
 
22
int vfs_readdir(struct file *file, filldir_t filler, void *buf)
23
{
24
        struct inode *inode = file->f_path.dentry->d_inode;
25
        int res = -ENOTDIR;
26
        if (!file->f_op || !file->f_op->readdir)
27
                goto out;
28
 
29
        res = security_file_permission(file, MAY_READ);
30
        if (res)
31
                goto out;
32
 
33
        mutex_lock(&inode->i_mutex);
34
        res = -ENOENT;
35
        if (!IS_DEADDIR(inode)) {
36
                res = file->f_op->readdir(file, buf, filler);
37
                file_accessed(file);
38
        }
39
        mutex_unlock(&inode->i_mutex);
40
out:
41
        return res;
42
}
43
 
44
EXPORT_SYMBOL(vfs_readdir);
45
 
46
/*
47
 * Traditional linux readdir() handling..
48
 *
49
 * "count=1" is a special case, meaning that the buffer is one
50
 * dirent-structure in size and that the code can't handle more
51
 * anyway. Thus the special "fillonedir()" function for that
52
 * case (the low-level handlers don't need to care about this).
53
 */
54
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
55
 
56
#ifdef __ARCH_WANT_OLD_READDIR
57
 
58
struct old_linux_dirent {
59
        unsigned long   d_ino;
60
        unsigned long   d_offset;
61
        unsigned short  d_namlen;
62
        char            d_name[1];
63
};
64
 
65
struct readdir_callback {
66
        struct old_linux_dirent __user * dirent;
67
        int result;
68
};
69
 
70
static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
71
                      u64 ino, unsigned int d_type)
72
{
73
        struct readdir_callback * buf = (struct readdir_callback *) __buf;
74
        struct old_linux_dirent __user * dirent;
75
        unsigned long d_ino;
76
 
77
        if (buf->result)
78
                return -EINVAL;
79
        d_ino = ino;
80
        if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
81
                return -EOVERFLOW;
82
        buf->result++;
83
        dirent = buf->dirent;
84
        if (!access_ok(VERIFY_WRITE, dirent,
85
                        (unsigned long)(dirent->d_name + namlen + 1) -
86
                                (unsigned long)dirent))
87
                goto efault;
88
        if (    __put_user(d_ino, &dirent->d_ino) ||
89
                __put_user(offset, &dirent->d_offset) ||
90
                __put_user(namlen, &dirent->d_namlen) ||
91
                __copy_to_user(dirent->d_name, name, namlen) ||
92
                __put_user(0, dirent->d_name + namlen))
93
                goto efault;
94
        return 0;
95
efault:
96
        buf->result = -EFAULT;
97
        return -EFAULT;
98
}
99
 
100
asmlinkage long old_readdir(unsigned int fd, struct old_linux_dirent __user * dirent, unsigned int count)
101
{
102
        int error;
103
        struct file * file;
104
        struct readdir_callback buf;
105
 
106
        error = -EBADF;
107
        file = fget(fd);
108
        if (!file)
109
                goto out;
110
 
111
        buf.result = 0;
112
        buf.dirent = dirent;
113
 
114
        error = vfs_readdir(file, fillonedir, &buf);
115
        if (error >= 0)
116
                error = buf.result;
117
 
118
        fput(file);
119
out:
120
        return error;
121
}
122
 
123
#endif /* __ARCH_WANT_OLD_READDIR */
124
 
125
/*
126
 * New, all-improved, singing, dancing, iBCS2-compliant getdents()
127
 * interface.
128
 */
129
struct linux_dirent {
130
        unsigned long   d_ino;
131
        unsigned long   d_off;
132
        unsigned short  d_reclen;
133
        char            d_name[1];
134
};
135
 
136
struct getdents_callback {
137
        struct linux_dirent __user * current_dir;
138
        struct linux_dirent __user * previous;
139
        int count;
140
        int error;
141
};
142
 
143
static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
144
                   u64 ino, unsigned int d_type)
145
{
146
        struct linux_dirent __user * dirent;
147
        struct getdents_callback * buf = (struct getdents_callback *) __buf;
148
        unsigned long d_ino;
149
        int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 2, sizeof(long));
150
 
151
        buf->error = -EINVAL;   /* only used if we fail.. */
152
        if (reclen > buf->count)
153
                return -EINVAL;
154
        d_ino = ino;
155
        if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
156
                return -EOVERFLOW;
157
        dirent = buf->previous;
158
        if (dirent) {
159
                if (__put_user(offset, &dirent->d_off))
160
                        goto efault;
161
        }
162
        dirent = buf->current_dir;
163
        if (__put_user(d_ino, &dirent->d_ino))
164
                goto efault;
165
        if (__put_user(reclen, &dirent->d_reclen))
166
                goto efault;
167
        if (copy_to_user(dirent->d_name, name, namlen))
168
                goto efault;
169
        if (__put_user(0, dirent->d_name + namlen))
170
                goto efault;
171
        if (__put_user(d_type, (char __user *) dirent + reclen - 1))
172
                goto efault;
173
        buf->previous = dirent;
174
        dirent = (void __user *)dirent + reclen;
175
        buf->current_dir = dirent;
176
        buf->count -= reclen;
177
        return 0;
178
efault:
179
        buf->error = -EFAULT;
180
        return -EFAULT;
181
}
182
 
183
asmlinkage long sys_getdents(unsigned int fd, struct linux_dirent __user * dirent, unsigned int count)
184
{
185
        struct file * file;
186
        struct linux_dirent __user * lastdirent;
187
        struct getdents_callback buf;
188
        int error;
189
 
190
        error = -EFAULT;
191
        if (!access_ok(VERIFY_WRITE, dirent, count))
192
                goto out;
193
 
194
        error = -EBADF;
195
        file = fget(fd);
196
        if (!file)
197
                goto out;
198
 
199
        buf.current_dir = dirent;
200
        buf.previous = NULL;
201
        buf.count = count;
202
        buf.error = 0;
203
 
204
        error = vfs_readdir(file, filldir, &buf);
205
        if (error < 0)
206
                goto out_putf;
207
        error = buf.error;
208
        lastdirent = buf.previous;
209
        if (lastdirent) {
210
                if (put_user(file->f_pos, &lastdirent->d_off))
211
                        error = -EFAULT;
212
                else
213
                        error = count - buf.count;
214
        }
215
 
216
out_putf:
217
        fput(file);
218
out:
219
        return error;
220
}
221
 
222
struct getdents_callback64 {
223
        struct linux_dirent64 __user * current_dir;
224
        struct linux_dirent64 __user * previous;
225
        int count;
226
        int error;
227
};
228
 
229
static int filldir64(void * __buf, const char * name, int namlen, loff_t offset,
230
                     u64 ino, unsigned int d_type)
231
{
232
        struct linux_dirent64 __user *dirent;
233
        struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf;
234
        int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 1, sizeof(u64));
235
 
236
        buf->error = -EINVAL;   /* only used if we fail.. */
237
        if (reclen > buf->count)
238
                return -EINVAL;
239
        dirent = buf->previous;
240
        if (dirent) {
241
                if (__put_user(offset, &dirent->d_off))
242
                        goto efault;
243
        }
244
        dirent = buf->current_dir;
245
        if (__put_user(ino, &dirent->d_ino))
246
                goto efault;
247
        if (__put_user(0, &dirent->d_off))
248
                goto efault;
249
        if (__put_user(reclen, &dirent->d_reclen))
250
                goto efault;
251
        if (__put_user(d_type, &dirent->d_type))
252
                goto efault;
253
        if (copy_to_user(dirent->d_name, name, namlen))
254
                goto efault;
255
        if (__put_user(0, dirent->d_name + namlen))
256
                goto efault;
257
        buf->previous = dirent;
258
        dirent = (void __user *)dirent + reclen;
259
        buf->current_dir = dirent;
260
        buf->count -= reclen;
261
        return 0;
262
efault:
263
        buf->error = -EFAULT;
264
        return -EFAULT;
265
}
266
 
267
asmlinkage long sys_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent, unsigned int count)
268
{
269
        struct file * file;
270
        struct linux_dirent64 __user * lastdirent;
271
        struct getdents_callback64 buf;
272
        int error;
273
 
274
        error = -EFAULT;
275
        if (!access_ok(VERIFY_WRITE, dirent, count))
276
                goto out;
277
 
278
        error = -EBADF;
279
        file = fget(fd);
280
        if (!file)
281
                goto out;
282
 
283
        buf.current_dir = dirent;
284
        buf.previous = NULL;
285
        buf.count = count;
286
        buf.error = 0;
287
 
288
        error = vfs_readdir(file, filldir64, &buf);
289
        if (error < 0)
290
                goto out_putf;
291
        error = buf.error;
292
        lastdirent = buf.previous;
293
        if (lastdirent) {
294
                typeof(lastdirent->d_off) d_off = file->f_pos;
295
                error = -EFAULT;
296
                if (__put_user(d_off, &lastdirent->d_off))
297
                        goto out_putf;
298
                error = count - buf.count;
299
        }
300
 
301
out_putf:
302
        fput(file);
303
out:
304
        return error;
305
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.