[readdir] convert fatfs

... pox upon the idiotic ioctls; life would be much easier without
those.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2013-05-22 18:37:16 -04:00
parent b8227554c9
commit 2c6a2473b8

View file

@ -543,6 +543,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
EXPORT_SYMBOL_GPL(fat_search_long); EXPORT_SYMBOL_GPL(fat_search_long);
struct fat_ioctl_filldir_callback { struct fat_ioctl_filldir_callback {
struct dir_context ctx;
void __user *dirent; void __user *dirent;
int result; int result;
/* for dir ioctl */ /* for dir ioctl */
@ -552,8 +553,9 @@ struct fat_ioctl_filldir_callback {
int short_len; int short_len;
}; };
static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent, static int __fat_readdir(struct inode *inode, struct file *file,
filldir_t filldir, int short_only, int both) struct dir_context *ctx, int short_only,
struct fat_ioctl_filldir_callback *both)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb); struct msdos_sb_info *sbi = MSDOS_SB(sb);
@ -564,27 +566,20 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
unsigned char bufname[FAT_MAX_SHORT_SIZE]; unsigned char bufname[FAT_MAX_SHORT_SIZE];
int isvfat = sbi->options.isvfat; int isvfat = sbi->options.isvfat;
const char *fill_name = NULL; const char *fill_name = NULL;
unsigned long inum; int fake_offset = 0;
unsigned long lpos, dummy, *furrfu = &lpos;
loff_t cpos; loff_t cpos;
int short_len = 0, fill_len = 0; int short_len = 0, fill_len = 0;
int ret = 0; int ret = 0;
mutex_lock(&sbi->s_lock); mutex_lock(&sbi->s_lock);
cpos = filp->f_pos; cpos = ctx->pos;
/* Fake . and .. for the root directory. */ /* Fake . and .. for the root directory. */
if (inode->i_ino == MSDOS_ROOT_INO) { if (inode->i_ino == MSDOS_ROOT_INO) {
while (cpos < 2) { if (!dir_emit_dots(file, ctx))
if (filldir(dirent, "..", cpos+1, cpos, goto out;
MSDOS_ROOT_INO, DT_DIR) < 0) if (ctx->pos == 2) {
goto out; fake_offset = 1;
cpos++;
filp->f_pos++;
}
if (cpos == 2) {
dummy = 2;
furrfu = &dummy;
cpos = 0; cpos = 0;
} }
} }
@ -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, int status = fat_parse_long(inode, &cpos, &bh, &de,
&unicode, &nr_slots); &unicode, &nr_slots);
if (status < 0) { if (status < 0) {
filp->f_pos = cpos; ctx->pos = cpos;
ret = status; ret = status;
goto out; goto out;
} else if (status == PARSE_INVALID) } else if (status == PARSE_INVALID)
@ -639,6 +634,19 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
/* !both && !short_only, so we don't need shortname. */ /* !both && !short_only, so we don't need shortname. */
if (!both) if (!both)
goto start_filldir; 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;
} }
} }
@ -646,28 +654,21 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
if (short_len == 0) if (short_len == 0)
goto record_end; goto record_end;
if (nr_slots) { fill_name = bufname;
/* hack for fat_ioctl_filldir() */ fill_len = short_len;
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;
}
start_filldir: start_filldir:
lpos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry); if (!fake_offset)
if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
inum = inode->i_ino;
else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) {
inum = parent_ino(filp->f_path.dentry); 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 { } else {
unsigned long inum;
loff_t i_pos = fat_make_i_pos(sb, bh, de); loff_t i_pos = fat_make_i_pos(sb, bh, de);
struct inode *tmp = fat_iget(sb, i_pos); struct inode *tmp = fat_iget(sb, i_pos);
if (tmp) { if (tmp) {
@ -675,18 +676,17 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
iput(tmp); iput(tmp);
} else } else
inum = iunique(sb, MSDOS_ROOT_INO); 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: record_end:
furrfu = &lpos; fake_offset = 0;
filp->f_pos = cpos; ctx->pos = cpos;
goto get_new; goto get_new;
end_of_dir: end_of_dir:
filp->f_pos = cpos; ctx->pos = cpos;
fill_failed: fill_failed:
brelse(bh); brelse(bh);
if (unicode) if (unicode)
@ -696,10 +696,9 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
return ret; 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(file_inode(file), file, ctx, 0, NULL);
return __fat_readdir(inode, filp, dirent, filldir, 0, 0);
} }
#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \ #define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \
@ -755,20 +754,25 @@ efault: \
FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, __fat_dirent) 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, void __user *dirent, filldir_t filldir,
int short_only, int both) int short_only, int both)
{ {
struct fat_ioctl_filldir_callback buf; struct fat_ioctl_filldir_callback buf = {
.ctx.actor = filldir,
.dirent = dirent
};
int ret; int ret;
buf.dirent = dirent; buf.dirent = dirent;
buf.result = 0; buf.result = 0;
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
buf.ctx.pos = file->f_pos;
ret = -ENOENT; ret = -ENOENT;
if (!IS_DEADDIR(inode)) { if (!IS_DEADDIR(inode)) {
ret = __fat_readdir(inode, filp, &buf, filldir, ret = __fat_readdir(inode, file, &buf.ctx,
short_only, both); short_only, both ? &buf : NULL);
file->f_pos = buf.ctx.pos;
} }
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
if (ret >= 0) if (ret >= 0)
@ -854,7 +858,7 @@ static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,
const struct file_operations fat_dir_operations = { const struct file_operations fat_dir_operations = {
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
.read = generic_read_dir, .read = generic_read_dir,
.readdir = fat_readdir, .iterate = fat_readdir,
.unlocked_ioctl = fat_dir_ioctl, .unlocked_ioctl = fat_dir_ioctl,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = fat_compat_dir_ioctl, .compat_ioctl = fat_compat_dir_ioctl,