aboutsummaryrefslogtreecommitdiffstats
path: root/fs/readdir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/readdir.c')
-rw-r--r--fs/readdir.c56
1 files changed, 29 insertions, 27 deletions
diff --git a/fs/readdir.c b/fs/readdir.c
index fee38e04fae4..93d71e574310 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -20,11 +20,11 @@
20 20
21#include <asm/uaccess.h> 21#include <asm/uaccess.h>
22 22
23int vfs_readdir(struct file *file, filldir_t filler, void *buf) 23int iterate_dir(struct file *file, struct dir_context *ctx)
24{ 24{
25 struct inode *inode = file_inode(file); 25 struct inode *inode = file_inode(file);
26 int res = -ENOTDIR; 26 int res = -ENOTDIR;
27 if (!file->f_op || !file->f_op->readdir) 27 if (!file->f_op || !file->f_op->iterate)
28 goto out; 28 goto out;
29 29
30 res = security_file_permission(file, MAY_READ); 30 res = security_file_permission(file, MAY_READ);
@@ -37,15 +37,16 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf)
37 37
38 res = -ENOENT; 38 res = -ENOENT;
39 if (!IS_DEADDIR(inode)) { 39 if (!IS_DEADDIR(inode)) {
40 res = file->f_op->readdir(file, buf, filler); 40 ctx->pos = file->f_pos;
41 res = file->f_op->iterate(file, ctx);
42 file->f_pos = ctx->pos;
41 file_accessed(file); 43 file_accessed(file);
42 } 44 }
43 mutex_unlock(&inode->i_mutex); 45 mutex_unlock(&inode->i_mutex);
44out: 46out:
45 return res; 47 return res;
46} 48}
47 49EXPORT_SYMBOL(iterate_dir);
48EXPORT_SYMBOL(vfs_readdir);
49 50
50/* 51/*
51 * Traditional linux readdir() handling.. 52 * Traditional linux readdir() handling..
@@ -66,6 +67,7 @@ struct old_linux_dirent {
66}; 67};
67 68
68struct readdir_callback { 69struct readdir_callback {
70 struct dir_context ctx;
69 struct old_linux_dirent __user * dirent; 71 struct old_linux_dirent __user * dirent;
70 int result; 72 int result;
71}; 73};
@@ -73,7 +75,7 @@ struct readdir_callback {
73static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset, 75static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
74 u64 ino, unsigned int d_type) 76 u64 ino, unsigned int d_type)
75{ 77{
76 struct readdir_callback * buf = (struct readdir_callback *) __buf; 78 struct readdir_callback *buf = (struct readdir_callback *) __buf;
77 struct old_linux_dirent __user * dirent; 79 struct old_linux_dirent __user * dirent;
78 unsigned long d_ino; 80 unsigned long d_ino;
79 81
@@ -107,15 +109,15 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
107{ 109{
108 int error; 110 int error;
109 struct fd f = fdget(fd); 111 struct fd f = fdget(fd);
110 struct readdir_callback buf; 112 struct readdir_callback buf = {
113 .ctx.actor = fillonedir,
114 .dirent = dirent
115 };
111 116
112 if (!f.file) 117 if (!f.file)
113 return -EBADF; 118 return -EBADF;
114 119
115 buf.result = 0; 120 error = iterate_dir(f.file, &buf.ctx);
116 buf.dirent = dirent;
117
118 error = vfs_readdir(f.file, fillonedir, &buf);
119 if (buf.result) 121 if (buf.result)
120 error = buf.result; 122 error = buf.result;
121 123
@@ -137,6 +139,7 @@ struct linux_dirent {
137}; 139};
138 140
139struct getdents_callback { 141struct getdents_callback {
142 struct dir_context ctx;
140 struct linux_dirent __user * current_dir; 143 struct linux_dirent __user * current_dir;
141 struct linux_dirent __user * previous; 144 struct linux_dirent __user * previous;
142 int count; 145 int count;
@@ -191,7 +194,11 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
191{ 194{
192 struct fd f; 195 struct fd f;
193 struct linux_dirent __user * lastdirent; 196 struct linux_dirent __user * lastdirent;
194 struct getdents_callback buf; 197 struct getdents_callback buf = {
198 .ctx.actor = filldir,
199 .count = count,
200 .current_dir = dirent
201 };
195 int error; 202 int error;
196 203
197 if (!access_ok(VERIFY_WRITE, dirent, count)) 204 if (!access_ok(VERIFY_WRITE, dirent, count))
@@ -201,17 +208,12 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
201 if (!f.file) 208 if (!f.file)
202 return -EBADF; 209 return -EBADF;
203 210
204 buf.current_dir = dirent; 211 error = iterate_dir(f.file, &buf.ctx);
205 buf.previous = NULL;
206 buf.count = count;
207 buf.error = 0;
208
209 error = vfs_readdir(f.file, filldir, &buf);
210 if (error >= 0) 212 if (error >= 0)
211 error = buf.error; 213 error = buf.error;
212 lastdirent = buf.previous; 214 lastdirent = buf.previous;
213 if (lastdirent) { 215 if (lastdirent) {
214 if (put_user(f.file->f_pos, &lastdirent->d_off)) 216 if (put_user(buf.ctx.pos, &lastdirent->d_off))
215 error = -EFAULT; 217 error = -EFAULT;
216 else 218 else
217 error = count - buf.count; 219 error = count - buf.count;
@@ -221,6 +223,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
221} 223}
222 224
223struct getdents_callback64 { 225struct getdents_callback64 {
226 struct dir_context ctx;
224 struct linux_dirent64 __user * current_dir; 227 struct linux_dirent64 __user * current_dir;
225 struct linux_dirent64 __user * previous; 228 struct linux_dirent64 __user * previous;
226 int count; 229 int count;
@@ -271,7 +274,11 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
271{ 274{
272 struct fd f; 275 struct fd f;
273 struct linux_dirent64 __user * lastdirent; 276 struct linux_dirent64 __user * lastdirent;
274 struct getdents_callback64 buf; 277 struct getdents_callback64 buf = {
278 .ctx.actor = filldir64,
279 .count = count,
280 .current_dir = dirent
281 };
275 int error; 282 int error;
276 283
277 if (!access_ok(VERIFY_WRITE, dirent, count)) 284 if (!access_ok(VERIFY_WRITE, dirent, count))
@@ -281,17 +288,12 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
281 if (!f.file) 288 if (!f.file)
282 return -EBADF; 289 return -EBADF;
283 290
284 buf.current_dir = dirent; 291 error = iterate_dir(f.file, &buf.ctx);
285 buf.previous = NULL;
286 buf.count = count;
287 buf.error = 0;
288
289 error = vfs_readdir(f.file, filldir64, &buf);
290 if (error >= 0) 292 if (error >= 0)
291 error = buf.error; 293 error = buf.error;
292 lastdirent = buf.previous; 294 lastdirent = buf.previous;
293 if (lastdirent) { 295 if (lastdirent) {
294 typeof(lastdirent->d_off) d_off = f.file->f_pos; 296 typeof(lastdirent->d_off) d_off = buf.ctx.pos;
295 if (__put_user(d_off, &lastdirent->d_off)) 297 if (__put_user(d_off, &lastdirent->d_off))
296 error = -EFAULT; 298 error = -EFAULT;
297 else 299 else