diff options
author | Junio C Hamano <junkio@cox.net> | 2006-09-04 09:55:54 +0400 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2006-09-04 13:42:00 +0400 |
commit | f986f2c830b24a0f56f2bf4b3f30353ca1e372a9 (patch) | |
tree | c6bcc444c0bcd81b6a4844034bde1a1bdaff248a | |
parent | f2e609473cb4aeb3884b7dd57a3a652df4e5edcf (diff) |
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 <junkio@cox.net>
-rw-r--r-- | Documentation/git-unpack-objects.txt | 8 | ||||
-rw-r--r-- | 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] <pack-file +'git-unpack-objects' [-n] [-q] [-r] <pack-file DESCRIPTION @@ -34,6 +34,12 @@ OPTIONS The command usually shows percentage progress. This flag suppresses it. +-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 + possible. + Author ------ diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index 0c180b53a3..5f9c0d2f9e 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -10,7 +10,7 @@ #include <sys/time.h> -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; } |