If there are double '.' or '..' dirents in directory, fsck.f2fs won't
detect and repaire the issue correctly, fix it.

Reviewed-by: Sheng Yong <shengy...@oppo.com>
Signed-off-by: Chao Yu <c...@kernel.org>
---
 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 a18bee9..54ddc11 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -1307,10 +1307,10 @@ skip_blkcnt_fix:
                                                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 a8f187e..efccfbc 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 15a1c82..0b6777a 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -1429,6 +1429,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
-- 
2.40.1



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to