diff options
Diffstat (limited to 'fsck.c')
-rw-r--r-- | fsck.c | 153 |
1 files changed, 131 insertions, 22 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,88 @@ 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; - init_tree_desc(&desc, tree->buffer, tree->size); - while (tree_entry(&desc, &entry)) { + name = get_object_name(options, &tree->object); + if (init_tree_desc_gently(&desc, tree->buffer, tree->size)) + return -1; + while (tree_entry_gently(&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 +384,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 +445,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 +468,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; } } @@ -427,7 +521,7 @@ static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, con static int fsck_tree(struct tree *item, struct fsck_options *options) { - int retval; + int retval = 0; int has_null_sha1 = 0; int has_full_path = 0; int has_empty_name = 0; @@ -442,7 +536,10 @@ static int fsck_tree(struct tree *item, struct fsck_options *options) unsigned o_mode; const char *o_name; - init_tree_desc(&desc, item->buffer, item->size); + if (init_tree_desc_gently(&desc, item->buffer, item->size)) { + retval += report(options, &item->object, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree"); + return retval; + } o_mode = 0; o_name = NULL; @@ -450,11 +547,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, "."); @@ -463,7 +560,10 @@ static int fsck_tree(struct tree *item, struct fsck_options *options) is_hfs_dotgit(name) || is_ntfs_dotgit(name)); has_zero_pad |= *(char *)desc.buffer == '0'; - update_tree_entry(&desc); + if (update_tree_entry_gently(&desc)) { + retval += report(options, &item->object, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree"); + break; + } switch (mode) { /* @@ -504,7 +604,6 @@ static int fsck_tree(struct tree *item, struct fsck_options *options) o_name = name; } - retval = 0; if (has_null_sha1) retval += report(options, &item->object, FSCK_MSG_NULL_SHA1, "contains entries pointing to null sha1"); if (has_full_path) @@ -610,6 +709,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 +766,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 +916,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; } |