Lines 422-428
EODir:
Link Here
|
422 |
EXPORT_SYMBOL_GPL(fat_search_long); |
422 |
EXPORT_SYMBOL_GPL(fat_search_long); |
423 |
|
423 |
|
424 |
struct fat_ioctl_filldir_callback { |
424 |
struct fat_ioctl_filldir_callback { |
425 |
struct dirent __user *dirent; |
425 |
void __user *dirent; |
426 |
int result; |
426 |
int result; |
427 |
/* for dir ioctl */ |
427 |
/* for dir ioctl */ |
428 |
const char *longname; |
428 |
const char *longname; |
Lines 647-708
static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
Link Here
|
647 |
return __fat_readdir(inode, filp, dirent, filldir, 0, 0); |
647 |
return __fat_readdir(inode, filp, dirent, filldir, 0, 0); |
648 |
} |
648 |
} |
649 |
|
649 |
|
650 |
static int fat_ioctl_filldir(void *__buf, const char *name, int name_len, |
650 |
#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \ |
651 |
loff_t offset, u64 ino, unsigned int d_type) |
651 |
static int func(void *__buf, const char *name, int name_len, \ |
|
|
652 |
loff_t offset, u64 ino, unsigned int d_type) \ |
653 |
{ \ |
654 |
struct fat_ioctl_filldir_callback *buf = __buf; \ |
655 |
struct dirent_type __user *d1 = buf->dirent; \ |
656 |
struct dirent_type __user *d2 = d1 + 1; \ |
657 |
\ |
658 |
if (buf->result) \ |
659 |
return -EINVAL; \ |
660 |
buf->result++; \ |
661 |
\ |
662 |
if (name != NULL) { \ |
663 |
/* dirent has only short name */ \ |
664 |
if (name_len >= sizeof(d1->d_name)) \ |
665 |
name_len = sizeof(d1->d_name) - 1; \ |
666 |
\ |
667 |
if (put_user(0, d2->d_name) || \ |
668 |
put_user(0, &d2->d_reclen) || \ |
669 |
copy_to_user(d1->d_name, name, name_len) || \ |
670 |
put_user(0, d1->d_name + name_len) || \ |
671 |
put_user(name_len, &d1->d_reclen)) \ |
672 |
goto efault; \ |
673 |
} else { \ |
674 |
/* dirent has short and long name */ \ |
675 |
const char *longname = buf->longname; \ |
676 |
int long_len = buf->long_len; \ |
677 |
const char *shortname = buf->shortname; \ |
678 |
int short_len = buf->short_len; \ |
679 |
\ |
680 |
if (long_len >= sizeof(d1->d_name)) \ |
681 |
long_len = sizeof(d1->d_name) - 1; \ |
682 |
if (short_len >= sizeof(d1->d_name)) \ |
683 |
short_len = sizeof(d1->d_name) - 1; \ |
684 |
\ |
685 |
if (copy_to_user(d2->d_name, longname, long_len) || \ |
686 |
put_user(0, d2->d_name + long_len) || \ |
687 |
put_user(long_len, &d2->d_reclen) || \ |
688 |
put_user(ino, &d2->d_ino) || \ |
689 |
put_user(offset, &d2->d_off) || \ |
690 |
copy_to_user(d1->d_name, shortname, short_len) || \ |
691 |
put_user(0, d1->d_name + short_len) || \ |
692 |
put_user(short_len, &d1->d_reclen)) \ |
693 |
goto efault; \ |
694 |
} \ |
695 |
return 0; \ |
696 |
efault: \ |
697 |
buf->result = -EFAULT; \ |
698 |
return -EFAULT; \ |
699 |
} |
700 |
|
701 |
FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, dirent) |
702 |
|
703 |
static int fat_ioctl_readdir(struct inode *inode, struct file *filp, |
704 |
void __user *dirent, filldir_t filldir, |
705 |
int short_only, int both) |
652 |
{ |
706 |
{ |
653 |
struct fat_ioctl_filldir_callback *buf = __buf; |
707 |
struct fat_ioctl_filldir_callback buf; |
654 |
struct dirent __user *d1 = buf->dirent; |
708 |
int ret; |
655 |
struct dirent __user *d2 = d1 + 1; |
709 |
|
656 |
|
710 |
buf.dirent = dirent; |
657 |
if (buf->result) |
711 |
buf.result = 0; |
658 |
return -EINVAL; |
712 |
mutex_lock(&inode->i_mutex); |
659 |
buf->result++; |
713 |
ret = -ENOENT; |
660 |
|
714 |
if (!IS_DEADDIR(inode)) { |
661 |
if (name != NULL) { |
715 |
ret = __fat_readdir(inode, filp, &buf, filldir, |
662 |
/* dirent has only short name */ |
716 |
short_only, both); |
663 |
if (name_len >= sizeof(d1->d_name)) |
|
|
664 |
name_len = sizeof(d1->d_name) - 1; |
665 |
|
666 |
if (put_user(0, d2->d_name) || |
667 |
put_user(0, &d2->d_reclen) || |
668 |
copy_to_user(d1->d_name, name, name_len) || |
669 |
put_user(0, d1->d_name + name_len) || |
670 |
put_user(name_len, &d1->d_reclen)) |
671 |
goto efault; |
672 |
} else { |
673 |
/* dirent has short and long name */ |
674 |
const char *longname = buf->longname; |
675 |
int long_len = buf->long_len; |
676 |
const char *shortname = buf->shortname; |
677 |
int short_len = buf->short_len; |
678 |
|
679 |
if (long_len >= sizeof(d1->d_name)) |
680 |
long_len = sizeof(d1->d_name) - 1; |
681 |
if (short_len >= sizeof(d1->d_name)) |
682 |
short_len = sizeof(d1->d_name) - 1; |
683 |
|
684 |
if (copy_to_user(d2->d_name, longname, long_len) || |
685 |
put_user(0, d2->d_name + long_len) || |
686 |
put_user(long_len, &d2->d_reclen) || |
687 |
put_user(ino, &d2->d_ino) || |
688 |
put_user(offset, &d2->d_off) || |
689 |
copy_to_user(d1->d_name, shortname, short_len) || |
690 |
put_user(0, d1->d_name + short_len) || |
691 |
put_user(short_len, &d1->d_reclen)) |
692 |
goto efault; |
693 |
} |
717 |
} |
694 |
return 0; |
718 |
mutex_unlock(&inode->i_mutex); |
695 |
efault: |
719 |
if (ret >= 0) |
696 |
buf->result = -EFAULT; |
720 |
ret = buf.result; |
697 |
return -EFAULT; |
721 |
return ret; |
698 |
} |
722 |
} |
699 |
|
723 |
|
700 |
static int fat_dir_ioctl(struct inode * inode, struct file * filp, |
724 |
static int fat_dir_ioctl(struct inode *inode, struct file *filp, |
701 |
unsigned int cmd, unsigned long arg) |
725 |
unsigned int cmd, unsigned long arg) |
702 |
{ |
726 |
{ |
703 |
struct fat_ioctl_filldir_callback buf; |
727 |
struct dirent __user *d1 = (struct dirent __user *)arg; |
704 |
struct dirent __user *d1; |
728 |
int short_only, both; |
705 |
int ret, short_only, both; |
|
|
706 |
|
729 |
|
707 |
switch (cmd) { |
730 |
switch (cmd) { |
708 |
case VFAT_IOCTL_READDIR_SHORT: |
731 |
case VFAT_IOCTL_READDIR_SHORT: |
Lines 717-723
static int fat_dir_ioctl(struct inode * inode, struct file * filp,
Link Here
|
717 |
return fat_generic_ioctl(inode, filp, cmd, arg); |
740 |
return fat_generic_ioctl(inode, filp, cmd, arg); |
718 |
} |
741 |
} |
719 |
|
742 |
|
720 |
d1 = (struct dirent __user *)arg; |
|
|
721 |
if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2]))) |
743 |
if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2]))) |
722 |
return -EFAULT; |
744 |
return -EFAULT; |
723 |
/* |
745 |
/* |
Lines 728-796
static int fat_dir_ioctl(struct inode * inode, struct file * filp,
Link Here
|
728 |
if (put_user(0, &d1->d_reclen)) |
750 |
if (put_user(0, &d1->d_reclen)) |
729 |
return -EFAULT; |
751 |
return -EFAULT; |
730 |
|
752 |
|
731 |
buf.dirent = d1; |
753 |
return fat_ioctl_readdir(inode, filp, d1, fat_ioctl_filldir, |
732 |
buf.result = 0; |
754 |
short_only, both); |
733 |
mutex_lock(&inode->i_mutex); |
|
|
734 |
ret = -ENOENT; |
735 |
if (!IS_DEADDIR(inode)) { |
736 |
ret = __fat_readdir(inode, filp, &buf, fat_ioctl_filldir, |
737 |
short_only, both); |
738 |
} |
739 |
mutex_unlock(&inode->i_mutex); |
740 |
if (ret >= 0) |
741 |
ret = buf.result; |
742 |
return ret; |
743 |
} |
755 |
} |
744 |
|
756 |
|
745 |
#ifdef CONFIG_COMPAT |
757 |
#ifdef CONFIG_COMPAT |
746 |
#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2]) |
758 |
#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2]) |
747 |
#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2]) |
759 |
#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2]) |
748 |
|
760 |
|
749 |
static long fat_compat_put_dirent32(struct dirent *d, |
761 |
FAT_IOCTL_FILLDIR_FUNC(fat_compat_ioctl_filldir, compat_dirent) |
750 |
struct compat_dirent __user *d32) |
|
|
751 |
{ |
752 |
if (!access_ok(VERIFY_WRITE, d32, sizeof(struct compat_dirent))) |
753 |
return -EFAULT; |
754 |
|
755 |
__put_user(d->d_ino, &d32->d_ino); |
756 |
__put_user(d->d_off, &d32->d_off); |
757 |
__put_user(d->d_reclen, &d32->d_reclen); |
758 |
if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen)) |
759 |
return -EFAULT; |
760 |
|
762 |
|
761 |
return 0; |
763 |
static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd, |
762 |
} |
|
|
763 |
|
764 |
static long fat_compat_dir_ioctl(struct file *file, unsigned cmd, |
765 |
unsigned long arg) |
764 |
unsigned long arg) |
766 |
{ |
765 |
{ |
767 |
struct compat_dirent __user *p = compat_ptr(arg); |
766 |
struct inode *inode = filp->f_path.dentry->d_inode; |
768 |
int ret; |
767 |
struct compat_dirent __user *d1 = compat_ptr(arg); |
769 |
mm_segment_t oldfs = get_fs(); |
768 |
int short_only, both; |
770 |
struct dirent d[2]; |
|
|
771 |
|
769 |
|
772 |
switch (cmd) { |
770 |
switch (cmd) { |
773 |
case VFAT_IOCTL_READDIR_BOTH32: |
|
|
774 |
cmd = VFAT_IOCTL_READDIR_BOTH; |
775 |
break; |
776 |
case VFAT_IOCTL_READDIR_SHORT32: |
771 |
case VFAT_IOCTL_READDIR_SHORT32: |
777 |
cmd = VFAT_IOCTL_READDIR_SHORT; |
772 |
short_only = 1; |
|
|
773 |
both = 0; |
774 |
break; |
775 |
case VFAT_IOCTL_READDIR_BOTH32: |
776 |
short_only = 0; |
777 |
both = 1; |
778 |
break; |
778 |
break; |
779 |
default: |
779 |
default: |
780 |
return -ENOIOCTLCMD; |
780 |
return -ENOIOCTLCMD; |
781 |
} |
781 |
} |
782 |
|
782 |
|
783 |
set_fs(KERNEL_DS); |
783 |
if (!access_ok(VERIFY_WRITE, d1, sizeof(struct compat_dirent[2]))) |
784 |
lock_kernel(); |
784 |
return -EFAULT; |
785 |
ret = fat_dir_ioctl(file->f_path.dentry->d_inode, file, |
785 |
/* |
786 |
cmd, (unsigned long) &d); |
786 |
* Yes, we don't need this put_user() absolutely. However old |
787 |
unlock_kernel(); |
787 |
* code didn't return the right value. So, app use this value, |
788 |
set_fs(oldfs); |
788 |
* in order to check whether it is EOF. |
789 |
if (ret >= 0) { |
789 |
*/ |
790 |
ret |= fat_compat_put_dirent32(&d[0], p); |
790 |
if (put_user(0, &d1->d_reclen)) |
791 |
ret |= fat_compat_put_dirent32(&d[1], p + 1); |
791 |
return -EFAULT; |
792 |
} |
792 |
|
793 |
return ret; |
793 |
return fat_ioctl_readdir(inode, filp, d1, fat_compat_ioctl_filldir, |
|
|
794 |
short_only, both); |
794 |
} |
795 |
} |
795 |
#endif /* CONFIG_COMPAT */ |
796 |
#endif /* CONFIG_COMPAT */ |
796 |
|
797 |
|