From f986f2c830b24a0f56f2bf4b3f30353ca1e372a9 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 3 Sep 2006 22:55:54 -0700 Subject: [PATCH 1/2] unpack-objects desperately salvages objects from a corrupt pack The command unpack-objects dies upon the first error. This is probably considered a feature -- if a pack is corrupt, instead of trying to extract from it and possibly risking to contaminate a good repository with objects whose validity is dubious, we should seek a good copy of the pack and retry. However, we may not have any good copy anywhere. This implements the last resort effort to extract what are salvageable from such a corrupt pack. This flag might have helped Sergio when recovering from a corrupt pack. In my test, it managed to salvage 247 objects out of a pack that had 251 objects but without it the command stopped after extracting 73 objects. Signed-off-by: Junio C Hamano --- Documentation/git-unpack-objects.txt | 8 +++- builtin-unpack-objects.c | 59 ++++++++++++++++++---------- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/Documentation/git-unpack-objects.txt b/Documentation/git-unpack-objects.txt index c20b38b08a..415c09ba10 100644 --- a/Documentation/git-unpack-objects.txt +++ b/Documentation/git-unpack-objects.txt @@ -8,7 +8,7 @@ git-unpack-objects - Unpack objects from a packed archive SYNOPSIS -------- -'git-unpack-objects' [-n] [-q] -static int dry_run, quiet; +static int dry_run, quiet, desperate, has_errors; static const char unpack_usage[] = "git-unpack-objects [-n] [-q] < pack-file"; /* We always read in 4kB chunks. */ @@ -71,8 +71,15 @@ static void *get_data(unsigned long size) use(len - stream.avail_in); if (stream.total_out == size && ret == Z_STREAM_END) break; - if (ret != Z_OK) - die("inflate returned %d\n", ret); + if (ret != Z_OK) { + error("inflate returned %d\n", ret); + free(buf); + buf = NULL; + if (!desperate) + exit(1); + has_errors = 1; + break; + } stream.next_in = fill(1); stream.avail_in = len; } @@ -110,9 +117,9 @@ static void write_object(void *buf, unsigned long size, const char *type) added_object(sha1, type, buf, size); } -static int resolve_delta(const char *type, - void *base, unsigned long base_size, - void *delta, unsigned long delta_size) +static void resolve_delta(const char *type, + void *base, unsigned long base_size, + void *delta, unsigned long delta_size) { void *result; unsigned long result_size; @@ -125,7 +132,6 @@ static int resolve_delta(const char *type, free(delta); write_object(result, result_size, type); free(result); - return 0; } static void added_object(unsigned char *sha1, const char *type, void *data, unsigned long size) @@ -145,7 +151,7 @@ static void added_object(unsigned char *sha1, const char *type, void *data, unsi } } -static int unpack_non_delta_entry(enum object_type kind, unsigned long size) +static void unpack_non_delta_entry(enum object_type kind, unsigned long size) { void *buf = get_data(size); const char *type; @@ -157,39 +163,42 @@ static int unpack_non_delta_entry(enum object_type kind, unsigned long size) case OBJ_TAG: type = tag_type; break; default: die("bad type %d", kind); } - if (!dry_run) + if (!dry_run && buf) write_object(buf, size, type); free(buf); - return 0; } -static int unpack_delta_entry(unsigned long delta_size) +static void unpack_delta_entry(unsigned long delta_size) { void *delta_data, *base; unsigned long base_size; char type[20]; unsigned char base_sha1[20]; - int result; hashcpy(base_sha1, fill(20)); use(20); delta_data = get_data(delta_size); - if (dry_run) { + if (dry_run || !delta_data) { free(delta_data); - return 0; + return; } if (!has_sha1_file(base_sha1)) { add_delta_to_list(base_sha1, delta_data, delta_size); - return 0; + return; } base = read_sha1_file(base_sha1, type, &base_size); - if (!base) - die("failed to read delta-pack base object %s", sha1_to_hex(base_sha1)); - result = resolve_delta(type, base, base_size, delta_data, delta_size); + if (!base) { + error("failed to read delta-pack base object %s", + sha1_to_hex(base_sha1)); + if (!desperate) + exit(1); + has_errors = 1; + return; + } + resolve_delta(type, base, base_size, delta_data, delta_size); free(base); - return result; } static void unpack_one(unsigned nr, unsigned total) @@ -236,7 +245,11 @@ static void unpack_one(unsigned nr, unsigned total) unpack_delta_entry(size); return; default: - die("bad object type %d", type); + error("bad object type %d", type); + has_errors = 1; + if (desperate) + return; + exit(1); } } @@ -280,6 +293,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix) quiet = 1; continue; } + if (!strcmp(arg, "-r")) { + desperate = 1; + continue; + } usage(unpack_usage); } @@ -306,5 +323,5 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix) /* All done */ if (!quiet) fprintf(stderr, "\n"); - return 0; + return has_errors; } From 3b67d2917a0e93aa583c4069f5a00655e05dbd84 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 13 Sep 2006 12:59:20 -0700 Subject: [PATCH 2/2] unpack-objects -r: call it "recover". The code called this operation "desperate" but the option flag is -r and the word "recover" describes what it does better. Signed-off-by: Junio C Hamano --- Documentation/git-unpack-objects.txt | 2 +- builtin-unpack-objects.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/git-unpack-objects.txt b/Documentation/git-unpack-objects.txt index 415c09ba10..ff6184b0f7 100644 --- a/Documentation/git-unpack-objects.txt +++ b/Documentation/git-unpack-objects.txt @@ -37,7 +37,7 @@ OPTIONS -r:: When unpacking a corrupt packfile, the command dies at the first corruption. This flag tells it to keep going - and make the best effort to salvage as many objects as + and make the best effort to recover as many objects as possible. diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index 5f9c0d2f9e..4f96bcae32 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -10,8 +10,8 @@ #include -static int dry_run, quiet, desperate, has_errors; -static const char unpack_usage[] = "git-unpack-objects [-n] [-q] < pack-file"; +static int dry_run, quiet, recover, has_errors; +static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file"; /* We always read in 4kB chunks. */ static unsigned char buffer[4096]; @@ -75,7 +75,7 @@ static void *get_data(unsigned long size) error("inflate returned %d\n", ret); free(buf); buf = NULL; - if (!desperate) + if (!recover) exit(1); has_errors = 1; break; @@ -192,7 +192,7 @@ static void unpack_delta_entry(unsigned long delta_size) if (!base) { error("failed to read delta-pack base object %s", sha1_to_hex(base_sha1)); - if (!desperate) + if (!recover) exit(1); has_errors = 1; return; @@ -247,7 +247,7 @@ static void unpack_one(unsigned nr, unsigned total) default: error("bad object type %d", type); has_errors = 1; - if (desperate) + if (recover) return; exit(1); } @@ -294,7 +294,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "-r")) { - desperate = 1; + recover = 1; continue; } usage(unpack_usage);