aboutsummaryrefslogtreecommitdiff
path: root/ubifs-utils
diff options
context:
space:
mode:
authorZhihao Cheng <chengzhihao1@huawei.com>2024-11-11 17:08:01 +0800
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2024-11-11 10:32:46 +0100
commit0d1cc10378c2a8f800ff78d79c93b39485d6ca14 (patch)
treed4a840af01f202d6a515e06de60a4dda7095763f /ubifs-utils
parent7e9a7ceaa9d3851963f92f99ce012f7cd99e742b (diff)
fsck.ubifs: Traverse TNC and construct files
This is the 6/18 step of fsck. Traverse TNC and construct files. There could be following steps and possible errors: Step 1. Traverse TNC, check whether the leaf node is valid, remove invalid nodes, construct file for valid node and insert file into file tree. a. corrupted node searched from TNC: remove corresponding TNC branch for danger mode and normal mode with 'yes' answer, other modes will exit. b. corrupted index node read from TNC: danger mode with rebuild_fs and normal mode with 'yes' answer will turn to rebuild filesystem, other modes will exit. Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'ubifs-utils')
-rw-r--r--ubifs-utils/Makemodule.am3
-rw-r--r--ubifs-utils/fsck.ubifs/check_files.c201
-rw-r--r--ubifs-utils/fsck.ubifs/extract_files.c216
-rw-r--r--ubifs-utils/fsck.ubifs/fsck.ubifs.c15
-rw-r--r--ubifs-utils/fsck.ubifs/fsck.ubifs.h6
-rw-r--r--ubifs-utils/fsck.ubifs/problem.c6
-rw-r--r--ubifs-utils/libubifs/debug.c12
-rw-r--r--ubifs-utils/libubifs/debug.h1
8 files changed, 395 insertions, 65 deletions
diff --git a/ubifs-utils/Makemodule.am b/ubifs-utils/Makemodule.am
index a822639..f88723a 100644
--- a/ubifs-utils/Makemodule.am
+++ b/ubifs-utils/Makemodule.am
@@ -84,7 +84,8 @@ fsck_ubifs_SOURCES = \
ubifs-utils/fsck.ubifs/problem.c \
ubifs-utils/fsck.ubifs/load_fs.c \
ubifs-utils/fsck.ubifs/extract_files.c \
- ubifs-utils/fsck.ubifs/rebuild_fs.c
+ ubifs-utils/fsck.ubifs/rebuild_fs.c \
+ ubifs-utils/fsck.ubifs/check_files.c
fsck_ubifs_LDADD = libmtd.a libubi.a $(ZLIB_LIBS) $(LZO_LIBS) $(ZSTD_LIBS) $(UUID_LIBS) $(LIBSELINUX_LIBS) $(OPENSSL_LIBS) \
$(DUMP_STACK_LD) -lm -lpthread
diff --git a/ubifs-utils/fsck.ubifs/check_files.c b/ubifs-utils/fsck.ubifs/check_files.c
new file mode 100644
index 0000000..982c05b
--- /dev/null
+++ b/ubifs-utils/fsck.ubifs/check_files.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024, Huawei Technologies Co, Ltd.
+ *
+ * Authors: Zhihao Cheng <chengzhihao1@huawei.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bitops.h"
+#include "kmem.h"
+#include "ubifs.h"
+#include "defs.h"
+#include "debug.h"
+#include "key.h"
+#include "fsck.ubifs.h"
+
+struct invalid_node {
+ union ubifs_key key;
+ int lnum;
+ int offs;
+ struct list_head list;
+};
+
+struct iteration_info {
+ struct list_head invalid_nodes;
+};
+
+static int add_invalid_node(struct ubifs_info *c, union ubifs_key *key,
+ int lnum, int offs, struct iteration_info *iter)
+{
+ struct invalid_node *in;
+
+ in = kmalloc(sizeof(struct invalid_node), GFP_KERNEL);
+ if (!in) {
+ log_err(c, errno, "can not allocate invalid node");
+ return -ENOMEM;
+ }
+
+ key_copy(c, key, &in->key);
+ in->lnum = lnum;
+ in->offs = offs;
+ list_add(&in->list, &iter->invalid_nodes);
+
+ return 0;
+}
+
+static int construct_file(struct ubifs_info *c, union ubifs_key *key,
+ int lnum, int offs, void *node,
+ struct iteration_info *iter)
+{
+ ino_t inum = 0;
+ struct rb_root *tree = &FSCK(c)->scanned_files;
+ struct scanned_node *sn = NULL;
+ struct ubifs_ch *ch = (struct ubifs_ch *)node;
+
+ switch (ch->node_type) {
+ case UBIFS_INO_NODE:
+ {
+ struct scanned_ino_node ino_node;
+
+ if (!parse_ino_node(c, lnum, offs, node, key, &ino_node)) {
+ if (fix_problem(c, INVALID_INO_NODE, NULL))
+ return add_invalid_node(c, key, lnum, offs, iter);
+ }
+ inum = key_inum(c, key);
+ sn = (struct scanned_node *)&ino_node;
+ break;
+ }
+ case UBIFS_DENT_NODE:
+ case UBIFS_XENT_NODE:
+ {
+ struct scanned_dent_node dent_node;
+
+ if (!parse_dent_node(c, lnum, offs, node, key, &dent_node)) {
+ if (fix_problem(c, INVALID_DENT_NODE, NULL))
+ return add_invalid_node(c, key, lnum, offs, iter);
+ }
+ inum = dent_node.inum;
+ sn = (struct scanned_node *)&dent_node;
+ break;
+ }
+ case UBIFS_DATA_NODE:
+ {
+ struct scanned_data_node data_node;
+
+ if (!parse_data_node(c, lnum, offs, node, key, &data_node)) {
+ if (fix_problem(c, INVALID_DATA_NODE, NULL))
+ return add_invalid_node(c, key, lnum, offs, iter);
+ }
+ inum = key_inum(c, key);
+ sn = (struct scanned_node *)&data_node;
+ break;
+ }
+ default:
+ ubifs_assert(c, 0);
+ }
+
+ dbg_fsck("construct file(%lu) for %s node, TNC location %d:%d, in %s",
+ inum, ubifs_get_key_name(key_type(c, key)), sn->lnum, sn->offs,
+ c->dev_name);
+ return insert_or_update_file(c, tree, sn, key_type(c, key), inum);
+}
+
+static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+ void *priv)
+{
+ void *node;
+ struct iteration_info *iter = (struct iteration_info *)priv;
+ union ubifs_key *key = &zbr->key;
+ int lnum = zbr->lnum, offs = zbr->offs, len = zbr->len, err = 0;
+
+ if (len < UBIFS_CH_SZ) {
+ ubifs_err(c, "bad leaf length %d (LEB %d:%d)",
+ len, lnum, offs);
+ set_failure_reason_callback(c, FR_TNC_CORRUPTED);
+ return -EINVAL;
+ }
+ if (key_type(c, key) != UBIFS_INO_KEY &&
+ key_type(c, key) != UBIFS_DATA_KEY &&
+ key_type(c, key) != UBIFS_DENT_KEY &&
+ key_type(c, key) != UBIFS_XENT_KEY) {
+ ubifs_err(c, "bad key type %d (LEB %d:%d)",
+ key_type(c, key), lnum, offs);
+ set_failure_reason_callback(c, FR_TNC_CORRUPTED);
+ return -EINVAL;
+ }
+
+ node = kmalloc(len, GFP_NOFS);
+ if (!node)
+ return -ENOMEM;
+
+ err = ubifs_tnc_read_node(c, zbr, node);
+ if (err) {
+ if (test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED)) {
+ if (fix_problem(c, TNC_DATA_CORRUPTED, NULL))
+ err = add_invalid_node(c, key, lnum, offs, iter);
+ }
+ goto out;
+ }
+
+ err = construct_file(c, key, lnum, offs, node, iter);
+
+out:
+ kfree(node);
+ return err;
+}
+
+static int remove_invalid_nodes(struct ubifs_info *c,
+ struct list_head *invalid_nodes, int error)
+{
+ int ret = 0;;
+ struct invalid_node *in;
+
+ while (!list_empty(invalid_nodes)) {
+ in = list_entry(invalid_nodes->next, struct invalid_node, list);
+
+ if (!error) {
+ error = ubifs_tnc_remove_node(c, &in->key, in->lnum, in->offs);
+ if (error) {
+ /* TNC traversing is finished, any TNC path is accessible */
+ ubifs_assert(c, !get_failure_reason_callback(c));
+ ret = error;
+ }
+ }
+
+ list_del(&in->list);
+ kfree(in);
+ }
+
+ return ret;
+}
+
+/**
+ * traverse_tnc_and_construct_files - traverse TNC and construct all files.
+ * @c: UBIFS file-system description object
+ *
+ * This function checks all index nodes and non-index nodes by traversing TNC,
+ * then construct file according to scanned non-index nodes and insert file
+ * into file tree. Returns zero in case of success, a negative error code in
+ * case of failure.
+ */
+int traverse_tnc_and_construct_files(struct ubifs_info *c)
+{
+ int err, ret;
+ struct iteration_info iter;
+
+ FSCK(c)->scanned_files = RB_ROOT;
+ INIT_LIST_HEAD(&iter.invalid_nodes);
+
+ err = dbg_walk_index(c, check_leaf, NULL, &iter);
+
+ ret = remove_invalid_nodes(c, &iter.invalid_nodes, err);
+ if (!err)
+ err = ret;
+
+ if (err)
+ destroy_file_tree(c, &FSCK(c)->scanned_files);
+ return err;
+}
diff --git a/ubifs-utils/fsck.ubifs/extract_files.c b/ubifs-utils/fsck.ubifs/extract_files.c
index c3ab2b7..e9c71a3 100644
--- a/ubifs-utils/fsck.ubifs/extract_files.c
+++ b/ubifs-utils/fsck.ubifs/extract_files.c
@@ -74,15 +74,24 @@ bool parse_ino_node(struct ubifs_info *c, int lnum, int offs, void *node,
ino_t inum = key_inum(c, key);
if (!inum || inum > INUM_WATERMARK) {
- dbg_fsck("bad inode node(bad inum %lu) at %d:%d, in %s",
- inum, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node(bad inum %lu) at %d:%d, in %s",
+ inum, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node(bad inum %lu) at %d:%d",
+ inum, lnum, offs);
goto out;
}
if (ch->node_type != key_type(c, key)) {
- dbg_fsck("bad inode node %lu(inconsistent node type %d vs key_type %d) at %d:%d, in %s",
- inum, ch->node_type, key_type(c, key),
- lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(inconsistent node type %d vs key_type %d) at %d:%d, in %s",
+ inum, ch->node_type, key_type(c, key),
+ lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(inconsistent node type %d vs key_type %d) at %d:%d",
+ inum, ch->node_type, key_type(c, key),
+ lnum, offs);
goto out;
}
@@ -101,60 +110,101 @@ bool parse_ino_node(struct ubifs_info *c, int lnum, int offs, void *node,
ino_node->size = le64_to_cpu(ino->size);
if (inum == UBIFS_ROOT_INO && !S_ISDIR(ino_node->mode)) {
- dbg_fsck("bad inode node %lu(root inode is not dir, tyoe %u) at %d:%d, in %s",
- inum, ino_node->mode & S_IFMT, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(root inode is not dir, tyoe %u) at %d:%d, in %s",
+ inum, ino_node->mode & S_IFMT, lnum, offs,
+ c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(root inode is not dir, tyoe %u) at %d:%d",
+ inum, ino_node->mode & S_IFMT, lnum, offs);
goto out;
}
if (ino_node->size > c->max_inode_sz) {
- dbg_fsck("bad inode node %lu(size %llu is too large) at %d:%d, in %s",
- inum, ino_node->size, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(size %llu is too large) at %d:%d, in %s",
+ inum, ino_node->size, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(size %llu is too large) at %d:%d",
+ inum, ino_node->size, lnum, offs);
goto out;
}
if (le16_to_cpu(ino->compr_type) >= UBIFS_COMPR_TYPES_CNT) {
- dbg_fsck("bad inode node %lu(unknown compression type %d) at %d:%d, in %s",
- inum, le16_to_cpu(ino->compr_type), lnum, offs,
- c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(unknown compression type %d) at %d:%d, in %s",
+ inum, le16_to_cpu(ino->compr_type), lnum, offs,
+ c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(unknown compression type %d) at %d:%d",
+ inum, le16_to_cpu(ino->compr_type), lnum, offs);
goto out;
}
if (ino_node->xnms + ino_node->xcnt > XATTR_LIST_MAX) {
- dbg_fsck("bad inode node %lu(too big xnames %u xcount %u) at %d:%d, in %s",
- inum, ino_node->xnms, ino_node->xcnt,
- lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(too big xnames %u xcount %u) at %d:%d, in %s",
+ inum, ino_node->xnms, ino_node->xcnt,
+ lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(too big xnames %u xcount %u) at %d:%d",
+ inum, ino_node->xnms, ino_node->xcnt,
+ lnum, offs);
goto out;
}
if (data_len < 0 || data_len > UBIFS_MAX_INO_DATA) {
- dbg_fsck("bad inode node %lu(invalid data len %d) at %d:%d, in %s",
- inum, data_len, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(invalid data len %d) at %d:%d, in %s",
+ inum, data_len, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(invalid data len %d) at %d:%d",
+ inum, data_len, lnum, offs);
goto out;
}
if (UBIFS_INO_NODE_SZ + data_len != node_len) {
- dbg_fsck("bad inode node %lu(inconsistent data len %d vs node len %d) at %d:%d, in %s",
- inum, data_len, node_len, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(inconsistent data len %d vs node len %d) at %d:%d, in %s",
+ inum, data_len, node_len, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(inconsistent data len %d vs node len %d) at %d:%d",
+ inum, data_len, node_len, lnum, offs);
goto out;
}
if (ino_node->is_xattr) {
if (!S_ISREG(ino_node->mode)) {
- dbg_fsck("bad inode node %lu(bad type %u for xattr) at %d:%d, in %s",
- inum, ino_node->mode & S_IFMT,
- lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(bad type %u for xattr) at %d:%d, in %s",
+ inum, ino_node->mode & S_IFMT,
+ lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(bad type %u for xattr) at %d:%d",
+ inum, ino_node->mode & S_IFMT,
+ lnum, offs);
goto out;
}
if (data_len != ino_node->size) {
- dbg_fsck("bad inode node %lu(inconsistent data_len %d vs size %llu for xattr) at %d:%d, in %s",
- inum, data_len, ino_node->size,
- lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(inconsistent data_len %d vs size %llu for xattr) at %d:%d, in %s",
+ inum, data_len, ino_node->size,
+ lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(inconsistent data_len %d vs size %llu for xattr) at %d:%d",
+ inum, data_len, ino_node->size,
+ lnum, offs);
goto out;
}
if (ino_node->xcnt || ino_node->xsz || ino_node->xnms) {
- dbg_fsck("bad inode node %lu(non zero xattr count %u xattr size %u xattr names %u for xattr) at %d:%d, in %s",
- inum, ino_node->xcnt, ino_node->xsz,
- ino_node->xnms, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(non zero xattr count %u xattr size %u xattr names %u for xattr) at %d:%d, in %s",
+ inum, ino_node->xcnt, ino_node->xsz,
+ ino_node->xnms, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(non zero xattr count %u xattr size %u xattr names %u for xattr) at %d:%d",
+ inum, ino_node->xcnt, ino_node->xsz,
+ ino_node->xnms, lnum, offs);
goto out;
}
}
@@ -162,15 +212,23 @@ bool parse_ino_node(struct ubifs_info *c, int lnum, int offs, void *node,
switch (ino_node->mode & S_IFMT) {
case S_IFREG:
if (!ino_node->is_xattr && data_len != 0) {
- dbg_fsck("bad inode node %lu(bad data len %d for reg file) at %d:%d, in %s",
- inum, data_len, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(bad data len %d for reg file) at %d:%d, in %s",
+ inum, data_len, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(bad data len %d for reg file) at %d:%d",
+ inum, data_len, lnum, offs);
goto out;
}
break;
case S_IFDIR:
if (data_len != 0) {
- dbg_fsck("bad inode node %lu(bad data len %d for dir file) at %d:%d, in %s",
- inum, data_len, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(bad data len %d for dir file) at %d:%d, in %s",
+ inum, data_len, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(bad data len %d for dir file) at %d:%d",
+ inum, data_len, lnum, offs);
goto out;
}
break;
@@ -187,8 +245,12 @@ bool parse_ino_node(struct ubifs_info *c, int lnum, int offs, void *node,
* Just drop the inode node when above class of
* exceptions are found.
*/
- dbg_fsck("bad symlink inode node %lu(bad data len %d) at %d:%d, in %s",
- inum, data_len, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad symlink inode node %lu(bad data len %d) at %d:%d, in %s",
+ inum, data_len, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad symlink inode node %lu(bad data len %d) at %d:%d",
+ inum, data_len, lnum, offs);
goto out;
}
break;
@@ -200,9 +262,14 @@ bool parse_ino_node(struct ubifs_info *c, int lnum, int offs, void *node,
int sz_new = sizeof(dev->new), sz_huge = sizeof(dev->huge);
if (data_len != sz_new && data_len != sz_huge) {
- dbg_fsck("bad inode node %lu(bad data len %d for char/block file, expect %d or %d) at %d:%d, in %s",
- inum, data_len, sz_new, sz_huge, lnum,
- offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(bad data len %d for char/block file, expect %d or %d) at %d:%d, in %s",
+ inum, data_len, sz_new, sz_huge, lnum,
+ offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(bad data len %d for char/block file, expect %d or %d) at %d:%d",
+ inum, data_len, sz_new, sz_huge, lnum,
+ offs);
goto out;
}
break;
@@ -211,22 +278,35 @@ bool parse_ino_node(struct ubifs_info *c, int lnum, int offs, void *node,
fallthrough;
case S_IFIFO:
if (data_len != 0) {
- dbg_fsck("bad inode node %lu(bad data len %d for fifo/sock file) at %d:%d, in %s",
- inum, data_len, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(bad data len %d for fifo/sock file) at %d:%d, in %s",
+ inum, data_len, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(bad data len %d for fifo/sock file) at %d:%d",
+ inum, data_len, lnum, offs);
goto out;
}
break;
default:
/* invalid file type. */
- dbg_fsck("bad inode node %lu(unknown type %u) at %d:%d, in %s",
- inum, ino_node->mode & S_IFMT, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(unknown type %u) at %d:%d, in %s",
+ inum, ino_node->mode & S_IFMT, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(unknown type %u) at %d:%d",
+ inum, ino_node->mode & S_IFMT, lnum, offs);
goto out;
}
if (ino_node->is_encrypted && !inode_can_be_encrypted(c, ino_node)) {
- dbg_fsck("bad inode node %lu(encrypted but cannot be encrypted, type %u, is_xattr %d, fs_encrypted %d) at %d:%d, in %s",
- inum, ino_node->mode & S_IFMT, ino_node->is_xattr,
- c->encrypted, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad inode node %lu(encrypted but cannot be encrypted, type %u, is_xattr %d, fs_encrypted %d) at %d:%d, in %s",
+ inum, ino_node->mode & S_IFMT, ino_node->is_xattr,
+ c->encrypted, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad inode node %lu(encrypted but cannot be encrypted, type %u, is_xattr %d, fs_encrypted %d) at %d:%d",
+ inum, ino_node->mode & S_IFMT, ino_node->is_xattr,
+ c->encrypted, lnum, offs);
goto out;
}
@@ -272,10 +352,16 @@ bool parse_dent_node(struct ubifs_info *c, int lnum, int offs, void *node,
(key_type == UBIFS_XENT_KEY &&
strnlen((const char *)dent->name, nlen) != nlen) ||
inum > INUM_WATERMARK || key_type != ch->node_type) {
- dbg_fsck("bad %s node(len %d nlen %d type %d inum %lu key_type %d node_type %d) at %d:%d, in %s",
- ch->node_type == UBIFS_XENT_NODE ? "xattr entry" : "directory entry",
- node_len, nlen, dent->type, inum, key_type,
- ch->node_type, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad %s node(len %d nlen %d type %d inum %lu key_type %d node_type %d) at %d:%d, in %s",
+ ch->node_type == UBIFS_XENT_NODE ? "xattr entry" : "directory entry",
+ node_len, nlen, dent->type, inum, key_type,
+ ch->node_type, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad %s node(len %d nlen %d type %d inum %lu key_type %d node_type %d) at %d:%d",
+ ch->node_type == UBIFS_XENT_NODE ? "xattr entry" : "directory entry",
+ node_len, nlen, dent->type, inum, key_type,
+ ch->node_type, lnum, offs);
goto out;
}
@@ -318,15 +404,23 @@ bool parse_data_node(struct ubifs_info *c, int lnum, int offs, void *node,
ino_t inum = key_inum(c, key);
if (ch->node_type != key_type(c, key)) {
- dbg_fsck("bad data node(inconsistent node type %d vs key_type %d) at %d:%d, in %s",
- ch->node_type, key_type(c, key),
- lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad data node(inconsistent node type %d vs key_type %d) at %d:%d, in %s",
+ ch->node_type, key_type(c, key),
+ lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad data node(inconsistent node type %d vs key_type %d) at %d:%d",
+ ch->node_type, key_type(c, key), lnum, offs);
goto out;
}
if (!inum || inum > INUM_WATERMARK) {
- dbg_fsck("bad data node(bad inum %lu) at %d:%d, in %s",
- inum, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad data node(bad inum %lu) at %d:%d, in %s",
+ inum, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad data node(bad inum %lu) at %d:%d",
+ inum, lnum, offs);
goto out;
}
@@ -336,14 +430,22 @@ bool parse_data_node(struct ubifs_info *c, int lnum, int offs, void *node,
data_node->size = le32_to_cpu(dn->size);
if (!data_node->size || data_node->size > UBIFS_BLOCK_SIZE) {
- dbg_fsck("bad data node(invalid size %u) at %d:%d, in %s",
- data_node->size, lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad data node(invalid size %u) at %d:%d, in %s",
+ data_node->size, lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad data node(invalid size %u) at %d:%d",
+ data_node->size, lnum, offs);
goto out;
}
if (le16_to_cpu(dn->compr_type) >= UBIFS_COMPR_TYPES_CNT) {
- dbg_fsck("bad data node(invalid compression type %d) at %d:%d, in %s",
- le16_to_cpu(dn->compr_type), lnum, offs, c->dev_name);
+ if (FSCK(c)->mode == REBUILD_MODE)
+ dbg_fsck("bad data node(invalid compression type %d) at %d:%d, in %s",
+ le16_to_cpu(dn->compr_type), lnum, offs, c->dev_name);
+ else
+ log_out(c, "bad data node(invalid compression type %d) at %d:%d",
+ le16_to_cpu(dn->compr_type), lnum, offs);
goto out;
}
diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.c b/ubifs-utils/fsck.ubifs/fsck.ubifs.c
index 59080d8..96091b4 100644
--- a/ubifs-utils/fsck.ubifs/fsck.ubifs.c
+++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.c
@@ -434,7 +434,17 @@ void handle_error(const struct ubifs_info *c, int reason_set)
*/
static int do_fsck(void)
{
- return 0;
+ int err;
+
+ log_out(c, "Traverse TNC and construct files");
+ err = traverse_tnc_and_construct_files(c);
+ if (err) {
+ handle_error(c, HAS_TNC_CORRUPTED);
+ return err;
+ }
+
+ destroy_file_tree(c, &FSCK(c)->scanned_files);
+ return err;
}
int main(int argc, char *argv[])
@@ -468,6 +478,9 @@ int main(int argc, char *argv[])
goto out_close;
}
+ /*
+ * Step 6: Traverse tnc and construct files
+ */
err = do_fsck();
if (err && FSCK(c)->try_rebuild) {
ubifs_destroy_filesystem(c);
diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.h b/ubifs-utils/fsck.ubifs/fsck.ubifs.h
index db43ccc..4fa4088 100644
--- a/ubifs-utils/fsck.ubifs/fsck.ubifs.h
+++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.h
@@ -38,7 +38,8 @@ enum { NORMAL_MODE = 0, SAFE_MODE, DANGER_MODE0,
/* Types of inconsistent problems */
enum { SB_CORRUPTED = 0, MST_CORRUPTED, LOG_CORRUPTED, BUD_CORRUPTED,
- TNC_CORRUPTED, TNC_DATA_CORRUPTED, ORPHAN_CORRUPTED };
+ TNC_CORRUPTED, TNC_DATA_CORRUPTED, ORPHAN_CORRUPTED, INVALID_INO_NODE,
+ INVALID_DENT_NODE, INVALID_DATA_NODE };
enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 };
@@ -294,4 +295,7 @@ int check_and_correct_files(struct ubifs_info *c);
/* rebuild_fs.c */
int ubifs_rebuild_filesystem(struct ubifs_info *c);
+/* check_files.c */
+int traverse_tnc_and_construct_files(struct ubifs_info *c);
+
#endif
diff --git a/ubifs-utils/fsck.ubifs/problem.c b/ubifs-utils/fsck.ubifs/problem.c
index 9c8730a..f99fd90 100644
--- a/ubifs-utils/fsck.ubifs/problem.c
+++ b/ubifs-utils/fsck.ubifs/problem.c
@@ -42,6 +42,9 @@ static const struct fsck_problem problem_table[] = {
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA | PROBLEM_NEED_REBUILD, "Corrupted index node"}, // TNC_CORRUPTED
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Corrupted data searched from TNC"}, // TNC_DATA_CORRUPTED
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Corrupted orphan LEB"}, // ORPHAN_CORRUPTED
+ {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Invalid inode node"}, // INVALID_INO_NODE
+ {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Invalid dentry node"}, // INVALID_DENT_NODE
+ {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Invalid data node"}, // INVALID_DATA_NODE
};
static const char *get_question(const struct fsck_problem *problem,
@@ -54,6 +57,9 @@ static const char *get_question(const struct fsck_problem *problem,
case BUD_CORRUPTED:
return "Drop bud?";
case TNC_DATA_CORRUPTED:
+ case INVALID_INO_NODE:
+ case INVALID_DENT_NODE:
+ case INVALID_DATA_NODE:
return "Drop it?";
case ORPHAN_CORRUPTED:
return "Drop orphans on the LEB?";
diff --git a/ubifs-utils/libubifs/debug.c b/ubifs-utils/libubifs/debug.c
index eaf403f..836cbc7 100644
--- a/ubifs-utils/libubifs/debug.c
+++ b/ubifs-utils/libubifs/debug.c
@@ -51,7 +51,7 @@ static const char *get_key_hash(int hash)
}
}
-static const char *get_key_type(int type)
+const char *ubifs_get_key_name(int type)
{
switch (type) {
case UBIFS_INO_KEY:
@@ -102,23 +102,25 @@ const char *dbg_snprintf_key(const struct ubifs_info *c,
case UBIFS_INO_KEY:
len -= snprintf(p, len, "(%lu, %s)",
(unsigned long)key_inum(c, key),
- get_key_type(type));
+ ubifs_get_key_name(type));
break;
case UBIFS_DENT_KEY:
case UBIFS_XENT_KEY:
len -= snprintf(p, len, "(%lu, %s, %#08x)",
(unsigned long)key_inum(c, key),
- get_key_type(type), key_hash(c, key));
+ ubifs_get_key_name(type),
+ key_hash(c, key));
break;
case UBIFS_DATA_KEY:
len -= snprintf(p, len, "(%lu, %s, %u)",
(unsigned long)key_inum(c, key),
- get_key_type(type), key_block(c, key));
+ ubifs_get_key_name(type),
+ key_block(c, key));
break;
case UBIFS_TRUN_KEY:
len -= snprintf(p, len, "(%lu, %s)",
(unsigned long)key_inum(c, key),
- get_key_type(type));
+ ubifs_get_key_name(type));
break;
default:
len -= snprintf(p, len, "(bad key type: %#08x, %#08x)",
diff --git a/ubifs-utils/libubifs/debug.h b/ubifs-utils/libubifs/debug.h
index 4b475a0..c4aa59d 100644
--- a/ubifs-utils/libubifs/debug.h
+++ b/ubifs-utils/libubifs/debug.h
@@ -84,6 +84,7 @@ static inline int dbg_is_chk_index(__unused const struct ubifs_info *c)
{ return 0; }
/* Dump functions */
+const char *ubifs_get_key_name(int type);
const char *ubifs_get_type_name(int type);
const char *dbg_ntype(int type);
const char *dbg_cstate(int cmt_state);