Linux 4.14.171
[linux/fpc-iii.git] / fs / readdir.c
blob0c357663e33a762a5114161e50e6d1f770e86c91
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * linux/fs/readdir.c
5 * Copyright (C) 1995 Linus Torvalds
6 */
8 #include <linux/stddef.h>
9 #include <linux/kernel.h>
10 #include <linux/export.h>
11 #include <linux/time.h>
12 #include <linux/mm.h>
13 #include <linux/errno.h>
14 #include <linux/stat.h>
15 #include <linux/file.h>
16 #include <linux/fs.h>
17 #include <linux/fsnotify.h>
18 #include <linux/dirent.h>
19 #include <linux/security.h>
20 #include <linux/syscalls.h>
21 #include <linux/unistd.h>
22 #include <linux/compat.h>
24 #include <linux/uaccess.h>
26 int iterate_dir(struct file *file, struct dir_context *ctx)
28 struct inode *inode = file_inode(file);
29 bool shared = false;
30 int res = -ENOTDIR;
31 if (file->f_op->iterate_shared)
32 shared = true;
33 else if (!file->f_op->iterate)
34 goto out;
36 res = security_file_permission(file, MAY_READ);
37 if (res)
38 goto out;
40 if (shared) {
41 inode_lock_shared(inode);
42 } else {
43 res = down_write_killable(&inode->i_rwsem);
44 if (res)
45 goto out;
48 res = -ENOENT;
49 if (!IS_DEADDIR(inode)) {
50 ctx->pos = file->f_pos;
51 if (shared)
52 res = file->f_op->iterate_shared(file, ctx);
53 else
54 res = file->f_op->iterate(file, ctx);
55 file->f_pos = ctx->pos;
56 fsnotify_access(file);
57 file_accessed(file);
59 if (shared)
60 inode_unlock_shared(inode);
61 else
62 inode_unlock(inode);
63 out:
64 return res;
66 EXPORT_SYMBOL(iterate_dir);
69 * POSIX says that a dirent name cannot contain NULL or a '/'.
71 * It's not 100% clear what we should really do in this case.
72 * The filesystem is clearly corrupted, but returning a hard
73 * error means that you now don't see any of the other names
74 * either, so that isn't a perfect alternative.
76 * And if you return an error, what error do you use? Several
77 * filesystems seem to have decided on EUCLEAN being the error
78 * code for EFSCORRUPTED, and that may be the error to use. Or
79 * just EIO, which is perhaps more obvious to users.
81 * In order to see the other file names in the directory, the
82 * caller might want to make this a "soft" error: skip the
83 * entry, and return the error at the end instead.
85 * Note that this should likely do a "memchr(name, 0, len)"
86 * check too, since that would be filesystem corruption as
87 * well. However, that case can't actually confuse user space,
88 * which has to do a strlen() on the name anyway to find the
89 * filename length, and the above "soft error" worry means
90 * that it's probably better left alone until we have that
91 * issue clarified.
93 static int verify_dirent_name(const char *name, int len)
95 if (!len)
96 return -EIO;
97 if (memchr(name, '/', len))
98 return -EIO;
99 return 0;
103 * Traditional linux readdir() handling..
105 * "count=1" is a special case, meaning that the buffer is one
106 * dirent-structure in size and that the code can't handle more
107 * anyway. Thus the special "fillonedir()" function for that
108 * case (the low-level handlers don't need to care about this).
111 #ifdef __ARCH_WANT_OLD_READDIR
113 struct old_linux_dirent {
114 unsigned long d_ino;
115 unsigned long d_offset;
116 unsigned short d_namlen;
117 char d_name[1];
120 struct readdir_callback {
121 struct dir_context ctx;
122 struct old_linux_dirent __user * dirent;
123 int result;
126 static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
127 loff_t offset, u64 ino, unsigned int d_type)
129 struct readdir_callback *buf =
130 container_of(ctx, struct readdir_callback, ctx);
131 struct old_linux_dirent __user * dirent;
132 unsigned long d_ino;
134 if (buf->result)
135 return -EINVAL;
136 d_ino = ino;
137 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
138 buf->result = -EOVERFLOW;
139 return -EOVERFLOW;
141 buf->result++;
142 dirent = buf->dirent;
143 if (!access_ok(VERIFY_WRITE, dirent,
144 (unsigned long)(dirent->d_name + namlen + 1) -
145 (unsigned long)dirent))
146 goto efault;
147 if ( __put_user(d_ino, &dirent->d_ino) ||
148 __put_user(offset, &dirent->d_offset) ||
149 __put_user(namlen, &dirent->d_namlen) ||
150 __copy_to_user(dirent->d_name, name, namlen) ||
151 __put_user(0, dirent->d_name + namlen))
152 goto efault;
153 return 0;
154 efault:
155 buf->result = -EFAULT;
156 return -EFAULT;
159 SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
160 struct old_linux_dirent __user *, dirent, unsigned int, count)
162 int error;
163 struct fd f = fdget_pos(fd);
164 struct readdir_callback buf = {
165 .ctx.actor = fillonedir,
166 .dirent = dirent
169 if (!f.file)
170 return -EBADF;
172 error = iterate_dir(f.file, &buf.ctx);
173 if (buf.result)
174 error = buf.result;
176 fdput_pos(f);
177 return error;
180 #endif /* __ARCH_WANT_OLD_READDIR */
183 * New, all-improved, singing, dancing, iBCS2-compliant getdents()
184 * interface.
186 struct linux_dirent {
187 unsigned long d_ino;
188 unsigned long d_off;
189 unsigned short d_reclen;
190 char d_name[1];
193 struct getdents_callback {
194 struct dir_context ctx;
195 struct linux_dirent __user * current_dir;
196 struct linux_dirent __user * previous;
197 int count;
198 int error;
201 static int filldir(struct dir_context *ctx, const char *name, int namlen,
202 loff_t offset, u64 ino, unsigned int d_type)
204 struct linux_dirent __user * dirent;
205 struct getdents_callback *buf =
206 container_of(ctx, struct getdents_callback, ctx);
207 unsigned long d_ino;
208 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
209 sizeof(long));
211 buf->error = verify_dirent_name(name, namlen);
212 if (unlikely(buf->error))
213 return buf->error;
214 buf->error = -EINVAL; /* only used if we fail.. */
215 if (reclen > buf->count)
216 return -EINVAL;
217 d_ino = ino;
218 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
219 buf->error = -EOVERFLOW;
220 return -EOVERFLOW;
222 dirent = buf->previous;
223 if (dirent) {
224 if (signal_pending(current))
225 return -EINTR;
226 if (__put_user(offset, &dirent->d_off))
227 goto efault;
229 dirent = buf->current_dir;
230 if (__put_user(d_ino, &dirent->d_ino))
231 goto efault;
232 if (__put_user(reclen, &dirent->d_reclen))
233 goto efault;
234 if (copy_to_user(dirent->d_name, name, namlen))
235 goto efault;
236 if (__put_user(0, dirent->d_name + namlen))
237 goto efault;
238 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
239 goto efault;
240 buf->previous = dirent;
241 dirent = (void __user *)dirent + reclen;
242 buf->current_dir = dirent;
243 buf->count -= reclen;
244 return 0;
245 efault:
246 buf->error = -EFAULT;
247 return -EFAULT;
250 SYSCALL_DEFINE3(getdents, unsigned int, fd,
251 struct linux_dirent __user *, dirent, unsigned int, count)
253 struct fd f;
254 struct linux_dirent __user * lastdirent;
255 struct getdents_callback buf = {
256 .ctx.actor = filldir,
257 .count = count,
258 .current_dir = dirent
260 int error;
262 if (!access_ok(VERIFY_WRITE, dirent, count))
263 return -EFAULT;
265 f = fdget_pos(fd);
266 if (!f.file)
267 return -EBADF;
269 error = iterate_dir(f.file, &buf.ctx);
270 if (error >= 0)
271 error = buf.error;
272 lastdirent = buf.previous;
273 if (lastdirent) {
274 if (put_user(buf.ctx.pos, &lastdirent->d_off))
275 error = -EFAULT;
276 else
277 error = count - buf.count;
279 fdput_pos(f);
280 return error;
283 struct getdents_callback64 {
284 struct dir_context ctx;
285 struct linux_dirent64 __user * current_dir;
286 struct linux_dirent64 __user * previous;
287 int count;
288 int error;
291 static int filldir64(struct dir_context *ctx, const char *name, int namlen,
292 loff_t offset, u64 ino, unsigned int d_type)
294 struct linux_dirent64 __user *dirent;
295 struct getdents_callback64 *buf =
296 container_of(ctx, struct getdents_callback64, ctx);
297 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
298 sizeof(u64));
300 buf->error = verify_dirent_name(name, namlen);
301 if (unlikely(buf->error))
302 return buf->error;
303 buf->error = -EINVAL; /* only used if we fail.. */
304 if (reclen > buf->count)
305 return -EINVAL;
306 dirent = buf->previous;
307 if (dirent) {
308 if (signal_pending(current))
309 return -EINTR;
310 if (__put_user(offset, &dirent->d_off))
311 goto efault;
313 dirent = buf->current_dir;
314 if (__put_user(ino, &dirent->d_ino))
315 goto efault;
316 if (__put_user(0, &dirent->d_off))
317 goto efault;
318 if (__put_user(reclen, &dirent->d_reclen))
319 goto efault;
320 if (__put_user(d_type, &dirent->d_type))
321 goto efault;
322 if (copy_to_user(dirent->d_name, name, namlen))
323 goto efault;
324 if (__put_user(0, dirent->d_name + namlen))
325 goto efault;
326 buf->previous = dirent;
327 dirent = (void __user *)dirent + reclen;
328 buf->current_dir = dirent;
329 buf->count -= reclen;
330 return 0;
331 efault:
332 buf->error = -EFAULT;
333 return -EFAULT;
336 SYSCALL_DEFINE3(getdents64, unsigned int, fd,
337 struct linux_dirent64 __user *, dirent, unsigned int, count)
339 struct fd f;
340 struct linux_dirent64 __user * lastdirent;
341 struct getdents_callback64 buf = {
342 .ctx.actor = filldir64,
343 .count = count,
344 .current_dir = dirent
346 int error;
348 if (!access_ok(VERIFY_WRITE, dirent, count))
349 return -EFAULT;
351 f = fdget_pos(fd);
352 if (!f.file)
353 return -EBADF;
355 error = iterate_dir(f.file, &buf.ctx);
356 if (error >= 0)
357 error = buf.error;
358 lastdirent = buf.previous;
359 if (lastdirent) {
360 typeof(lastdirent->d_off) d_off = buf.ctx.pos;
361 if (__put_user(d_off, &lastdirent->d_off))
362 error = -EFAULT;
363 else
364 error = count - buf.count;
366 fdput_pos(f);
367 return error;
370 #ifdef CONFIG_COMPAT
371 struct compat_old_linux_dirent {
372 compat_ulong_t d_ino;
373 compat_ulong_t d_offset;
374 unsigned short d_namlen;
375 char d_name[1];
378 struct compat_readdir_callback {
379 struct dir_context ctx;
380 struct compat_old_linux_dirent __user *dirent;
381 int result;
384 static int compat_fillonedir(struct dir_context *ctx, const char *name,
385 int namlen, loff_t offset, u64 ino,
386 unsigned int d_type)
388 struct compat_readdir_callback *buf =
389 container_of(ctx, struct compat_readdir_callback, ctx);
390 struct compat_old_linux_dirent __user *dirent;
391 compat_ulong_t d_ino;
393 if (buf->result)
394 return -EINVAL;
395 d_ino = ino;
396 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
397 buf->result = -EOVERFLOW;
398 return -EOVERFLOW;
400 buf->result++;
401 dirent = buf->dirent;
402 if (!access_ok(VERIFY_WRITE, dirent,
403 (unsigned long)(dirent->d_name + namlen + 1) -
404 (unsigned long)dirent))
405 goto efault;
406 if ( __put_user(d_ino, &dirent->d_ino) ||
407 __put_user(offset, &dirent->d_offset) ||
408 __put_user(namlen, &dirent->d_namlen) ||
409 __copy_to_user(dirent->d_name, name, namlen) ||
410 __put_user(0, dirent->d_name + namlen))
411 goto efault;
412 return 0;
413 efault:
414 buf->result = -EFAULT;
415 return -EFAULT;
418 COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
419 struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
421 int error;
422 struct fd f = fdget_pos(fd);
423 struct compat_readdir_callback buf = {
424 .ctx.actor = compat_fillonedir,
425 .dirent = dirent
428 if (!f.file)
429 return -EBADF;
431 error = iterate_dir(f.file, &buf.ctx);
432 if (buf.result)
433 error = buf.result;
435 fdput_pos(f);
436 return error;
439 struct compat_linux_dirent {
440 compat_ulong_t d_ino;
441 compat_ulong_t d_off;
442 unsigned short d_reclen;
443 char d_name[1];
446 struct compat_getdents_callback {
447 struct dir_context ctx;
448 struct compat_linux_dirent __user *current_dir;
449 struct compat_linux_dirent __user *previous;
450 int count;
451 int error;
454 static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
455 loff_t offset, u64 ino, unsigned int d_type)
457 struct compat_linux_dirent __user * dirent;
458 struct compat_getdents_callback *buf =
459 container_of(ctx, struct compat_getdents_callback, ctx);
460 compat_ulong_t d_ino;
461 int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
462 namlen + 2, sizeof(compat_long_t));
464 buf->error = -EINVAL; /* only used if we fail.. */
465 if (reclen > buf->count)
466 return -EINVAL;
467 d_ino = ino;
468 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
469 buf->error = -EOVERFLOW;
470 return -EOVERFLOW;
472 dirent = buf->previous;
473 if (dirent) {
474 if (signal_pending(current))
475 return -EINTR;
476 if (__put_user(offset, &dirent->d_off))
477 goto efault;
479 dirent = buf->current_dir;
480 if (__put_user(d_ino, &dirent->d_ino))
481 goto efault;
482 if (__put_user(reclen, &dirent->d_reclen))
483 goto efault;
484 if (copy_to_user(dirent->d_name, name, namlen))
485 goto efault;
486 if (__put_user(0, dirent->d_name + namlen))
487 goto efault;
488 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
489 goto efault;
490 buf->previous = dirent;
491 dirent = (void __user *)dirent + reclen;
492 buf->current_dir = dirent;
493 buf->count -= reclen;
494 return 0;
495 efault:
496 buf->error = -EFAULT;
497 return -EFAULT;
500 COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
501 struct compat_linux_dirent __user *, dirent, unsigned int, count)
503 struct fd f;
504 struct compat_linux_dirent __user * lastdirent;
505 struct compat_getdents_callback buf = {
506 .ctx.actor = compat_filldir,
507 .current_dir = dirent,
508 .count = count
510 int error;
512 if (!access_ok(VERIFY_WRITE, dirent, count))
513 return -EFAULT;
515 f = fdget_pos(fd);
516 if (!f.file)
517 return -EBADF;
519 error = iterate_dir(f.file, &buf.ctx);
520 if (error >= 0)
521 error = buf.error;
522 lastdirent = buf.previous;
523 if (lastdirent) {
524 if (put_user(buf.ctx.pos, &lastdirent->d_off))
525 error = -EFAULT;
526 else
527 error = count - buf.count;
529 fdput_pos(f);
530 return error;
532 #endif