aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ocfs2/dir.c96
-rw-r--r--fs/ocfs2/dir.h2
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
663struct ocfs2_empty_dir_priv {
664 unsigned seen_dot;
665 unsigned seen_dot_dot;
666 unsigned seen_other;
667};
668static 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 */
666int ocfs2_empty_dir(struct inode *inode) 696int 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
726int ocfs2_fill_new_dir(struct ocfs2_super *osb, 720int 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,
54int ocfs2_check_dir_for_entry(struct inode *dir, 54int ocfs2_check_dir_for_entry(struct inode *dir,
55 const char *name, 55 const char *name,
56 int namelen); 56 int namelen);
57int ocfs2_empty_dir(struct inode *inode); /* FIXME: to namei.c */ 57int ocfs2_empty_dir(struct inode *inode);
58int ocfs2_find_files_on_disk(const char *name, 58int ocfs2_find_files_on_disk(const char *name,
59 int namelen, 59 int namelen,
60 u64 *blkno, 60 u64 *blkno,