aboutsummaryrefslogtreecommitdiff
path: root/ubifs-utils
diff options
context:
space:
mode:
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);