diff options
| author | Hirofumi Ogawa <hirofumi@mail.parknet.co.jp> | 2003-05-27 05:56:40 -0700 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 2003-05-27 05:56:40 -0700 |
| commit | e7ddc6ac9e8f1014bbc096b2d8daa05aedab0e50 (patch) | |
| tree | 264e5023c3cc9559a5fee4ef35fb2e3ecfb50274 /fs | |
| parent | 99df9271d098308964fa014776c4a54c0d6fb664 (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.c | 112 |
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 */ |
