diff options
Diffstat (limited to 'ubifs-utils')
-rw-r--r-- | ubifs-utils/fsck.ubifs/extract_files.c | 76 | ||||
-rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.c | 8 | ||||
-rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.h | 2 | ||||
-rw-r--r-- | ubifs-utils/fsck.ubifs/problem.c | 16 |
4 files changed, 74 insertions, 28 deletions
diff --git a/ubifs-utils/fsck.ubifs/extract_files.c b/ubifs-utils/fsck.ubifs/extract_files.c index b24445b..c83d377 100644 --- a/ubifs-utils/fsck.ubifs/extract_files.c +++ b/ubifs-utils/fsck.ubifs/extract_files.c @@ -1292,8 +1292,8 @@ reachable: * 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; @@ -1306,15 +1306,24 @@ static void calculate_file_info(struct ubifs_info *c, struct scanned_file *file, 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)) { @@ -1326,29 +1335,11 @@ static void calculate_file_info(struct ubifs_info *c, struct scanned_file *file, 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)) { @@ -1359,7 +1350,7 @@ static void calculate_file_info(struct ubifs_info *c, struct scanned_file *file, 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); } @@ -1368,7 +1359,7 @@ static void calculate_file_info(struct ubifs_info *c, struct scanned_file *file, 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; } /* @@ -1452,10 +1443,22 @@ drop_data: 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; } /** @@ -1490,6 +1493,7 @@ static int correct_file_info(struct ubifs_info *c, struct scanned_file *file) 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" : @@ -1537,7 +1541,9 @@ int check_and_correct_files(struct ubifs_info *c) 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)) { @@ -1548,5 +1554,21 @@ int check_and_correct_files(struct ubifs_info *c) 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; } diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.c b/ubifs-utils/fsck.ubifs/fsck.ubifs.c index 6a718fd..3f61668 100644 --- a/ubifs-utils/fsck.ubifs/fsck.ubifs.c +++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.c @@ -460,6 +460,13 @@ static int do_fsck(void) goto free_disconnected_files; } + log_out(c, "Check and correct files"); + err = check_and_correct_files(c); + if (err) { + exit_code |= FSCK_ERROR; + goto free_disconnected_files; + } + free_disconnected_files: destroy_file_list(c, &FSCK(c)->disconnected_files); free_used_lebs: @@ -504,6 +511,7 @@ int main(int argc, char *argv[]) * Step 7: Update files' size * Step 8: Check and handle invalid files * Step 9: Check and handle unreachable files + * Step 10: Check and correct files */ err = do_fsck(); if (err && FSCK(c)->try_rebuild) { diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.h b/ubifs-utils/fsck.ubifs/fsck.ubifs.h index 521723d..32a991d 100644 --- a/ubifs-utils/fsck.ubifs/fsck.ubifs.h +++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.h @@ -43,7 +43,7 @@ enum { SB_CORRUPTED = 0, MST_CORRUPTED, LOG_CORRUPTED, BUD_CORRUPTED, FILE_HAS_0_NLINK_INODE, FILE_HAS_INCONSIST_TYPE, FILE_HAS_TOO_MANY_DENT, FILE_SHOULDNT_HAVE_DATA, FILE_HAS_NO_DENT, XATTR_HAS_NO_HOST, XATTR_HAS_WRONG_HOST, FILE_HAS_NO_ENCRYPT, FILE_IS_DISCONNECTED, - FILE_ROOT_HAS_DENT, DENTRY_IS_UNREACHABLE }; + FILE_ROOT_HAS_DENT, DENTRY_IS_UNREACHABLE, FILE_IS_INCONSISTENT }; enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 }; diff --git a/ubifs-utils/fsck.ubifs/problem.c b/ubifs-utils/fsck.ubifs/problem.c index 0395a34..e8f0860 100644 --- a/ubifs-utils/fsck.ubifs/problem.c +++ b/ubifs-utils/fsck.ubifs/problem.c @@ -59,6 +59,7 @@ static const struct fsck_problem problem_table[] = { {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, @@ -212,6 +213,21 @@ static void print_problem(const struct ubifs_info *c, 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; |