[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:
parent
b8227554c9
commit
2c6a2473b8
1 changed files with 54 additions and 50 deletions
104
fs/fat/dir.c
104
fs/fat/dir.c
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue