[readdir] introduce ->iterate(), ctx->pos, dir_emit()
New method - ->iterate(file, ctx). That's the replacement for ->readdir(); it takes callback from ctx->actor, uses ctx->pos instead of file->f_pos and calls dir_emit(ctx, ...) instead of filldir(data, ...). It does *not* update file->f_pos (or look at it, for that matter); iterate_dir() does the update. Note that dir_emit() takes the offset from ctx->pos (and eventually filldir_t will lose that argument). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
15
fs/readdir.c
15
fs/readdir.c
@@ -24,7 +24,7 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
int res = -ENOTDIR;
|
||||
if (!file->f_op || !file->f_op->readdir)
|
||||
if (!file->f_op || (!file->f_op->readdir && !file->f_op->iterate))
|
||||
goto out;
|
||||
|
||||
res = security_file_permission(file, MAY_READ);
|
||||
@@ -37,7 +37,14 @@ int iterate_dir(struct file *file, struct dir_context *ctx)
|
||||
|
||||
res = -ENOENT;
|
||||
if (!IS_DEADDIR(inode)) {
|
||||
res = file->f_op->readdir(file, ctx, ctx->actor);
|
||||
if (file->f_op->iterate) {
|
||||
ctx->pos = file->f_pos;
|
||||
res = file->f_op->iterate(file, ctx);
|
||||
file->f_pos = ctx->pos;
|
||||
} else {
|
||||
res = file->f_op->readdir(file, ctx, ctx->actor);
|
||||
ctx->pos = file->f_pos;
|
||||
}
|
||||
file_accessed(file);
|
||||
}
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
@@ -214,7 +221,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
if (lastdirent) {
|
||||
if (put_user(f.file->f_pos, &lastdirent->d_off))
|
||||
if (put_user(buf.ctx.pos, &lastdirent->d_off))
|
||||
error = -EFAULT;
|
||||
else
|
||||
error = count - buf.count;
|
||||
@@ -296,7 +303,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
if (lastdirent) {
|
||||
typeof(lastdirent->d_off) d_off = f.file->f_pos;
|
||||
typeof(lastdirent->d_off) d_off = buf.ctx.pos;
|
||||
if (__put_user(d_off, &lastdirent->d_off))
|
||||
error = -EFAULT;
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user