Release 4.7 fs/readdir.c
/*
* linux/fs/readdir.c
*
* Copyright (C) 1995 Linus Torvalds
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/fsnotify.h>
#include <linux/dirent.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
#include <asm/uaccess.h>
int iterate_dir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(file);
bool shared = false;
int res = -ENOTDIR;
if (file->f_op->iterate_shared)
shared = true;
else if (!file->f_op->iterate)
goto out;
res = security_file_permission(file, MAY_READ);
if (res)
goto out;
if (shared) {
inode_lock_shared(inode);
} else {
res = down_write_killable(&inode->i_rwsem);
if (res)
goto out;
}
res = -ENOENT;
if (!IS_DEADDIR(inode)) {
ctx->pos = file->f_pos;
if (shared)
res = file->f_op->iterate_shared(file, ctx);
else
res = file->f_op->iterate(file, ctx);
file->f_pos = ctx->pos;
fsnotify_access(file);
file_accessed(file);
}
if (shared)
inode_unlock_shared(inode);
else
inode_unlock(inode);
out:
return res;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 114 | 57.00% | 7 | 46.67% |
pre-git | pre-git | 62 | 31.00% | 3 | 20.00% |
stephen d. smalley | stephen d. smalley | 11 | 5.50% | 1 | 6.67% |
greg kroah-hartman | greg kroah-hartman | 5 | 2.50% | 2 | 13.33% |
heinrich schuchardt | heinrich schuchardt | 5 | 2.50% | 1 | 6.67% |
andrew morton | andrew morton | 3 | 1.50% | 1 | 6.67% |
| Total | 200 | 100.00% | 15 | 100.00% |
EXPORT_SYMBOL(iterate_dir);
/*
* Traditional linux readdir() handling..
*
* "count=1" is a special case, meaning that the buffer is one
* dirent-structure in size and that the code can't handle more
* anyway. Thus the special "fillonedir()" function for that
* case (the low-level handlers don't need to care about this).
*/
#ifdef __ARCH_WANT_OLD_READDIR
struct old_linux_dirent {
unsigned long d_ino;
unsigned long d_offset;
unsigned short d_namlen;
char d_name[1];
};
struct readdir_callback {
struct dir_context ctx;
struct old_linux_dirent __user * dirent;
int result;
};
static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
loff_t offset, u64 ino, unsigned int d_type)
{
struct readdir_callback *buf =
container_of(ctx, struct readdir_callback, ctx);
struct old_linux_dirent __user * dirent;
unsigned long d_ino;
if (buf->result)
return -EINVAL;
d_ino = ino;
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
buf->result = -EOVERFLOW;
return -EOVERFLOW;
}
buf->result++;
dirent = buf->dirent;
if (!access_ok(VERIFY_WRITE, dirent,
(unsigned long)(dirent->d_name + namlen + 1) -
(unsigned long)dirent))
goto efault;
if ( __put_user(d_ino, &dirent->d_ino) ||
__put_user(offset, &dirent->d_offset) ||
__put_user(namlen, &dirent->d_namlen) ||
__copy_to_user(dirent->d_name, name, namlen) ||
__put_user(0, dirent->d_name + namlen))
goto efault;
return 0;
efault:
buf->result = -EFAULT;
return -EFAULT;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pre-git | pre-git | 99 | 46.26% | 4 | 36.36% |
andrew morton | andrew morton | 64 | 29.91% | 2 | 18.18% |
david howells | david howells | 30 | 14.02% | 1 | 9.09% |
miklos szeredi | miklos szeredi | 10 | 4.67% | 1 | 9.09% |
al viro | al viro | 9 | 4.21% | 1 | 9.09% |
linus torvalds | linus torvalds | 2 | 0.93% | 2 | 18.18% |
| Total | 214 | 100.00% | 11 | 100.00% |
SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
struct old_linux_dirent __user *, dirent, unsigned int, count)
{
int error;
struct fd f = fdget_pos(fd);
struct readdir_callback buf = {
.ctx.actor = fillonedir,
.dirent = dirent
};
if (!f.file)
return -EBADF;
error = iterate_dir(f.file, &buf.ctx);
if (buf.result)
error = buf.result;
fdput_pos(f);
return error;
}
#endif /* __ARCH_WANT_OLD_READDIR */
/*
* New, all-improved, singing, dancing, iBCS2-compliant getdents()
* interface.
*/
struct linux_dirent {
unsigned long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[1];
};
struct getdents_callback {
struct dir_context ctx;
struct linux_dirent __user * current_dir;
struct linux_dirent __user * previous;
int count;
int error;
};
static int filldir(struct dir_context *ctx, const char *name, int namlen,
loff_t offset, u64 ino, unsigned int d_type)
{
struct linux_dirent __user * dirent;
struct getdents_callback *buf =
container_of(ctx, struct getdents_callback, ctx);
unsigned long d_ino;
int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
sizeof(long));
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
d_ino = ino;
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
buf->error = -EOVERFLOW;
return -EOVERFLOW;
}
dirent = buf->previous;
if (dirent) {
if (signal_pending(current))
return -EINTR;
if (__put_user(offset, &dirent->d_off))
goto efault;
}
dirent = buf->current_dir;
if (__put_user(d_ino, &dirent->d_ino))
goto efault;
if (__put_user(reclen, &dirent->d_reclen))
goto efault;
if (copy_to_user(dirent->d_name, name, namlen))
goto efault;
if (__put_user(0, dirent->d_name + namlen))
goto efault;
if (__put_user(d_type, (char __user *) dirent + reclen - 1))
goto efault;
buf->previous = dirent;
dirent = (void __user *)dirent + reclen;
buf->current_dir = dirent;
buf->count -= reclen;
return 0;
efault:
buf->error = -EFAULT;
return -EFAULT;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pre-git | pre-git | 147 | 48.68% | 7 | 31.82% |
andrew morton | andrew morton | 55 | 18.21% | 3 | 13.64% |
david howells | david howells | 30 | 9.93% | 1 | 4.55% |
linus torvalds | linus torvalds | 28 | 9.27% | 5 | 22.73% |
theodore tso | theodore tso | 11 | 3.64% | 1 | 4.55% |
miklos szeredi | miklos szeredi | 10 | 3.31% | 1 | 4.55% |
al viro | al viro | 10 | 3.31% | 2 | 9.09% |
milind arun choudhary | milind arun choudhary | 6 | 1.99% | 1 | 4.55% |
kevin winchester | kevin winchester | 5 | 1.66% | 1 | 4.55% |
| Total | 302 | 100.00% | 22 | 100.00% |
SYSCALL_DEFINE3(getdents, unsigned int, fd,
struct linux_dirent __user *, dirent, unsigned int, count)
{
struct fd f;
struct linux_dirent __user * lastdirent;
struct getdents_callback buf = {
.ctx.actor = filldir,
.count = count,
.current_dir = dirent
};
int error;
if (!access_ok(VERIFY_WRITE, dirent, count))
return -EFAULT;
f = fdget_pos(fd);
if (!f.file)
return -EBADF;
error = iterate_dir(f.file, &buf.ctx);
if (error >= 0)
error = buf.error;
lastdirent = buf.previous;
if (lastdirent) {
if (put_user(buf.ctx.pos, &lastdirent->d_off))
error = -EFAULT;
else
error = count - buf.count;
}
fdput_pos(f);
return error;
}
struct getdents_callback64 {
struct dir_context ctx;
struct linux_dirent64 __user * current_dir;
struct linux_dirent64 __user * previous;
int count;
int error;
};
static int filldir64(struct dir_context *ctx, const char *name, int namlen,
loff_t offset, u64 ino, unsigned int d_type)
{
struct linux_dirent64 __user *dirent;
struct getdents_callback64 *buf =
container_of(ctx, struct getdents_callback64, ctx);
int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
sizeof(u64));
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
dirent = buf->previous;
if (dirent) {
if (signal_pending(current))
return -EINTR;
if (__put_user(offset, &dirent->d_off))
goto efault;
}
dirent = buf->current_dir;
if (__put_user(ino, &dirent->d_ino))
goto efault;
if (__put_user(0, &dirent->d_off))
goto efault;
if (__put_user(reclen, &dirent->d_reclen))
goto efault;
if (__put_user(d_type, &dirent->d_type))
goto efault;
if (copy_to_user(dirent->d_name, name, namlen))
goto efault;
if (__put_user(0, dirent->d_name + namlen))
goto efault;
buf->previous = dirent;
dirent = (void __user *)dirent + reclen;
buf->current_dir = dirent;
buf->count -= reclen;
return 0;
efault:
buf->error = -EFAULT;
return -EFAULT;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pre-git | pre-git | 142 | 51.82% | 1 | 7.14% |
andrew morton | andrew morton | 93 | 33.94% | 3 | 21.43% |
theodore tso | theodore tso | 11 | 4.01% | 1 | 7.14% |
miklos szeredi | miklos szeredi | 10 | 3.65% | 1 | 7.14% |
linus torvalds | linus torvalds | 6 | 2.19% | 5 | 35.71% |
milind arun choudhary | milind arun choudhary | 6 | 2.19% | 1 | 7.14% |
kevin winchester | kevin winchester | 5 | 1.82% | 1 | 7.14% |
david howells | david howells | 1 | 0.36% | 1 | 7.14% |
| Total | 274 | 100.00% | 14 | 100.00% |
SYSCALL_DEFINE3(getdents64, unsigned int, fd,
struct linux_dirent64 __user *, dirent, unsigned int, count)
{
struct fd f;
struct linux_dirent64 __user * lastdirent;
struct getdents_callback64 buf = {
.ctx.actor = filldir64,
.count = count,
.current_dir = dirent
};
int error;
if (!access_ok(VERIFY_WRITE, dirent, count))
return -EFAULT;
f = fdget_pos(fd);
if (!f.file)
return -EBADF;
error = iterate_dir(f.file, &buf.ctx);
if (error >= 0)
error = buf.error;
lastdirent = buf.previous;
if (lastdirent) {
typeof(lastdirent->d_off) d_off = buf.ctx.pos;
if (__put_user(d_off, &lastdirent->d_off))
error = -EFAULT;
else
error = count - buf.count;
}
fdput_pos(f);
return error;
}
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pre-git | pre-git | 766 | 47.99% | 17 | 26.98% |
al viro | al viro | 281 | 17.61% | 14 | 22.22% |
andrew morton | andrew morton | 251 | 15.73% | 8 | 12.70% |
linus torvalds | linus torvalds | 61 | 3.82% | 6 | 9.52% |
david howells | david howells | 61 | 3.82% | 1 | 1.59% |
heiko carstens | heiko carstens | 48 | 3.01% | 2 | 3.17% |
miklos szeredi | miklos szeredi | 30 | 1.88% | 1 | 1.59% |
theodore tso | theodore tso | 22 | 1.38% | 1 | 1.59% |
milind arun choudhary | milind arun choudhary | 15 | 0.94% | 1 | 1.59% |
kevin winchester | kevin winchester | 13 | 0.81% | 1 | 1.59% |
stephen d. smalley | stephen d. smalley | 11 | 0.69% | 1 | 1.59% |
greg kroah-hartman | greg kroah-hartman | 8 | 0.50% | 3 | 4.76% |
heinrich schuchardt | heinrich schuchardt | 8 | 0.50% | 1 | 1.59% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 6 | 0.38% | 1 | 1.59% |
adam kropelin | adam kropelin | 4 | 0.25% | 1 | 1.59% |
dave jones | dave jones | 4 | 0.25% | 1 | 1.59% |
arnd bergmann | arnd bergmann | 3 | 0.19% | 1 | 1.59% |
prasanna meda | prasanna meda | 3 | 0.19% | 1 | 1.59% |
paul gortmaker | paul gortmaker | 1 | 0.06% | 1 | 1.59% |
| Total | 1596 | 100.00% | 63 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.