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, |
