diff options
Diffstat (limited to 'fsck.c')
| -rw-r--r-- | fsck.c | 135 | 
1 files changed, 119 insertions, 16 deletions
@@ -9,6 +9,7 @@  #include "refs.h"  #include "utf8.h"  #include "sha1-array.h" +#include "decorate.h"  #define FSCK_FATAL -1  #define FSCK_INFO -2 @@ -59,6 +60,7 @@  	FUNC(HAS_DOTGIT, WARN) \  	FUNC(NULL_SHA1, WARN) \  	FUNC(ZERO_PADDED_FILEMODE, WARN) \ +	FUNC(NUL_IN_COMMIT, WARN) \  	/* infos (reported as warnings, but ignored by default) */ \  	FUNC(BAD_TAG_NAME, INFO) \  	FUNC(MISSING_TAGGER_ENTRY, INFO) @@ -289,35 +291,87 @@ static int report(struct fsck_options *options, struct object *object,  	va_start(ap, fmt);  	strbuf_vaddf(&sb, fmt, ap); -	result = options->error_func(object, msg_type, sb.buf); +	result = options->error_func(options, object, msg_type, sb.buf);  	strbuf_release(&sb);  	va_end(ap);  	return result;  } +static char *get_object_name(struct fsck_options *options, struct object *obj) +{ +	if (!options->object_names) +		return NULL; +	return lookup_decoration(options->object_names, obj); +} + +static void put_object_name(struct fsck_options *options, struct object *obj, +	const char *fmt, ...) +{ +	va_list ap; +	struct strbuf buf = STRBUF_INIT; +	char *existing; + +	if (!options->object_names) +		return; +	existing = lookup_decoration(options->object_names, obj); +	if (existing) +		return; +	va_start(ap, fmt); +	strbuf_vaddf(&buf, fmt, ap); +	add_decoration(options->object_names, obj, strbuf_detach(&buf, NULL)); +	va_end(ap); +} + +static const char *describe_object(struct fsck_options *o, struct object *obj) +{ +	static struct strbuf buf = STRBUF_INIT; +	char *name; + +	strbuf_reset(&buf); +	strbuf_addstr(&buf, oid_to_hex(&obj->oid)); +	if (o->object_names && (name = lookup_decoration(o->object_names, obj))) +		strbuf_addf(&buf, " (%s)", name); + +	return buf.buf; +} +  static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *options)  {  	struct tree_desc desc;  	struct name_entry entry;  	int res = 0; +	const char *name;  	if (parse_tree(tree))  		return -1; +	name = get_object_name(options, &tree->object);  	init_tree_desc(&desc, tree->buffer, tree->size);  	while (tree_entry(&desc, &entry)) { +		struct object *obj;  		int result;  		if (S_ISGITLINK(entry.mode))  			continue; -		if (S_ISDIR(entry.mode)) -			result = options->walk(&lookup_tree(entry.sha1)->object, OBJ_TREE, data, options); -		else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) -			result = options->walk(&lookup_blob(entry.sha1)->object, OBJ_BLOB, data, options); + +		if (S_ISDIR(entry.mode)) { +			obj = &lookup_tree(entry.oid->hash)->object; +			if (name) +				put_object_name(options, obj, "%s%s/", name, +					entry.path); +			result = options->walk(obj, OBJ_TREE, data, options); +		} +		else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) { +			obj = &lookup_blob(entry.oid->hash)->object; +			if (name) +				put_object_name(options, obj, "%s%s", name, +					entry.path); +			result = options->walk(obj, OBJ_BLOB, data, options); +		}  		else {  			result = error("in tree %s: entry %s has bad mode %.6o", -					oid_to_hex(&tree->object.oid), entry.path, entry.mode); +					describe_object(options, &tree->object), entry.path, entry.mode);  		}  		if (result < 0)  			return result; @@ -329,20 +383,55 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op  static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_options *options)  { +	int counter = 0, generation = 0, name_prefix_len = 0;  	struct commit_list *parents;  	int res;  	int result; +	const char *name;  	if (parse_commit(commit))  		return -1; +	name = get_object_name(options, &commit->object); +	if (name) +		put_object_name(options, &commit->tree->object, "%s:", name); +  	result = options->walk((struct object *)commit->tree, OBJ_TREE, data, options);  	if (result < 0)  		return result;  	res = result;  	parents = commit->parents; +	if (name && parents) { +		int len = strlen(name), power; + +		if (len && name[len - 1] == '^') { +			generation = 1; +			name_prefix_len = len - 1; +		} +		else { /* parse ~<generation> suffix */ +			for (generation = 0, power = 1; +			     len && isdigit(name[len - 1]); +			     power *= 10) +				generation += power * (name[--len] - '0'); +			if (power > 1 && len && name[len - 1] == '~') +				name_prefix_len = len - 1; +		} +	} +  	while (parents) { +		if (name) { +			struct object *obj = &parents->item->object; + +			if (++counter > 1) +				put_object_name(options, obj, "%s^%d", +					name, counter); +			else if (generation > 0) +				put_object_name(options, obj, "%.*s~%d", +					name_prefix_len, name, generation + 1); +			else +				put_object_name(options, obj, "%s^", name); +		}  		result = options->walk((struct object *)parents->item, OBJ_COMMIT, data, options);  		if (result < 0)  			return result; @@ -355,8 +444,12 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio  static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *options)  { +	char *name = get_object_name(options, &tag->object); +  	if (parse_tag(tag))  		return -1; +	if (name) +		put_object_name(options, tag->tagged, "%s", name);  	return options->walk(tag->tagged, OBJ_ANY, data, options);  } @@ -374,7 +467,7 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)  	case OBJ_TAG:  		return fsck_walk_tag((struct tag *)obj, data, options);  	default: -		error("Unknown object type for %s", oid_to_hex(&obj->oid)); +		error("Unknown object type for %s", describe_object(options, obj));  		return -1;  	}  } @@ -450,11 +543,11 @@ static int fsck_tree(struct tree *item, struct fsck_options *options)  	while (desc.size) {  		unsigned mode;  		const char *name; -		const unsigned char *sha1; +		const struct object_id *oid; -		sha1 = tree_entry_extract(&desc, &name, &mode); +		oid = tree_entry_extract(&desc, &name, &mode); -		has_null_sha1 |= is_null_sha1(sha1); +		has_null_sha1 |= is_null_oid(oid);  		has_full_path |= !!strchr(name, '/');  		has_empty_name |= !*name;  		has_dot |= !strcmp(name, "."); @@ -610,6 +703,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,  	struct commit_graft *graft;  	unsigned parent_count, parent_line_count = 0, author_count;  	int err; +	const char *buffer_begin = buffer;  	if (verify_headers(buffer, size, &commit->object, options))  		return -1; @@ -666,9 +760,17 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,  	err = fsck_ident(&buffer, &commit->object, options);  	if (err)  		return err; -	if (!commit->tree) -		return report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", sha1_to_hex(tree_sha1)); - +	if (!commit->tree) { +		err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", sha1_to_hex(tree_sha1)); +		if (err) +			return err; +	} +	if (memchr(buffer_begin, '\0', size)) { +		err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT, +			     "NUL byte in the commit object body"); +		if (err) +			return err; +	}  	return 0;  } @@ -808,12 +910,13 @@ int fsck_object(struct object *obj, void *data, unsigned long size,  			  obj->type);  } -int fsck_error_function(struct object *obj, int msg_type, const char *message) +int fsck_error_function(struct fsck_options *o, +	struct object *obj, int msg_type, const char *message)  {  	if (msg_type == FSCK_WARN) { -		warning("object %s: %s", oid_to_hex(&obj->oid), message); +		warning("object %s: %s", describe_object(o, obj), message);  		return 0;  	} -	error("object %s: %s", oid_to_hex(&obj->oid), message); +	error("object %s: %s", describe_object(o, obj), message);  	return 1;  }  | 
