From 271b8d25b25e49b367087440e093e755e5f35aa9 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:05 +0100 Subject: builtin-fsck: move away from object-refs to fsck_walk Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- builtin-fsck.c | 99 +++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 28 deletions(-) (limited to 'builtin-fsck.c') diff --git a/builtin-fsck.c b/builtin-fsck.c index 2a6e94deaf..7321ab236b 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -8,6 +8,7 @@ #include "pack.h" #include "cache-tree.h" #include "tree-walk.h" +#include "fsck.h" #include "parse-options.h" #define REACHABLE 0x0001 @@ -63,13 +64,73 @@ static int objwarning(struct object *obj, const char *err, ...) return -1; } +static int mark_object(struct object *obj, int type, void *data) +{ + struct tree *tree = NULL; + struct object *parent = data; + int result; + + if (!obj) { + printf("broken link from %7s %s\n", + typename(parent->type), sha1_to_hex(parent->sha1)); + printf("broken link from %7s %s\n", + (type == OBJ_ANY ? "unknown" : typename(type)), "unknown"); + errors_found |= ERROR_REACHABLE; + return 1; + } + + if (type != OBJ_ANY && obj->type != type) + objerror(parent, "wrong object type in link"); + + if (obj->flags & REACHABLE) + return 0; + obj->flags |= REACHABLE; + if (!obj->parsed) { + if (parent && !has_sha1_file(obj->sha1)) { + printf("broken link from %7s %s\n", + typename(parent->type), sha1_to_hex(parent->sha1)); + printf(" to %7s %s\n", + typename(obj->type), sha1_to_hex(obj->sha1)); + errors_found |= ERROR_REACHABLE; + } + return 1; + } + + if (obj->type == OBJ_TREE) { + obj->parsed = 0; + tree = (struct tree *)obj; + if (parse_tree(tree) < 0) + return 1; /* error already displayed */ + } + result = fsck_walk(obj, mark_object, obj); + if (tree) { + free(tree->buffer); + tree->buffer = NULL; + } + if (result < 0) + result = 1; + + return result; +} + +static void mark_object_reachable(struct object *obj) +{ + mark_object(obj, OBJ_ANY, 0); +} + +static int mark_used(struct object *obj, int type, void *data) +{ + if (!obj) + return 1; + obj->used = 1; + return 0; +} + /* * Check a single reachable object */ static void check_reachable_object(struct object *obj) { - const struct object_refs *refs; - /* * We obviously want the object to be parsed, * except if it was in a pack-file and we didn't @@ -82,25 +143,6 @@ static void check_reachable_object(struct object *obj) errors_found |= ERROR_REACHABLE; return; } - - /* - * Check that everything that we try to reference is also good. - */ - refs = lookup_object_refs(obj); - if (refs) { - unsigned j; - for (j = 0; j < refs->count; j++) { - struct object *ref = refs->ref[j]; - if (ref->parsed || - (has_sha1_file(ref->sha1))) - continue; - printf("broken link from %7s %s\n", - typename(obj->type), sha1_to_hex(obj->sha1)); - printf(" to %7s %s\n", - typename(ref->type), sha1_to_hex(ref->sha1)); - errors_found |= ERROR_REACHABLE; - } - } } /* @@ -414,6 +456,8 @@ static int fsck_sha1(const unsigned char *sha1) if (obj->flags & SEEN) return 0; obj->flags |= SEEN; + if (fsck_walk(obj, mark_used, 0)) + objerror(obj, "broken links"); if (obj->type == OBJ_BLOB) return 0; if (obj->type == OBJ_TREE) @@ -538,13 +582,13 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1, obj = lookup_object(osha1); if (obj) { obj->used = 1; - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); } } obj = lookup_object(nsha1); if (obj) { obj->used = 1; - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); } return 0; } @@ -574,7 +618,7 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f error("%s: not a commit", refname); default_refs++; obj->used = 1; - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); return 0; } @@ -660,7 +704,7 @@ static int fsck_cache_tree(struct cache_tree *it) sha1_to_hex(it->sha1)); return 1; } - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); obj->used = 1; if (obj->type != OBJ_TREE) err |= objerror(obj, "non-tree in cache-tree"); @@ -693,7 +737,6 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) { int i, heads; - track_object_refs = 1; errors_found = 0; argc = parse_options(argc, argv, fsck_opts, fsck_usage, 0); @@ -741,7 +784,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) continue; obj->used = 1; - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); heads++; continue; } @@ -773,7 +816,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) continue; obj = &blob->object; obj->used = 1; - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); } if (active_cache_tree) fsck_cache_tree(active_cache_tree); -- cgit v1.2.3 From 45163382437c3862d3beb88134b7a975a3a26443 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:07 +0100 Subject: builtin-fsck: reports missing parent commits parse_commit ignores parent commits with certain errors (eg. a non commit object is already loaded under the sha1 of the parent). To make fsck reports such errors, it has to compare the nummer of parent commits returned by parse commit with the number of parent commits in the object or in the graft/shallow file. Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- builtin-fsck.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'builtin-fsck.c') diff --git a/builtin-fsck.c b/builtin-fsck.c index 7321ab236b..727310afc2 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -397,6 +397,8 @@ static int fsck_commit(struct commit *commit) { char *buffer = commit->buffer; unsigned char tree_sha1[20], sha1[20]; + struct commit_graft *graft; + int parents = 0; if (verbose) fprintf(stderr, "Checking commit %s\n", @@ -411,6 +413,28 @@ static int fsck_commit(struct commit *commit) if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n') return objerror(&commit->object, "invalid 'parent' line format - bad sha1"); buffer += 48; + parents++; + } + graft = lookup_commit_graft(commit->object.sha1); + if (graft) { + struct commit_list *p = commit->parents; + parents = 0; + while (p) { + p = p->next; + parents++; + } + if (graft->nr_parent == -1 && !parents) + ; /* shallow commit */ + else if (graft->nr_parent != parents) + return objerror(&commit->object, "graft objects missing"); + } else { + struct commit_list *p = commit->parents; + while (p && parents) { + p = p->next; + parents--; + } + if (p || parents) + return objerror(&commit->object, "parent objects missing"); } if (memcmp(buffer, "author ", 7)) return objerror(&commit->object, "invalid format - expected 'author' line"); -- cgit v1.2.3 From ba002f3b28ab9febea432d4c415dbe581836d9a0 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:08 +0100 Subject: builtin-fsck: move common object checking code to fsck.c Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- builtin-fsck.c | 270 ++++++++------------------------------------------------- 1 file changed, 35 insertions(+), 235 deletions(-) (limited to 'builtin-fsck.c') diff --git a/builtin-fsck.c b/builtin-fsck.c index 727310afc2..d545650c8c 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -55,13 +55,13 @@ static int objerror(struct object *obj, const char *err, ...) return -1; } -static int objwarning(struct object *obj, const char *err, ...) +static int fsck_error_func(struct object *obj, int type, const char *err, ...) { va_list params; va_start(params, err); - objreport(obj, "warning", err, params); + objreport(obj, (type == FSCK_WARN) ? "warning" : "error", err, params); va_end(params); - return -1; + return (type == FSCK_WARN) ? 0 : 1; } static int mark_object(struct object *obj, int type, void *data) @@ -246,256 +246,56 @@ static void check_connectivity(void) } } -/* - * The entries in a tree are ordered in the _path_ order, - * which means that a directory entry is ordered by adding - * a slash to the end of it. - * - * So a directory called "a" is ordered _after_ a file - * called "a.c", because "a/" sorts after "a.c". - */ -#define TREE_UNORDERED (-1) -#define TREE_HAS_DUPS (-2) - -static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2) +static int fsck_sha1(const unsigned char *sha1) { - int len1 = strlen(name1); - int len2 = strlen(name2); - int len = len1 < len2 ? len1 : len2; - unsigned char c1, c2; - int cmp; - - cmp = memcmp(name1, name2, len); - if (cmp < 0) + struct object *obj = parse_object(sha1); + if (!obj) { + errors_found |= ERROR_OBJECT; + return error("%s: object corrupt or missing", + sha1_to_hex(sha1)); + } + if (obj->flags & SEEN) return 0; - if (cmp > 0) - return TREE_UNORDERED; - - /* - * Ok, the first characters are the same. - * Now we need to order the next one, but turn - * a '\0' into a '/' for a directory entry. - */ - c1 = name1[len]; - c2 = name2[len]; - if (!c1 && !c2) - /* - * git-write-tree used to write out a nonsense tree that has - * entries with the same name, one blob and one tree. Make - * sure we do not have duplicate entries. - */ - return TREE_HAS_DUPS; - if (!c1 && S_ISDIR(mode1)) - c1 = '/'; - if (!c2 && S_ISDIR(mode2)) - c2 = '/'; - return c1 < c2 ? 0 : TREE_UNORDERED; -} - -static int fsck_tree(struct tree *item) -{ - int retval; - int has_full_path = 0; - int has_empty_name = 0; - int has_zero_pad = 0; - int has_bad_modes = 0; - int has_dup_entries = 0; - int not_properly_sorted = 0; - struct tree_desc desc; - unsigned o_mode; - const char *o_name; - const unsigned char *o_sha1; + obj->flags |= SEEN; if (verbose) - fprintf(stderr, "Checking tree %s\n", - sha1_to_hex(item->object.sha1)); - - init_tree_desc(&desc, item->buffer, item->size); - - o_mode = 0; - o_name = NULL; - o_sha1 = NULL; - while (desc.size) { - unsigned mode; - const char *name; - const unsigned char *sha1; - - sha1 = tree_entry_extract(&desc, &name, &mode); - - if (strchr(name, '/')) - has_full_path = 1; - if (!*name) - has_empty_name = 1; - has_zero_pad |= *(char *)desc.buffer == '0'; - update_tree_entry(&desc); - - switch (mode) { - /* - * Standard modes.. - */ - case S_IFREG | 0755: - case S_IFREG | 0644: - case S_IFLNK: - case S_IFDIR: - case S_IFGITLINK: - break; - /* - * This is nonstandard, but we had a few of these - * early on when we honored the full set of mode - * bits.. - */ - case S_IFREG | 0664: - if (!check_strict) - break; - default: - has_bad_modes = 1; - } + fprintf(stderr, "Checking %s %s\n", + typename(obj->type), sha1_to_hex(obj->sha1)); - if (o_name) { - switch (verify_ordered(o_mode, o_name, mode, name)) { - case TREE_UNORDERED: - not_properly_sorted = 1; - break; - case TREE_HAS_DUPS: - has_dup_entries = 1; - break; - default: - break; - } - } + if (fsck_walk(obj, mark_used, 0)) + objerror(obj, "broken links"); + if (fsck_object(obj, check_strict, fsck_error_func)) + return -1; - o_mode = mode; - o_name = name; - o_sha1 = sha1; - } - free(item->buffer); - item->buffer = NULL; + if (obj->type == OBJ_TREE) { + struct tree *item = (struct tree *) obj; - retval = 0; - if (has_full_path) { - objwarning(&item->object, "contains full pathnames"); - } - if (has_empty_name) { - objwarning(&item->object, "contains empty pathname"); - } - if (has_zero_pad) { - objwarning(&item->object, "contains zero-padded file modes"); - } - if (has_bad_modes) { - objwarning(&item->object, "contains bad file modes"); + free(item->buffer); + item->buffer = NULL; } - if (has_dup_entries) { - retval = objerror(&item->object, "contains duplicate file entries"); - } - if (not_properly_sorted) { - retval = objerror(&item->object, "not properly sorted"); - } - return retval; -} -static int fsck_commit(struct commit *commit) -{ - char *buffer = commit->buffer; - unsigned char tree_sha1[20], sha1[20]; - struct commit_graft *graft; - int parents = 0; + if (obj->type == OBJ_COMMIT) { + struct commit *commit = (struct commit *) obj; - if (verbose) - fprintf(stderr, "Checking commit %s\n", - sha1_to_hex(commit->object.sha1)); - - if (memcmp(buffer, "tree ", 5)) - return objerror(&commit->object, "invalid format - expected 'tree' line"); - if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n') - return objerror(&commit->object, "invalid 'tree' line format - bad sha1"); - buffer += 46; - while (!memcmp(buffer, "parent ", 7)) { - if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n') - return objerror(&commit->object, "invalid 'parent' line format - bad sha1"); - buffer += 48; - parents++; - } - graft = lookup_commit_graft(commit->object.sha1); - if (graft) { - struct commit_list *p = commit->parents; - parents = 0; - while (p) { - p = p->next; - parents++; - } - if (graft->nr_parent == -1 && !parents) - ; /* shallow commit */ - else if (graft->nr_parent != parents) - return objerror(&commit->object, "graft objects missing"); - } else { - struct commit_list *p = commit->parents; - while (p && parents) { - p = p->next; - parents--; - } - if (p || parents) - return objerror(&commit->object, "parent objects missing"); - } - if (memcmp(buffer, "author ", 7)) - return objerror(&commit->object, "invalid format - expected 'author' line"); - free(commit->buffer); - commit->buffer = NULL; - if (!commit->tree) - return objerror(&commit->object, "could not load commit's tree %s", tree_sha1); - if (!commit->parents && show_root) - printf("root %s\n", sha1_to_hex(commit->object.sha1)); - if (!commit->date) - printf("bad commit date in %s\n", - sha1_to_hex(commit->object.sha1)); - return 0; -} + free(commit->buffer); + commit->buffer = NULL; -static int fsck_tag(struct tag *tag) -{ - struct object *tagged = tag->tagged; + if (!commit->parents && show_root) + printf("root %s\n", sha1_to_hex(commit->object.sha1)); + } - if (verbose) - fprintf(stderr, "Checking tag %s\n", - sha1_to_hex(tag->object.sha1)); + if (obj->type == OBJ_TAG) { + struct tag *tag = (struct tag *) obj; - if (!tagged) { - return objerror(&tag->object, "could not load tagged object"); + if (show_tags && tag->tagged) { + printf("tagged %s %s", typename(tag->tagged->type), sha1_to_hex(tag->tagged->sha1)); + printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1)); + } } - if (!show_tags) - return 0; - printf("tagged %s %s", typename(tagged->type), sha1_to_hex(tagged->sha1)); - printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1)); return 0; } -static int fsck_sha1(const unsigned char *sha1) -{ - struct object *obj = parse_object(sha1); - if (!obj) { - errors_found |= ERROR_OBJECT; - return error("%s: object corrupt or missing", - sha1_to_hex(sha1)); - } - if (obj->flags & SEEN) - return 0; - obj->flags |= SEEN; - if (fsck_walk(obj, mark_used, 0)) - objerror(obj, "broken links"); - if (obj->type == OBJ_BLOB) - return 0; - if (obj->type == OBJ_TREE) - return fsck_tree((struct tree *) obj); - if (obj->type == OBJ_COMMIT) - return fsck_commit((struct commit *) obj); - if (obj->type == OBJ_TAG) - return fsck_tag((struct tag *) obj); - - /* By now, parse_object() would've returned NULL instead. */ - return objerror(obj, "unknown type '%d' (internal fsck error)", - obj->type); -} - /* * This is the sorting chunk size: make it reasonably * big so that we can sort well.. -- cgit v1.2.3