diff options
Diffstat (limited to 'ubifs-utils/fsck.ubifs')
| -rw-r--r-- | ubifs-utils/fsck.ubifs/check_files.c | 57 | ||||
| -rw-r--r-- | ubifs-utils/fsck.ubifs/extract_files.c | 13 | ||||
| -rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.c | 9 | ||||
| -rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.h | 3 | ||||
| -rw-r--r-- | ubifs-utils/fsck.ubifs/problem.c | 14 | 
5 files changed, 95 insertions, 1 deletions
| diff --git a/ubifs-utils/fsck.ubifs/check_files.c b/ubifs-utils/fsck.ubifs/check_files.c index c5c606e..2be9619 100644 --- a/ubifs-utils/fsck.ubifs/check_files.c +++ b/ubifs-utils/fsck.ubifs/check_files.c @@ -7,6 +7,7 @@  #include <stdio.h>  #include <stdlib.h> +#include <sys/stat.h>  #include "linux_err.h"  #include "bitops.h" @@ -442,3 +443,59 @@ int handle_invalid_files(struct ubifs_info *c)  	return 0;  } + +/** + * handle_dentry_tree - Handle unreachable dentries and files. + * @c: UBIFS file-system description object + * + * This function iterates all directory entries and remove those unreachable + * ones. If file has no directory entries, it becomes unreachable: + * 1. If the unreachable file has non-regular type, delete it; + * 2. If the unreachable file has regular type, move it into the + *    @FSCK(c)->disconnected_files. + * 'Unreachable' means that a directory entry can not be searched from '/'. + * + * Returns zero in case of success, a negative error code in case of failure. + */ +int handle_dentry_tree(struct ubifs_info *c) +{ +	struct rb_node *node; +	struct scanned_file *file; +	struct rb_root *tree = &FSCK(c)->scanned_files; +	LIST_HEAD(unreachable); + +	for (node = rb_first(tree); node; node = rb_next(node)) { +		file = rb_entry(node, struct scanned_file, rb); + +		/* +		 * Since all xattr files are already attached to corresponding +		 * host file, there are only non-xattr files in the file tree. +		 */ +		ubifs_assert(c, !file->ino.is_xattr); +		if (!file_is_reachable(c, file, tree)) +			list_add(&file->list, &unreachable); +	} + +	while (!list_empty(&unreachable)) { +		file = list_entry(unreachable.next, struct scanned_file, list); + +		list_del(&file->list); +		if (S_ISREG(file->ino.mode)) { +			/* +			 * Move regular type unreachable file into the +			 * @FSCK(c)->disconnected_files. +			 */ +			list_add(&file->list, &FSCK(c)->disconnected_files); +			rb_erase(&file->rb, tree); +		} else { +			/* Delete non-regular type unreachable file. */ +			int err = delete_file(c, file); +			if (err) +				return err; +			rb_erase(&file->rb, tree); +			kfree(file); +		} +	} + +	return 0; +} diff --git a/ubifs-utils/fsck.ubifs/extract_files.c b/ubifs-utils/fsck.ubifs/extract_files.c index 51b83b8..b24445b 100644 --- a/ubifs-utils/fsck.ubifs/extract_files.c +++ b/ubifs-utils/fsck.ubifs/extract_files.c @@ -1247,6 +1247,15 @@ retry:  			dent_node = list_entry(path_list.next,  					       struct scanned_dent_node, list); +			handle_invalid_file(c, DENTRY_IS_UNREACHABLE, +					    dent_node->file, dent_node); +			if (FSCK(c)->mode != REBUILD_MODE) { +				int err = delete_node(c, &dent_node->key, +						      dent_node->header.lnum, +						      dent_node->header.offs); +				if (err) +					return err; +			}  			dbg_fsck("remove unreachable dentry %s, in %s",  				 c->encrypted && !file->ino.is_xattr ?  				 "<encrypted>" : dent_node->name, c->dev_name); @@ -1260,6 +1269,10 @@ retry:  	}  	if (!rb_first(&file->dent_nodes)) { +		if (S_ISREG(file->ino.mode)) +			handle_invalid_file(c, FILE_IS_DISCONNECTED, file, NULL); +		else +			handle_invalid_file(c, FILE_HAS_NO_DENT, file, NULL);  		dbg_fsck("file %lu is unreachable, in %s", file->inum, c->dev_name);  		return false;  	} diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.c b/ubifs-utils/fsck.ubifs/fsck.ubifs.c index ac94ba4..6a718fd 100644 --- a/ubifs-utils/fsck.ubifs/fsck.ubifs.c +++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.c @@ -453,6 +453,14 @@ static int do_fsck(void)  		goto free_used_lebs;  	} +	log_out(c, "Check and handle unreachable files"); +	err = handle_dentry_tree(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:  	kfree(FSCK(c)->used_lebs); @@ -495,6 +503,7 @@ int main(int argc, char *argv[])  	 * Step 6: Traverse tnc and construct files  	 * Step 7: Update files' size  	 * Step 8: Check and handle invalid files +	 * Step 9: Check and handle unreachable 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 7ac512c..521723d 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 }; +       FILE_ROOT_HAS_DENT, DENTRY_IS_UNREACHABLE };  enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 }; @@ -317,5 +317,6 @@ int ubifs_rebuild_filesystem(struct ubifs_info *c);  int traverse_tnc_and_construct_files(struct ubifs_info *c);  void update_files_size(struct ubifs_info *c);  int handle_invalid_files(struct ubifs_info *c); +int handle_dentry_tree(struct ubifs_info *c);  #endif diff --git a/ubifs-utils/fsck.ubifs/problem.c b/ubifs-utils/fsck.ubifs/problem.c index 9222cba..0395a34 100644 --- a/ubifs-utils/fsck.ubifs/problem.c +++ b/ubifs-utils/fsck.ubifs/problem.c @@ -58,6 +58,7 @@ static const struct fsck_problem problem_table[] = {  	{PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Encrypted file has no encryption information"},	// FILE_HAS_NO_ENCRYPT  	{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  };  static const char *get_question(const struct fsck_problem *problem, @@ -84,6 +85,7 @@ static const char *get_question(const struct fsck_problem *problem,  	case XATTR_HAS_WRONG_HOST:  	case FILE_HAS_NO_ENCRYPT:  	case FILE_ROOT_HAS_DENT: +	case DENTRY_IS_UNREACHABLE:  		return "Delete it?";  	case FILE_HAS_INCONSIST_TYPE:  	case FILE_HAS_TOO_MANY_DENT: @@ -198,6 +200,18 @@ static void print_problem(const struct ubifs_info *c,  			host->ino.is_xattr ? "(xattr)" : "");  		break;  	} +	case DENTRY_IS_UNREACHABLE: +	{ +		const struct invalid_file_problem *ifp = (const struct invalid_file_problem *)priv; +		const struct scanned_dent_node *dent_node = (const struct scanned_dent_node *)ifp->priv; + +		log_out(c, "problem: %s, ino %lu, unreachable dentry %s, type %s%s", +			problem->desc, ifp->file->inum, +			c->encrypted && !ifp->file->ino.is_xattr ? "<encrypted>" : dent_node->name, +			ubifs_get_type_name(dent_node->type), +			key_type(c, &dent_node->key) == UBIFS_XENT_KEY ? "(xattr)" : ""); +		break; +	}  	default:  		log_out(c, "problem: %s", problem->desc);  		break; | 
