summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorHirofumi Ogawa <hirofumi@mail.parknet.co.jp>2003-05-27 05:56:40 -0700
committerArnaldo Carvalho de Melo <acme@conectiva.com.br>2003-05-27 05:56:40 -0700
commite7ddc6ac9e8f1014bbc096b2d8daa05aedab0e50 (patch)
tree264e5023c3cc9559a5fee4ef35fb2e3ecfb50274 /fs
parent99df9271d098308964fa014776c4a54c0d6fb664 (diff)
[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>
Diffstat (limited to 'fs')
-rw-r--r--fs/fat/dir.c112
1 files changed, 59 insertions, 53 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 01c006023d3c..d10571657ecb 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -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 */