Skip to content

Commit

Permalink
fsck.f2fs: fix to detect double '.' or '..'
Browse files Browse the repository at this point in the history
If there are double '.' or '..' dirents in directory, fsck.f2fs won't
detect and repaire the issue correctly, fix it.

Reviewed-by: Sheng Yong <[email protected]>
Signed-off-by: Chao Yu <[email protected]>
Signed-off-by: Jaegeuk Kim <[email protected]>
  • Loading branch information
chaseyu authored and Jaegeuk Kim committed Sep 6, 2024
1 parent d178be0 commit b6056ff
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 19 deletions.
55 changes: 37 additions & 18 deletions fsck/fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion fsck/fsck.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
6 changes: 6 additions & 0 deletions include/f2fs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit b6056ff

Please sign in to comment.