diff options
Diffstat (limited to 'fs/readdir.c')
-rw-r--r-- | fs/readdir.c | 56 |
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 | ||
23 | int vfs_readdir(struct file *file, filldir_t filler, void *buf) | 23 | int 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); |
44 | out: | 46 | out: |
45 | return res; | 47 | return res; |
46 | } | 48 | } |
47 | 49 | EXPORT_SYMBOL(iterate_dir); | |
48 | EXPORT_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 | ||
68 | struct readdir_callback { | 69 | struct 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 { | |||
73 | static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset, | 75 | static 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 | ||
139 | struct getdents_callback { | 141 | struct 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 | ||
223 | struct getdents_callback64 { | 225 | struct 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 |