diff options
Diffstat (limited to 'ubifs-utils/fsck.ubifs')
| -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; | 
