Skip to content

Commit

Permalink
[readdir] convert fatfs
Browse files Browse the repository at this point in the history
... pox upon the idiotic ioctls; life would be much easier without
those.

Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Al Viro committed Jun 29, 2013
1 parent b822755 commit 2c6a247
Showing 1 changed file with 54 additions and 50 deletions.
104 changes: 54 additions & 50 deletions fs/fat/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
EXPORT_SYMBOL_GPL(fat_search_long);

struct fat_ioctl_filldir_callback {
struct dir_context ctx;
void __user *dirent;
int result;
/* for dir ioctl */
Expand All @@ -552,8 +553,9 @@ struct fat_ioctl_filldir_callback {
int short_len;
};

static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
filldir_t filldir, int short_only, int both)
static int __fat_readdir(struct inode *inode, struct file *file,
struct dir_context *ctx, int short_only,
struct fat_ioctl_filldir_callback *both)
{
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
Expand All @@ -564,27 +566,20 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
unsigned char bufname[FAT_MAX_SHORT_SIZE];
int isvfat = sbi->options.isvfat;
const char *fill_name = NULL;
unsigned long inum;
unsigned long lpos, dummy, *furrfu = &lpos;
int fake_offset = 0;
loff_t cpos;
int short_len = 0, fill_len = 0;
int ret = 0;

mutex_lock(&sbi->s_lock);

cpos = filp->f_pos;
cpos = ctx->pos;
/* Fake . and .. for the root directory. */
if (inode->i_ino == MSDOS_ROOT_INO) {
while (cpos < 2) {
if (filldir(dirent, "..", cpos+1, cpos,
MSDOS_ROOT_INO, DT_DIR) < 0)
goto out;
cpos++;
filp->f_pos++;
}
if (cpos == 2) {
dummy = 2;
furrfu = &dummy;
if (!dir_emit_dots(file, ctx))
goto out;
if (ctx->pos == 2) {
fake_offset = 1;
cpos = 0;
}
}
Expand Down Expand Up @@ -619,7 +614,7 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
int status = fat_parse_long(inode, &cpos, &bh, &de,
&unicode, &nr_slots);
if (status < 0) {
filp->f_pos = cpos;
ctx->pos = cpos;
ret = status;
goto out;
} else if (status == PARSE_INVALID)
Expand All @@ -639,54 +634,59 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
/* !both && !short_only, so we don't need shortname. */
if (!both)
goto start_filldir;

short_len = fat_parse_short(sb, de, bufname,
sbi->options.dotsOK);
if (short_len == 0)
goto record_end;
/* hack for fat_ioctl_filldir() */
both->longname = fill_name;
both->long_len = fill_len;
both->shortname = bufname;
both->short_len = short_len;
fill_name = NULL;
fill_len = 0;
goto start_filldir;
}
}

short_len = fat_parse_short(sb, de, bufname, sbi->options.dotsOK);
if (short_len == 0)
goto record_end;

if (nr_slots) {
/* hack for fat_ioctl_filldir() */
struct fat_ioctl_filldir_callback *p = dirent;

p->longname = fill_name;
p->long_len = fill_len;
p->shortname = bufname;
p->short_len = short_len;
fill_name = NULL;
fill_len = 0;
} else {
fill_name = bufname;
fill_len = short_len;
}
fill_name = bufname;
fill_len = short_len;

start_filldir:
lpos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME))
inum = inode->i_ino;
else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
inum = parent_ino(filp->f_path.dentry);
if (!fake_offset)
ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);

if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) {
if (!dir_emit_dot(file, ctx))
goto fill_failed;
} else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
if (!dir_emit_dotdot(file, ctx))
goto fill_failed;
} else {
unsigned long inum;
loff_t i_pos = fat_make_i_pos(sb, bh, de);
struct inode *tmp = fat_iget(sb, i_pos);
if (tmp) {
inum = tmp->i_ino;
iput(tmp);
} else
inum = iunique(sb, MSDOS_ROOT_INO);
if (!dir_emit(ctx, fill_name, fill_len, inum,
(de->attr & ATTR_DIR) ? DT_DIR : DT_REG))
goto fill_failed;
}

if (filldir(dirent, fill_name, fill_len, *furrfu, inum,
(de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
goto fill_failed;

record_end:
furrfu = &lpos;
filp->f_pos = cpos;
fake_offset = 0;
ctx->pos = cpos;
goto get_new;
end_of_dir:
filp->f_pos = cpos;
ctx->pos = cpos;
fill_failed:
brelse(bh);
if (unicode)
Expand All @@ -696,10 +696,9 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
return ret;
}

static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int fat_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(filp);
return __fat_readdir(inode, filp, dirent, filldir, 0, 0);
return __fat_readdir(file_inode(file), file, ctx, 0, NULL);
}

#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \
Expand Down Expand Up @@ -755,20 +754,25 @@ efault: \

FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, __fat_dirent)

static int fat_ioctl_readdir(struct inode *inode, struct file *filp,
static int fat_ioctl_readdir(struct inode *inode, struct file *file,
void __user *dirent, filldir_t filldir,
int short_only, int both)
{
struct fat_ioctl_filldir_callback buf;
struct fat_ioctl_filldir_callback buf = {
.ctx.actor = filldir,
.dirent = dirent
};
int ret;

buf.dirent = dirent;
buf.result = 0;
mutex_lock(&inode->i_mutex);
buf.ctx.pos = file->f_pos;
ret = -ENOENT;
if (!IS_DEADDIR(inode)) {
ret = __fat_readdir(inode, filp, &buf, filldir,
short_only, both);
ret = __fat_readdir(inode, file, &buf.ctx,
short_only, both ? &buf : NULL);
file->f_pos = buf.ctx.pos;
}
mutex_unlock(&inode->i_mutex);
if (ret >= 0)
Expand Down Expand Up @@ -854,7 +858,7 @@ static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,
const struct file_operations fat_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = fat_readdir,
.iterate = fat_readdir,
.unlocked_ioctl = fat_dir_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fat_compat_dir_ioctl,
Expand Down

0 comments on commit 2c6a247

Please sign in to comment.