From b6056ff5f93f5ca26b34b68efa384a25bf1963e9 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 4 Sep 2024 11:17:45 +0800 Subject: [PATCH] fsck.f2fs: fix to detect double '.' or '..' If there are double '.' or '..' dirents in directory, fsck.f2fs won't detect and repaire the issue correctly, fix it. Reviewed-by: Sheng Yong Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fsck/fsck.c | 55 +++++++++++++++++++++++++++++++---------------- fsck/fsck.h | 3 ++- include/f2fs_fs.h | 6 ++++++ 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index e4d4aaef..57fe423a 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1307,10 +1307,10 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid, nid, i_links, child.links); } } - if (child.dots < 2 && + if ((child.dot == 0 || child.dotdot == 0) && !(node_blk->i.i_inline & F2FS_INLINE_DOTS)) { - ASSERT_MSG("ino: 0x%x dots: %u", - nid, child.dots); + ASSERT_MSG("ino: 0x%x dot: %u, dotdot: %u", + nid, child.dot, child.dotdot); if (c.fix_on) { node_blk->i.i_inline |= F2FS_INLINE_DOTS; need_fix = 1; @@ -1862,26 +1862,45 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, int casefolded, /* Becareful. 'dentry.file_type' is not imode. */ if (ftype == F2FS_FT_DIR) { - if ((name[0] == '.' && name_len == 1) || - (name[0] == '.' && name[1] == '.' && - name_len == 2)) { - ret = __chk_dots_dentries(sbi, casefolded, &dentry[i], - child, name, name_len, &filenames[i], - enc_name); - switch (ret) { - case 1: + enum dot_type dot_type = NON_DOT; + + if (name[0] == '.' && name_len == 1) + dot_type = TYPE_DOT; + else if (name[0] == '.' && name[1] == '.' && + name_len == 2) + dot_type = TYPE_DOTDOT; + + if (dot_type != NON_DOT) { + bool need_del = false; + + DBG(3, "i:%u, dot_type:%u, ino:%u, p:%u, pp:%u\n", + i, dot_type, dentry[i].ino, + child->p_ino, child->pp_ino); + + ret = __chk_dots_dentries(sbi, casefolded, + &dentry[i], child, name, name_len, + &filenames[i], enc_name); + if (ret) fixed = 1; - fallthrough; - case 0: - child->dots++; - break; + + if (dot_type == TYPE_DOT) { + if (child->dot == 0) + child->dot++; + else + need_del = true; + } else if (dot_type == TYPE_DOTDOT) { + if (child->dotdot == 0) + child->dotdot++; + else + need_del = true; } - if (child->dots > 2) { - ASSERT_MSG("More than one '.' or '..', should delete the extra one\n"); + if (need_del) { + ASSERT_MSG("More than one '%s', should delete the extra one, i: %u, ino:%u", + dot_type == TYPE_DOT ? "." : "..", + i, dentry[i].ino); nullify_dentry(&dentry[i], i, &filenames[i], &bitmap); - child->dots--; fixed = 1; } diff --git a/fsck/fsck.h b/fsck/fsck.h index a8f187e0..efccfbc8 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -70,7 +70,8 @@ struct child_info { u32 links; u32 files; u32 pgofs; - u8 dots; + u8 dot; + u8 dotdot; u8 dir_level; u32 p_ino; /* parent ino */ char p_name[F2FS_NAME_LEN + 1]; /* parent name */ diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h index d1c656db..ae052f0a 100644 --- a/include/f2fs_fs.h +++ b/include/f2fs_fs.h @@ -1442,6 +1442,12 @@ enum FILE_TYPE { F2FS_FT_LAST_FILE_TYPE = F2FS_FT_XATTR, }; +enum dot_type { + NON_DOT, + TYPE_DOT, + TYPE_DOTDOT +}; + #define LINUX_S_IFMT 00170000 #define LINUX_S_IFREG 0100000 #define LINUX_S_IFDIR 0040000