diff options
-rw-r--r-- | fs/ocfs2/dir.c | 96 | ||||
-rw-r--r-- | fs/ocfs2/dir.h | 2 |
2 files changed, 46 insertions, 52 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index a75c340fc689..4bb54406354b 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -660,67 +660,61 @@ bail: | |||
660 | return ret; | 660 | return ret; |
661 | } | 661 | } |
662 | 662 | ||
663 | struct ocfs2_empty_dir_priv { | ||
664 | unsigned seen_dot; | ||
665 | unsigned seen_dot_dot; | ||
666 | unsigned seen_other; | ||
667 | }; | ||
668 | static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len, | ||
669 | loff_t pos, u64 ino, unsigned type) | ||
670 | { | ||
671 | struct ocfs2_empty_dir_priv *p = priv; | ||
672 | |||
673 | /* | ||
674 | * Check the positions of "." and ".." records to be sure | ||
675 | * they're in the correct place. | ||
676 | */ | ||
677 | if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) { | ||
678 | p->seen_dot = 1; | ||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | if (name_len == 2 && !strncmp("..", name, 2) && | ||
683 | pos == OCFS2_DIR_REC_LEN(1)) { | ||
684 | p->seen_dot_dot = 1; | ||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | p->seen_other = 1; | ||
689 | return 1; | ||
690 | } | ||
663 | /* | 691 | /* |
664 | * routine to check that the specified directory is empty (for rmdir) | 692 | * routine to check that the specified directory is empty (for rmdir) |
693 | * | ||
694 | * Returns 1 if dir is empty, zero otherwise. | ||
665 | */ | 695 | */ |
666 | int ocfs2_empty_dir(struct inode *inode) | 696 | int ocfs2_empty_dir(struct inode *inode) |
667 | { | 697 | { |
668 | unsigned long offset; | 698 | int ret; |
669 | struct buffer_head * bh; | 699 | loff_t start = 0; |
670 | struct ocfs2_dir_entry * de, * de1; | 700 | struct ocfs2_empty_dir_priv priv; |
671 | struct super_block * sb; | ||
672 | int err; | ||
673 | 701 | ||
674 | sb = inode->i_sb; | 702 | memset(&priv, 0, sizeof(priv)); |
675 | if ((i_size_read(inode) < | ||
676 | (OCFS2_DIR_REC_LEN(1) + OCFS2_DIR_REC_LEN(2))) || | ||
677 | !(bh = ocfs2_bread(inode, 0, &err, 0))) { | ||
678 | mlog(ML_ERROR, "bad directory (dir #%llu) - no data block\n", | ||
679 | (unsigned long long)OCFS2_I(inode)->ip_blkno); | ||
680 | return 1; | ||
681 | } | ||
682 | 703 | ||
683 | de = (struct ocfs2_dir_entry *) bh->b_data; | 704 | ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir); |
684 | de1 = (struct ocfs2_dir_entry *) | 705 | if (ret) |
685 | ((char *)de + le16_to_cpu(de->rec_len)); | 706 | mlog_errno(ret); |
686 | if ((le64_to_cpu(de->inode) != OCFS2_I(inode)->ip_blkno) || | 707 | |
687 | !le64_to_cpu(de1->inode) || | 708 | if (!priv.seen_dot || !priv.seen_dot_dot) { |
688 | strcmp(".", de->name) || | 709 | mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n", |
689 | strcmp("..", de1->name)) { | ||
690 | mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n", | ||
691 | (unsigned long long)OCFS2_I(inode)->ip_blkno); | 710 | (unsigned long long)OCFS2_I(inode)->ip_blkno); |
692 | brelse(bh); | 711 | /* |
712 | * XXX: Is it really safe to allow an unlink to continue? | ||
713 | */ | ||
693 | return 1; | 714 | return 1; |
694 | } | 715 | } |
695 | offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len); | 716 | |
696 | de = (struct ocfs2_dir_entry *)((char *)de1 + le16_to_cpu(de1->rec_len)); | 717 | return !priv.seen_other; |
697 | while (offset < i_size_read(inode) ) { | ||
698 | if (!bh || (void *)de >= (void *)(bh->b_data + sb->s_blocksize)) { | ||
699 | brelse(bh); | ||
700 | bh = ocfs2_bread(inode, | ||
701 | offset >> sb->s_blocksize_bits, &err, 0); | ||
702 | if (!bh) { | ||
703 | mlog(ML_ERROR, "dir %llu has a hole at %lu\n", | ||
704 | (unsigned long long)OCFS2_I(inode)->ip_blkno, offset); | ||
705 | offset += sb->s_blocksize; | ||
706 | continue; | ||
707 | } | ||
708 | de = (struct ocfs2_dir_entry *) bh->b_data; | ||
709 | } | ||
710 | if (!ocfs2_check_dir_entry(inode, de, bh, offset)) { | ||
711 | brelse(bh); | ||
712 | return 1; | ||
713 | } | ||
714 | if (le64_to_cpu(de->inode)) { | ||
715 | brelse(bh); | ||
716 | return 0; | ||
717 | } | ||
718 | offset += le16_to_cpu(de->rec_len); | ||
719 | de = (struct ocfs2_dir_entry *) | ||
720 | ((char *)de + le16_to_cpu(de->rec_len)); | ||
721 | } | ||
722 | brelse(bh); | ||
723 | return 1; | ||
724 | } | 718 | } |
725 | 719 | ||
726 | int ocfs2_fill_new_dir(struct ocfs2_super *osb, | 720 | int ocfs2_fill_new_dir(struct ocfs2_super *osb, |
diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index 075d0e9fd459..3e65f91b034d 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h | |||
@@ -54,7 +54,7 @@ static inline int ocfs2_add_entry(handle_t *handle, | |||
54 | int ocfs2_check_dir_for_entry(struct inode *dir, | 54 | int ocfs2_check_dir_for_entry(struct inode *dir, |
55 | const char *name, | 55 | const char *name, |
56 | int namelen); | 56 | int namelen); |
57 | int ocfs2_empty_dir(struct inode *inode); /* FIXME: to namei.c */ | 57 | int ocfs2_empty_dir(struct inode *inode); |
58 | int ocfs2_find_files_on_disk(const char *name, | 58 | int ocfs2_find_files_on_disk(const char *name, |
59 | int namelen, | 59 | int namelen, |
60 | u64 *blkno, | 60 | u64 *blkno, |