diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2013-05-22 18:37:16 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-06-29 04:57:01 -0400 |
commit | 2c6a2473b800f8eadc94c9a711fee8671dd1a244 (patch) | |
tree | d17702018438f68f990301b8dcf4dc87ae692de8 /fs/fat | |
parent | b8227554c951eb144e975c5e741d33f29c29596f (diff) |
[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>
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/dir.c | 104 |
1 files changed, 54 insertions, 50 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 7a6f02caf286..3963ede84eb0 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
@@ -543,6 +543,7 @@ end_of_dir: | |||
543 | EXPORT_SYMBOL_GPL(fat_search_long); | 543 | EXPORT_SYMBOL_GPL(fat_search_long); |
544 | 544 | ||
545 | struct fat_ioctl_filldir_callback { | 545 | struct fat_ioctl_filldir_callback { |
546 | struct dir_context ctx; | ||
546 | void __user *dirent; | 547 | void __user *dirent; |
547 | int result; | 548 | int result; |
548 | /* for dir ioctl */ | 549 | /* for dir ioctl */ |
@@ -552,8 +553,9 @@ struct fat_ioctl_filldir_callback { | |||
552 | int short_len; | 553 | int short_len; |
553 | }; | 554 | }; |
554 | 555 | ||
555 | static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent, | 556 | static int __fat_readdir(struct inode *inode, struct file *file, |
556 | filldir_t filldir, int short_only, int both) | 557 | struct dir_context *ctx, int short_only, |
558 | struct fat_ioctl_filldir_callback *both) | ||
557 | { | 559 | { |
558 | struct super_block *sb = inode->i_sb; | 560 | struct super_block *sb = inode->i_sb; |
559 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 561 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
@@ -564,27 +566,20 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent, | |||
564 | unsigned char bufname[FAT_MAX_SHORT_SIZE]; | 566 | unsigned char bufname[FAT_MAX_SHORT_SIZE]; |
565 | int isvfat = sbi->options.isvfat; | 567 | int isvfat = sbi->options.isvfat; |
566 | const char *fill_name = NULL; | 568 | const char *fill_name = NULL; |
567 | unsigned long inum; | 569 | int fake_offset = 0; |
568 | unsigned long lpos, dummy, *furrfu = &lpos; | ||
569 | loff_t cpos; | 570 | loff_t cpos; |
570 | int short_len = 0, fill_len = 0; | 571 | int short_len = 0, fill_len = 0; |
571 | int ret = 0; | 572 | int ret = 0; |
572 | 573 | ||
573 | mutex_lock(&sbi->s_lock); | 574 | mutex_lock(&sbi->s_lock); |
574 | 575 | ||
575 | cpos = filp->f_pos; | 576 | cpos = ctx->pos; |
576 | /* Fake . and .. for the root directory. */ | 577 | /* Fake . and .. for the root directory. */ |
577 | if (inode->i_ino == MSDOS_ROOT_INO) { | 578 | if (inode->i_ino == MSDOS_ROOT_INO) { |
578 | while (cpos < 2) { | 579 | if (!dir_emit_dots(file, ctx)) |
579 | if (filldir(dirent, "..", cpos+1, cpos, | 580 | goto out; |
580 | MSDOS_ROOT_INO, DT_DIR) < 0) | 581 | if (ctx->pos == 2) { |
581 | goto out; | 582 | fake_offset = 1; |
582 | cpos++; | ||
583 | filp->f_pos++; | ||
584 | } | ||
585 | if (cpos == 2) { | ||
586 | dummy = 2; | ||
587 | furrfu = &dummy; | ||
588 | cpos = 0; | 583 | cpos = 0; |
589 | } | 584 | } |
590 | } | 585 | } |
@@ -619,7 +614,7 @@ parse_record: | |||
619 | int status = fat_parse_long(inode, &cpos, &bh, &de, | 614 | int status = fat_parse_long(inode, &cpos, &bh, &de, |
620 | &unicode, &nr_slots); | 615 | &unicode, &nr_slots); |
621 | if (status < 0) { | 616 | if (status < 0) { |
622 | filp->f_pos = cpos; | 617 | ctx->pos = cpos; |
623 | ret = status; | 618 | ret = status; |
624 | goto out; | 619 | goto out; |
625 | } else if (status == PARSE_INVALID) | 620 | } else if (status == PARSE_INVALID) |
@@ -639,6 +634,19 @@ parse_record: | |||
639 | /* !both && !short_only, so we don't need shortname. */ | 634 | /* !both && !short_only, so we don't need shortname. */ |
640 | if (!both) | 635 | if (!both) |
641 | goto start_filldir; | 636 | goto start_filldir; |
637 | |||
638 | short_len = fat_parse_short(sb, de, bufname, | ||
639 | sbi->options.dotsOK); | ||
640 | if (short_len == 0) | ||
641 | goto record_end; | ||
642 | /* hack for fat_ioctl_filldir() */ | ||
643 | both->longname = fill_name; | ||
644 | both->long_len = fill_len; | ||
645 | both->shortname = bufname; | ||
646 | both->short_len = short_len; | ||
647 | fill_name = NULL; | ||
648 | fill_len = 0; | ||
649 | goto start_filldir; | ||
642 | } | 650 | } |
643 | } | 651 | } |
644 | 652 | ||
@@ -646,28 +654,21 @@ parse_record: | |||
646 | if (short_len == 0) | 654 | if (short_len == 0) |
647 | goto record_end; | 655 | goto record_end; |
648 | 656 | ||
649 | if (nr_slots) { | 657 | fill_name = bufname; |
650 | /* hack for fat_ioctl_filldir() */ | 658 | fill_len = short_len; |
651 | struct fat_ioctl_filldir_callback *p = dirent; | ||
652 | |||
653 | p->longname = fill_name; | ||
654 | p->long_len = fill_len; | ||
655 | p->shortname = bufname; | ||
656 | p->short_len = short_len; | ||
657 | fill_name = NULL; | ||
658 | fill_len = 0; | ||
659 | } else { | ||
660 | fill_name = bufname; | ||
661 | fill_len = short_len; | ||
662 | } | ||
663 | 659 | ||
664 | start_filldir: | 660 | start_filldir: |
665 | lpos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry); | 661 | if (!fake_offset) |
666 | if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) | 662 | ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry); |
667 | inum = inode->i_ino; | 663 | |
668 | else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { | 664 | if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) { |
669 | inum = parent_ino(filp->f_path.dentry); | 665 | if (!dir_emit_dot(file, ctx)) |
666 | goto fill_failed; | ||
667 | } else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { | ||
668 | if (!dir_emit_dotdot(file, ctx)) | ||
669 | goto fill_failed; | ||
670 | } else { | 670 | } else { |
671 | unsigned long inum; | ||
671 | loff_t i_pos = fat_make_i_pos(sb, bh, de); | 672 | loff_t i_pos = fat_make_i_pos(sb, bh, de); |
672 | struct inode *tmp = fat_iget(sb, i_pos); | 673 | struct inode *tmp = fat_iget(sb, i_pos); |
673 | if (tmp) { | 674 | if (tmp) { |
@@ -675,18 +676,17 @@ start_filldir: | |||
675 | iput(tmp); | 676 | iput(tmp); |
676 | } else | 677 | } else |
677 | inum = iunique(sb, MSDOS_ROOT_INO); | 678 | inum = iunique(sb, MSDOS_ROOT_INO); |
679 | if (!dir_emit(ctx, fill_name, fill_len, inum, | ||
680 | (de->attr & ATTR_DIR) ? DT_DIR : DT_REG)) | ||
681 | goto fill_failed; | ||
678 | } | 682 | } |
679 | 683 | ||
680 | if (filldir(dirent, fill_name, fill_len, *furrfu, inum, | ||
681 | (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0) | ||
682 | goto fill_failed; | ||
683 | |||
684 | record_end: | 684 | record_end: |
685 | furrfu = &lpos; | 685 | fake_offset = 0; |
686 | filp->f_pos = cpos; | 686 | ctx->pos = cpos; |
687 | goto get_new; | 687 | goto get_new; |
688 | end_of_dir: | 688 | end_of_dir: |
689 | filp->f_pos = cpos; | 689 | ctx->pos = cpos; |
690 | fill_failed: | 690 | fill_failed: |
691 | brelse(bh); | 691 | brelse(bh); |
692 | if (unicode) | 692 | if (unicode) |
@@ -696,10 +696,9 @@ out: | |||
696 | return ret; | 696 | return ret; |
697 | } | 697 | } |
698 | 698 | ||
699 | static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir) | 699 | static int fat_readdir(struct file *file, struct dir_context *ctx) |
700 | { | 700 | { |
701 | struct inode *inode = file_inode(filp); | 701 | return __fat_readdir(file_inode(file), file, ctx, 0, NULL); |
702 | return __fat_readdir(inode, filp, dirent, filldir, 0, 0); | ||
703 | } | 702 | } |
704 | 703 | ||
705 | #define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \ | 704 | #define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \ |
@@ -755,20 +754,25 @@ efault: \ | |||
755 | 754 | ||
756 | FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, __fat_dirent) | 755 | FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, __fat_dirent) |
757 | 756 | ||
758 | static int fat_ioctl_readdir(struct inode *inode, struct file *filp, | 757 | static int fat_ioctl_readdir(struct inode *inode, struct file *file, |
759 | void __user *dirent, filldir_t filldir, | 758 | void __user *dirent, filldir_t filldir, |
760 | int short_only, int both) | 759 | int short_only, int both) |
761 | { | 760 | { |
762 | struct fat_ioctl_filldir_callback buf; | 761 | struct fat_ioctl_filldir_callback buf = { |
762 | .ctx.actor = filldir, | ||
763 | .dirent = dirent | ||
764 | }; | ||
763 | int ret; | 765 | int ret; |
764 | 766 | ||
765 | buf.dirent = dirent; | 767 | buf.dirent = dirent; |
766 | buf.result = 0; | 768 | buf.result = 0; |
767 | mutex_lock(&inode->i_mutex); | 769 | mutex_lock(&inode->i_mutex); |
770 | buf.ctx.pos = file->f_pos; | ||
768 | ret = -ENOENT; | 771 | ret = -ENOENT; |
769 | if (!IS_DEADDIR(inode)) { | 772 | if (!IS_DEADDIR(inode)) { |
770 | ret = __fat_readdir(inode, filp, &buf, filldir, | 773 | ret = __fat_readdir(inode, file, &buf.ctx, |
771 | short_only, both); | 774 | short_only, both ? &buf : NULL); |
775 | file->f_pos = buf.ctx.pos; | ||
772 | } | 776 | } |
773 | mutex_unlock(&inode->i_mutex); | 777 | mutex_unlock(&inode->i_mutex); |
774 | if (ret >= 0) | 778 | if (ret >= 0) |
@@ -854,7 +858,7 @@ static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd, | |||
854 | const struct file_operations fat_dir_operations = { | 858 | const struct file_operations fat_dir_operations = { |
855 | .llseek = generic_file_llseek, | 859 | .llseek = generic_file_llseek, |
856 | .read = generic_read_dir, | 860 | .read = generic_read_dir, |
857 | .readdir = fat_readdir, | 861 | .iterate = fat_readdir, |
858 | .unlocked_ioctl = fat_dir_ioctl, | 862 | .unlocked_ioctl = fat_dir_ioctl, |
859 | #ifdef CONFIG_COMPAT | 863 | #ifdef CONFIG_COMPAT |
860 | .compat_ioctl = fat_compat_dir_ioctl, | 864 | .compat_ioctl = fat_compat_dir_ioctl, |