* data nodes and truncation node. The calculated informaion will be used
* to correct inode node.
*/
-static void calculate_file_info(struct ubifs_info *c, struct scanned_file *file,
- struct rb_root *file_tree)
+static int calculate_file_info(struct ubifs_info *c, struct scanned_file *file,
+ struct rb_root *file_tree)
{
int nlink = 0;
bool corrupted_truncation = false;
for (node = rb_first(&file->xattr_files); node; node = rb_next(node)) {
xattr_file = rb_entry(node, struct scanned_file, rb);
+ dent_node = rb_entry(rb_first(&xattr_file->dent_nodes),
+ struct scanned_dent_node, rb);
+ ubifs_assert(c, xattr_file->ino.is_xattr);
ubifs_assert(c, !rb_first(&xattr_file->xattr_files));
- calculate_file_info(c, xattr_file, file_tree);
+ xattr_file->calc_nlink = 1;
+ xattr_file->calc_size = xattr_file->ino.size;
+
+ file->calc_xcnt += 1;
+ file->calc_xsz += CALC_DENT_SIZE(dent_node->nlen);
+ file->calc_xsz += CALC_XATTR_BYTES(xattr_file->ino.size);
+ file->calc_xnms += dent_node->nlen;
}
if (file->inum == UBIFS_ROOT_INO) {
file->calc_nlink += 2;
file->calc_size += UBIFS_INO_NODE_SZ;
- return;
+ return 0;
}
if (S_ISDIR(file->ino.mode)) {
parent_file = lookup_file(file_tree, key_inum(c, &dent_node->key));
if (!parent_file) {
ubifs_assert(c, 0);
- return;
+ return 0;
}
parent_file->calc_nlink += 1;
parent_file->calc_size += CALC_DENT_SIZE(dent_node->nlen);
- return;
- }
-
- if (file->ino.is_xattr) {
- file->calc_nlink = 1;
- file->calc_size = file->ino.size;
-
- dent_node = rb_entry(rb_first(&file->dent_nodes),
- struct scanned_dent_node, rb);
- parent_file = lookup_file(file_tree, key_inum(c, &dent_node->key));
- if (!parent_file) {
- ubifs_assert(c, 0);
- return;
- }
- parent_file->calc_xcnt += 1;
- parent_file->calc_xsz += CALC_DENT_SIZE(dent_node->nlen);
- parent_file->calc_xsz += CALC_XATTR_BYTES(file->ino.size);
- parent_file->calc_xnms += dent_node->nlen;
- return;
+ return 0;
}
for (node = rb_first(&file->dent_nodes); node; node = rb_next(node)) {
parent_file = lookup_file(file_tree, key_inum(c, &dent_node->key));
if (!parent_file) {
ubifs_assert(c, 0);
- return;
+ return 0;
}
parent_file->calc_size += CALC_DENT_SIZE(dent_node->nlen);
}
if (!S_ISREG(file->ino.mode)) {
/* No need to verify i_size for symlink/sock/block/char/fifo. */
file->calc_size = file->ino.size;
- return;
+ return 0;
}
/*
data_node = list_entry(drop_list.next, struct scanned_data_node,
list);
+ if (FSCK(c)->mode != REBUILD_MODE) {
+ /*
+ * Don't ask, inconsistent file correcting will be
+ * asked in function correct_file_info().
+ */
+ int err = delete_node(c, &data_node->key,
+ data_node->header.lnum, data_node->header.offs);
+ if (err)
+ return err;
+ }
list_del(&data_node->list);
rb_erase(&data_node->rb, &file->data_nodes);
kfree(data_node);
}
+
+ return 0;
}
/**
file->calc_size == file->ino.size)
return 0;
+ handle_invalid_file(c, FILE_IS_INCONSISTENT, file, NULL);
lnum = file->ino.header.lnum;
dbg_fsck("correct file(inum:%lu type:%s), nlink %u->%u, xattr cnt %u->%u, xattr size %u->%u, xattr names %u->%u, size %llu->%llu, at %d:%d, in %s",
file->inum, file->ino.is_xattr ? "xattr" :
for (node = rb_first(tree); node; node = rb_next(node)) {
file = rb_entry(node, struct scanned_file, rb);
- calculate_file_info(c, file, tree);
+ err = calculate_file_info(c, file, tree);
+ if (err)
+ return err;
}
for (node = rb_first(tree); node; node = rb_next(node)) {
return err;
}
+ if (list_empty(&FSCK(c)->disconnected_files))
+ return 0;
+
+ ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
+ list_for_each_entry(file, &FSCK(c)->disconnected_files, list) {
+ err = calculate_file_info(c, file, tree);
+ if (err)
+ return err;
+
+ /* Reset disconnected file's nlink as one. */
+ file->calc_nlink = 1;
+ err = correct_file_info(c, file);
+ if (err)
+ return err;
+ }
+
return 0;
}
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX, "File is disconnected(regular file without dentries)"}, // FILE_IS_DISCONNECTED
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Root dir should not have a dentry"}, // FILE_ROOT_HAS_DENT
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Dentry is unreachable"}, // DENTRY_IS_UNREACHABLE
+ {PROBLEM_FIXABLE | PROBLEM_MUST_FIX, "File is inconsistent"}, // FILE_IS_INCONSISTENT
};
static const char *get_question(const struct fsck_problem *problem,
key_type(c, &dent_node->key) == UBIFS_XENT_KEY ? "(xattr)" : "");
break;
}
+ case FILE_IS_INCONSISTENT:
+ {
+ const struct invalid_file_problem *ifp = (const struct invalid_file_problem *)priv;
+ const struct scanned_file *file = ifp->file;
+
+ log_out(c, "problem: %s, ino %lu type %s, nlink %u xcnt %u xsz %u xnms %u size %llu, "
+ "should be nlink %u xcnt %u xsz %u xnms %u size %llu",
+ problem->desc, file->inum,
+ file->ino.is_xattr ? "xattr" : ubifs_get_type_name(ubifs_get_dent_type(file->ino.mode)),
+ file->ino.nlink, file->ino.xcnt, file->ino.xsz,
+ file->ino.xnms, file->ino.size,
+ file->calc_nlink, file->calc_xcnt, file->calc_xsz,
+ file->calc_xnms, file->calc_size);
+ break;
+ }
default:
log_out(c, "problem: %s", problem->desc);
break;