Commit e7ddc6ac authored by Hirofumi Ogawa's avatar Hirofumi Ogawa Committed by Arnaldo Carvalho de Melo

[PATCH] Fix VFAT_IOCTL_READDIR_BOTH/_SHORT ioctl (2/5)

This fixes the return value of ioctl() for enables using the same way as
readdir().

put/get_user() return code check patch from John R R Leavitt
<jrrl@steampunk.com>
parent 99df9271
......@@ -366,7 +366,7 @@ static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
lock_kernel();
cpos = filp->f_pos;
/* Fake . and .. for the root directory. */
/* 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)
......@@ -592,23 +592,23 @@ int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
return fat_readdirx(inode, filp, dirent, filldir, 0, 0);
}
static int vfat_ioctl_fill(
void * buf,
const char * name,
int name_len,
loff_t offset,
ino_t ino,
unsigned int d_type)
struct fat_ioctl_filldir_callback {
struct dirent __user *dirent;
int result;
};
static int fat_ioctl_filldir(void *__buf, const char * name, int name_len,
loff_t offset, ino_t ino, unsigned int d_type)
{
struct dirent *d1 = (struct dirent *)buf;
struct dirent *d2 = d1 + 1;
struct fat_ioctl_filldir_callback *buf = __buf;
struct dirent __user *d1 = buf->dirent;
struct dirent __user *d2 = d1 + 1;
int len, slen;
int dotdir;
get_user(len, &d1->d_reclen);
if (len != 0) {
return -1;
}
if (buf->result)
return -EINVAL;
buf->result++;
if ((name_len == 1 && name[0] == '.') ||
(name_len == 2 && name[0] == '.' && name[1] == '.')) {
......@@ -619,60 +619,66 @@ static int vfat_ioctl_fill(
len = strlen(name);
}
if (len != name_len) {
copy_to_user(d2->d_name, name, len);
put_user(0, d2->d_name + len);
put_user(len, &d2->d_reclen);
put_user(ino, &d2->d_ino);
put_user(offset, &d2->d_off);
slen = name_len - len;
copy_to_user(d1->d_name, name+len+1, slen);
put_user(0, d1->d_name+slen);
put_user(slen, &d1->d_reclen);
if (copy_to_user(d2->d_name, name, len) ||
put_user(0, d2->d_name + len) ||
put_user(len, &d2->d_reclen) ||
put_user(ino, &d2->d_ino) ||
put_user(offset, &d2->d_off) ||
copy_to_user(d1->d_name, name+len+1, slen) ||
put_user(0, d1->d_name+slen) ||
put_user(slen, &d1->d_reclen))
goto efault;
} else {
put_user(0, d2->d_name);
put_user(0, &d2->d_reclen);
copy_to_user(d1->d_name, name, len);
put_user(0, d1->d_name+len);
put_user(len, &d1->d_reclen);
if (put_user(0, d2->d_name) ||
put_user(0, &d2->d_reclen) ||
copy_to_user(d1->d_name, name, len) ||
put_user(0, d1->d_name+len) ||
put_user(len, &d1->d_reclen))
goto efault;
}
return 0;
efault:
buf->result = -EFAULT;
return -EFAULT;
}
int fat_dir_ioctl(struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg)
{
int err;
struct fat_ioctl_filldir_callback buf;
struct dirent __user *d1 = (struct dirent *)arg;
int ret, shortname, both;
if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2])))
return -EFAULT;
/*
* We want to provide an interface for Samba to be able
* to get the short filename for a given long filename.
* Samba should use this ioctl instead of readdir() to
* get the information it needs.
* Yes, we don't need this put_user() absolutely. However old
* code didn't return the right value. So, app use this value,
* in order to check whether it is EOF.
*/
if (put_user(0, &d1->d_reclen))
return -EFAULT;
buf.dirent = d1;
buf.result = 0;
switch (cmd) {
case VFAT_IOCTL_READDIR_BOTH: {
struct dirent *d1 = (struct dirent *)arg;
err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
if (err)
return err;
put_user(0, &d1->d_reclen);
return fat_readdirx(inode,filp,(void *)arg,
vfat_ioctl_fill, 0, 1);
}
case VFAT_IOCTL_READDIR_SHORT: {
struct dirent *d1 = (struct dirent *)arg;
put_user(0, &d1->d_reclen);
err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
if (err)
return err;
return fat_readdirx(inode,filp,(void *)arg,
vfat_ioctl_fill, 1, 1);
}
case VFAT_IOCTL_READDIR_SHORT:
shortname = 1;
both = 1;
break;
case VFAT_IOCTL_READDIR_BOTH:
shortname = 0;
both = 1;
break;
default:
return -EINVAL;
}
return 0;
ret = fat_readdirx(inode, filp, &buf, fat_ioctl_filldir,
shortname, both);
if (ret >= 0)
ret = buf.result;
return ret;
}
/***** See if directory is empty */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment