diff options
Diffstat (limited to 'unpack-objects.c')
-rw-r--r-- | unpack-objects.c | 65 |
1 files changed, 41 insertions, 24 deletions
diff --git a/unpack-objects.c b/unpack-objects.c index 57f3c9b6bb..98b696cf2c 100644 --- a/unpack-objects.c +++ b/unpack-objects.c @@ -1,6 +1,7 @@ #include "cache.h" #include "object.h" #include "delta.h" +#include "pack.h" static int dry_run; static int nr_entries; @@ -92,7 +93,7 @@ static int check_index(void) } static int unpack_non_delta_entry(struct pack_entry *entry, - int kind, + enum object_type kind, unsigned char *data, unsigned long size, unsigned long left) @@ -101,9 +102,9 @@ static int unpack_non_delta_entry(struct pack_entry *entry, z_stream stream; char *buffer; unsigned char sha1[20]; - char *type_s; + char *type; - printf("%s %c %lu\n", sha1_to_hex(entry->sha1), kind, size); + printf("%s %c %lu\n", sha1_to_hex(entry->sha1), ".CTBGD"[kind], size); if (dry_run) return 0; @@ -121,18 +122,18 @@ static int unpack_non_delta_entry(struct pack_entry *entry, if ((st != Z_STREAM_END) || stream.total_out != size) goto err_finish; switch (kind) { - case 'C': type_s = "commit"; break; - case 'T': type_s = "tree"; break; - case 'B': type_s = "blob"; break; - case 'G': type_s = "tag"; break; + case OBJ_COMMIT: type = "commit"; break; + case OBJ_TREE: type = "tree"; break; + case OBJ_BLOB: type = "blob"; break; + case OBJ_TAG: type = "tag"; break; default: goto err_finish; } - if (write_sha1_file(buffer, size, type_s, sha1) < 0) + if (write_sha1_file(buffer, size, type, sha1) < 0) die("failed to write %s (%s)", - sha1_to_hex(entry->sha1), type_s); - printf("%s %s\n", sha1_to_hex(sha1), type_s); + sha1_to_hex(entry->sha1), type); + printf("%s %s\n", sha1_to_hex(sha1), type); if (memcmp(sha1, entry->sha1, 20)) - die("resulting %s have wrong SHA1", type_s); + die("resulting %s have wrong SHA1", type); finish: st = 0; @@ -237,28 +238,44 @@ static int unpack_delta_entry(struct pack_entry *entry, static void unpack_entry(struct pack_entry *entry) { unsigned long offset, size, left; - unsigned char *pack; + unsigned char *pack, c; + int type; /* Have we done this one already due to deltas based on it? */ if (lookup_object(entry->sha1)) return; offset = ntohl(entry->offset); - if (offset > pack_size - 5) - die("object offset outside of pack file"); + if (offset >= pack_size) + goto bad; + pack = pack_base + offset; - size = (pack[1] << 24) + (pack[2] << 16) + (pack[3] << 8) + pack[4]; - left = pack_size - offset - 5; - switch (*pack) { - case 'C': case 'T': case 'B': case 'G': - unpack_non_delta_entry(entry, *pack, pack+5, size, left); - break; - case 'D': + c = *pack++; + offset++; + type = (c >> 4) & 7; + size = (c & 15); + while (c & 0x80) { + if (offset >= pack_size) + goto bad; + offset++; + c = *pack++; + size = (size << 7) + (c & 0x7f); + + } + left = pack_size - offset; + switch (type) { + case OBJ_COMMIT: + case OBJ_TREE: + case OBJ_BLOB: + case OBJ_TAG: + unpack_non_delta_entry(entry, type, pack, size, left); + return; + case OBJ_DELTA: unpack_delta_entry(entry, pack+5, size, left); - break; - default: - die("corrupted pack file"); + return; } +bad: + die("corrupted pack file"); } /* |