Linux 4.19.133
[linux/fpc-iii.git] / fs / readdir.c
blob443270f635f43e525097ef2339a1f4572f4534d2
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 res = down_read_killable(&inode->i_rwsem);
42 else
43 res = down_write_killable(&inode->i_rwsem);
44 if (res)
45 goto out;
47 res = -ENOENT;
48 if (!IS_DEADDIR(inode)) {
49 ctx->pos = file->f_pos;
50 if (shared)
51 res = file->f_op->iterate_shared(file, ctx);
52 else
53 res = file->f_op->iterate(file, ctx);
54 file->f_pos = ctx->pos;
55 fsnotify_access(file);
56 file_accessed(file);
58 if (shared)
59 inode_unlock_shared(inode);
60 else
61 inode_unlock(inode);
62 out:
63 return res;
65 EXPORT_SYMBOL(iterate_dir);
68 * POSIX says that a dirent name cannot contain NULL or a '/'.
70 * It's not 100% clear what we should really do in this case.
71 * The filesystem is clearly corrupted, but returning a hard
72 * error means that you now don't see any of the other names
73 * either, so that isn't a perfect alternative.
75 * And if you return an error, what error do you use? Several
76 * filesystems seem to have decided on EUCLEAN being the error
77 * code for EFSCORRUPTED, and that may be the error to use. Or
78 * just EIO, which is perhaps more obvious to users.
80 * In order to see the other file names in the directory, the
81 * caller might want to make this a "soft" error: skip the
82 * entry, and return the error at the end instead.
84 * Note that this should likely do a "memchr(name, 0, len)"
85 * check too, since that would be filesystem corruption as
86 * well. However, that case can't actually confuse user space,
87 * which has to do a strlen() on the name anyway to find the
88 * filename length, and the above "soft error" worry means
89 * that it's probably better left alone until we have that
90 * issue clarified.
92 static int verify_dirent_name(const char *name, int len)
94 if (!len)
95 return -EIO;
96 if (memchr(name, '/', len))
97 return -EIO;
98 return 0;
102 * Traditional linux readdir() handling..
104 * "count=1" is a special case, meaning that the buffer is one
105 * dirent-structure in size and that the code can't handle more
106 * anyway. Thus the special "fillonedir()" function for that
107 * case (the low-level handlers don't need to care about this).
110 #ifdef __ARCH_WANT_OLD_READDIR
112 struct old_linux_dirent {
113 unsigned long d_ino;
114 unsigned long d_offset;
115 unsigned short d_namlen;
116 char d_name[1];
119 struct readdir_callback {
120 struct dir_context ctx;
121 struct old_linux_dirent __user * dirent;
122 int result;
125 static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
126 loff_t offset, u64 ino, unsigned int d_type)
128 struct readdir_callback *buf =
129 container_of(ctx, struct readdir_callback, ctx);
130 struct old_linux_dirent __user * dirent;
131 unsigned long d_ino;
133 if (buf->result)
134 return -EINVAL;
135 d_ino = ino;
136 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
137 buf->result = -EOVERFLOW;
138 return -EOVERFLOW;
140 buf->result++;
141 dirent = buf->dirent;
142 if (!access_ok(VERIFY_WRITE, dirent,
143 (unsigned long)(dirent->d_name + namlen + 1) -
144 (unsigned long)dirent))
145 goto efault;
146 if ( __put_user(d_ino, &dirent->d_ino) ||
147 __put_user(offset, &dirent->d_offset) ||
148 __put_user(namlen, &dirent->d_namlen) ||
149 __copy_to_user(dirent->d_name, name, namlen) ||
150 __put_user(0, dirent->d_name + namlen))
151 goto efault;
152 return 0;
153 efault:
154 buf->result = -EFAULT;
155 return -EFAULT;
158 SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
159 struct old_linux_dirent __user *, dirent, unsigned int, count)
161 int error;
162 struct fd f = fdget_pos(fd);
163 struct readdir_callback buf = {
164 .ctx.actor = fillonedir,
165 .dirent = dirent
168 if (!f.file)
169 return -EBADF;
171 error = iterate_dir(f.file, &buf.ctx);
172 if (buf.result)
173 error = buf.result;
175 fdput_pos(f);
176 return error;
179 #endif /* __ARCH_WANT_OLD_READDIR */
182 * New, all-improved, singing, dancing, iBCS2-compliant getdents()
183 * interface.
185 struct linux_dirent {
186 unsigned long d_ino;
187 unsigned long d_off;
188 unsigned short d_reclen;
189 char d_name[1];
192 struct getdents_callback {
193 struct dir_context ctx;
194 struct linux_dirent __user * current_dir;
195 struct linux_dirent __user * previous;
196 int count;
197 int error;
200 static int filldir(struct dir_context *ctx, const char *name, int namlen,
201 loff_t offset, u64 ino, unsigned int d_type)
203 struct linux_dirent __user * dirent;
204 struct getdents_callback *buf =
205 container_of(ctx, struct getdents_callback, ctx);
206 unsigned long d_ino;
207 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
208 sizeof(long));
210 buf->error = verify_dirent_name(name, namlen);
211 if (unlikely(buf->error))
212 return buf->error;
213 buf->error = -EINVAL; /* only used if we fail.. */
214 if (reclen > buf->count)
215 return -EINVAL;
216 d_ino = ino;
217 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
218 buf->error = -EOVERFLOW;
219 return -EOVERFLOW;
221 dirent = buf->previous;
222 if (dirent) {
223 if (signal_pending(current))
224 return -EINTR;
225 if (__put_user(offset, &dirent->d_off))
226 goto efault;
228 dirent = buf->current_dir;
229 if (__put_user(d_ino, &dirent->d_ino))
230 goto efault;
231 if (__put_user(reclen, &dirent->d_reclen))
232 goto efault;
233 if (copy_to_user(dirent->d_name, name, namlen))
234 goto efault;
235 if (__put_user(0, dirent->d_name + namlen))
236 goto efault;
237 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
238 goto efault;
239 buf->previous = dirent;
240 dirent = (void __user *)dirent + reclen;
241 buf->current_dir = dirent;
242 buf->count -= reclen;
243 return 0;
244 efault:
245 buf->error = -EFAULT;
246 return -EFAULT;
249 SYSCALL_DEFINE3(getdents, unsigned int, fd,
250 struct linux_dirent __user *, dirent, unsigned int, count)
252 struct fd f;
253 struct linux_dirent __user * lastdirent;
254 struct getdents_callback buf = {
255 .ctx.actor = filldir,
256 .count = count,
257 .current_dir = dirent
259 int error;
261 if (!access_ok(VERIFY_WRITE, dirent, count))
262 return -EFAULT;
264 f = fdget_pos(fd);
265 if (!f.file)
266 return -EBADF;
268 error = iterate_dir(f.file, &buf.ctx);
269 if (error >= 0)
270 error = buf.error;
271 lastdirent = buf.previous;
272 if (lastdirent) {
273 if (put_user(buf.ctx.pos, &lastdirent->d_off))
274 error = -EFAULT;
275 else
276 error = count - buf.count;
278 fdput_pos(f);
279 return error;
282 struct getdents_callback64 {
283 struct dir_context ctx;
284 struct linux_dirent64 __user * current_dir;
285 struct linux_dirent64 __user * previous;
286 int count;
287 int error;
290 static int filldir64(struct dir_context *ctx, const char *name, int namlen,
291 loff_t offset, u64 ino, unsigned int d_type)
293 struct linux_dirent64 __user *dirent;
294 struct getdents_callback64 *buf =
295 container_of(ctx, struct getdents_callback64, ctx);
296 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
297 sizeof(u64));
299 buf->error = verify_dirent_name(name, namlen);
300 if (unlikely(buf->error))
301 return buf->error;
302 buf->error = -EINVAL; /* only used if we fail.. */
303 if (reclen > buf->count)
304 return -EINVAL;
305 dirent = buf->previous;
306 if (dirent) {
307 if (signal_pending(current))
308 return -EINTR;
309 if (__put_user(offset, &dirent->d_off))
310 goto efault;
312 dirent = buf->current_dir;
313 if (__put_user(ino, &dirent->d_ino))
314 goto efault;
315 if (__put_user(0, &dirent->d_off))
316 goto efault;
317 if (__put_user(reclen, &dirent->d_reclen))
318 goto efault;
319 if (__put_user(d_type, &dirent->d_type))
320 goto efault;
321 if (copy_to_user(dirent->d_name, name, namlen))
322 goto efault;
323 if (__put_user(0, dirent->d_name + namlen))
324 goto efault;
325 buf->previous = dirent;
326 dirent = (void __user *)dirent + reclen;
327 buf->current_dir = dirent;
328 buf->count -= reclen;
329 return 0;
330 efault:
331 buf->error = -EFAULT;
332 return -EFAULT;
335 int ksys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
336 unsigned int count)
338 struct fd f;
339 struct linux_dirent64 __user * lastdirent;
340 struct getdents_callback64 buf = {
341 .ctx.actor = filldir64,
342 .count = count,
343 .current_dir = dirent
345 int error;
347 if (!access_ok(VERIFY_WRITE, dirent, count))
348 return -EFAULT;
350 f = fdget_pos(fd);
351 if (!f.file)
352 return -EBADF;
354 error = iterate_dir(f.file, &buf.ctx);
355 if (error >= 0)
356 error = buf.error;
357 lastdirent = buf.previous;
358 if (lastdirent) {
359 typeof(lastdirent->d_off) d_off = buf.ctx.pos;
360 if (__put_user(d_off, &lastdirent->d_off))
361 error = -EFAULT;
362 else
363 error = count - buf.count;
365 fdput_pos(f);
366 return error;
370 SYSCALL_DEFINE3(getdents64, unsigned int, fd,
371 struct linux_dirent64 __user *, dirent, unsigned int, count)
373 return ksys_getdents64(fd, dirent, count);
376 #ifdef CONFIG_COMPAT
377 struct compat_old_linux_dirent {
378 compat_ulong_t d_ino;
379 compat_ulong_t d_offset;
380 unsigned short d_namlen;
381 char d_name[1];
384 struct compat_readdir_callback {
385 struct dir_context ctx;
386 struct compat_old_linux_dirent __user *dirent;
387 int result;
390 static int compat_fillonedir(struct dir_context *ctx, const char *name,
391 int namlen, loff_t offset, u64 ino,
392 unsigned int d_type)
394 struct compat_readdir_callback *buf =
395 container_of(ctx, struct compat_readdir_callback, ctx);
396 struct compat_old_linux_dirent __user *dirent;
397 compat_ulong_t d_ino;
399 if (buf->result)
400 return -EINVAL;
401 d_ino = ino;
402 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
403 buf->result = -EOVERFLOW;
404 return -EOVERFLOW;
406 buf->result++;
407 dirent = buf->dirent;
408 if (!access_ok(VERIFY_WRITE, dirent,
409 (unsigned long)(dirent->d_name + namlen + 1) -
410 (unsigned long)dirent))
411 goto efault;
412 if ( __put_user(d_ino, &dirent->d_ino) ||
413 __put_user(offset, &dirent->d_offset) ||
414 __put_user(namlen, &dirent->d_namlen) ||
415 __copy_to_user(dirent->d_name, name, namlen) ||
416 __put_user(0, dirent->d_name + namlen))
417 goto efault;
418 return 0;
419 efault:
420 buf->result = -EFAULT;
421 return -EFAULT;
424 COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
425 struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
427 int error;
428 struct fd f = fdget_pos(fd);
429 struct compat_readdir_callback buf = {
430 .ctx.actor = compat_fillonedir,
431 .dirent = dirent
434 if (!f.file)
435 return -EBADF;
437 error = iterate_dir(f.file, &buf.ctx);
438 if (buf.result)
439 error = buf.result;
441 fdput_pos(f);
442 return error;
445 struct compat_linux_dirent {
446 compat_ulong_t d_ino;
447 compat_ulong_t d_off;
448 unsigned short d_reclen;
449 char d_name[1];
452 struct compat_getdents_callback {
453 struct dir_context ctx;
454 struct compat_linux_dirent __user *current_dir;
455 struct compat_linux_dirent __user *previous;
456 int count;
457 int error;
460 static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
461 loff_t offset, u64 ino, unsigned int d_type)
463 struct compat_linux_dirent __user * dirent;
464 struct compat_getdents_callback *buf =
465 container_of(ctx, struct compat_getdents_callback, ctx);
466 compat_ulong_t d_ino;
467 int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
468 namlen + 2, sizeof(compat_long_t));
470 buf->error = -EINVAL; /* only used if we fail.. */
471 if (reclen > buf->count)
472 return -EINVAL;
473 d_ino = ino;
474 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
475 buf->error = -EOVERFLOW;
476 return -EOVERFLOW;
478 dirent = buf->previous;
479 if (dirent) {
480 if (signal_pending(current))
481 return -EINTR;
482 if (__put_user(offset, &dirent->d_off))
483 goto efault;
485 dirent = buf->current_dir;
486 if (__put_user(d_ino, &dirent->d_ino))
487 goto efault;
488 if (__put_user(reclen, &dirent->d_reclen))
489 goto efault;
490 if (copy_to_user(dirent->d_name, name, namlen))
491 goto efault;
492 if (__put_user(0, dirent->d_name + namlen))
493 goto efault;
494 if (__put_user(d_type, (char __user *) dirent + reclen - 1))
495 goto efault;
496 buf->previous = dirent;
497 dirent = (void __user *)dirent + reclen;
498 buf->current_dir = dirent;
499 buf->count -= reclen;
500 return 0;
501 efault:
502 buf->error = -EFAULT;
503 return -EFAULT;
506 COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
507 struct compat_linux_dirent __user *, dirent, unsigned int, count)
509 struct fd f;
510 struct compat_linux_dirent __user * lastdirent;
511 struct compat_getdents_callback buf = {
512 .ctx.actor = compat_filldir,
513 .current_dir = dirent,
514 .count = count
516 int error;
518 if (!access_ok(VERIFY_WRITE, dirent, count))
519 return -EFAULT;
521 f = fdget_pos(fd);
522 if (!f.file)
523 return -EBADF;
525 error = iterate_dir(f.file, &buf.ctx);
526 if (error >= 0)
527 error = buf.error;
528 lastdirent = buf.previous;
529 if (lastdirent) {
530 if (put_user(buf.ctx.pos, &lastdirent->d_off))
531 error = -EFAULT;
532 else
533 error = count - buf.count;
535 fdput_pos(f);
536 return error;
538 #endif