diff options
Diffstat (limited to 'builtin-unpack-objects.c')
-rw-r--r-- | builtin-unpack-objects.c | 405 |
1 files changed, 0 insertions, 405 deletions
diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c deleted file mode 100644 index 3956c56334..0000000000 --- a/builtin-unpack-objects.c +++ /dev/null @@ -1,405 +0,0 @@ -#include "builtin.h" -#include "cache.h" -#include "object.h" -#include "delta.h" -#include "pack.h" -#include "blob.h" -#include "commit.h" -#include "tag.h" -#include "tree.h" - -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]; -static unsigned long offset, len, consumed_bytes; -static SHA_CTX ctx; - -/* - * Make sure at least "min" bytes are available in the buffer, and - * return the pointer to the buffer. - */ -static void *fill(int min) -{ - if (min <= len) - return buffer + offset; - if (min > sizeof(buffer)) - die("cannot fill %d bytes", min); - if (offset) { - SHA1_Update(&ctx, buffer, offset); - memmove(buffer, buffer + offset, len); - offset = 0; - } - do { - int ret = xread(0, buffer + len, sizeof(buffer) - len); - if (ret <= 0) { - if (!ret) - die("early EOF"); - die("read error on input: %s", strerror(errno)); - } - len += ret; - } while (len < min); - return buffer; -} - -static void use(int bytes) -{ - if (bytes > len) - die("used more bytes than were available"); - len -= bytes; - offset += bytes; - consumed_bytes += bytes; -} - -static void *get_data(unsigned long size) -{ - z_stream stream; - void *buf = xmalloc(size); - - memset(&stream, 0, sizeof(stream)); - - stream.next_out = buf; - stream.avail_out = size; - stream.next_in = fill(1); - stream.avail_in = len; - inflateInit(&stream); - - for (;;) { - int ret = inflate(&stream, 0); - use(len - stream.avail_in); - if (stream.total_out == size && ret == Z_STREAM_END) - break; - if (ret != Z_OK) { - error("inflate returned %d\n", ret); - free(buf); - buf = NULL; - if (!recover) - exit(1); - has_errors = 1; - break; - } - stream.next_in = fill(1); - stream.avail_in = len; - } - inflateEnd(&stream); - return buf; -} - -struct delta_info { - unsigned char base_sha1[20]; - unsigned long base_offset; - unsigned long size; - void *delta; - unsigned nr; - struct delta_info *next; -}; - -static struct delta_info *delta_list; - -static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1, - unsigned long base_offset, - void *delta, unsigned long size) -{ - struct delta_info *info = xmalloc(sizeof(*info)); - - hashcpy(info->base_sha1, base_sha1); - info->base_offset = base_offset; - info->size = size; - info->delta = delta; - info->nr = nr; - info->next = delta_list; - delta_list = info; -} - -struct obj_info { - unsigned long offset; - unsigned char sha1[20]; -}; - -static struct obj_info *obj_list; - -static void added_object(unsigned nr, enum object_type type, - void *data, unsigned long size); - -static void write_object(unsigned nr, enum object_type type, - void *buf, unsigned long size) -{ - if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0) - die("failed to write object"); - added_object(nr, type, buf, size); -} - -static void resolve_delta(unsigned nr, enum object_type type, - void *base, unsigned long base_size, - void *delta, unsigned long delta_size) -{ - void *result; - unsigned long result_size; - - result = patch_delta(base, base_size, - delta, delta_size, - &result_size); - if (!result) - die("failed to apply delta"); - free(delta); - write_object(nr, type, result, result_size); - free(result); -} - -static void added_object(unsigned nr, enum object_type type, - void *data, unsigned long size) -{ - struct delta_info **p = &delta_list; - struct delta_info *info; - - while ((info = *p) != NULL) { - if (!hashcmp(info->base_sha1, obj_list[nr].sha1) || - info->base_offset == obj_list[nr].offset) { - *p = info->next; - p = &delta_list; - resolve_delta(info->nr, type, data, size, - info->delta, info->size); - free(info); - continue; - } - p = &info->next; - } -} - -static void unpack_non_delta_entry(enum object_type type, unsigned long size, - unsigned nr) -{ - void *buf = get_data(size); - - if (!dry_run && buf) - write_object(nr, type, buf, size); - free(buf); -} - -static void unpack_delta_entry(enum object_type type, unsigned long delta_size, - unsigned nr) -{ - void *delta_data, *base; - unsigned long base_size; - unsigned char base_sha1[20]; - - if (type == OBJ_REF_DELTA) { - hashcpy(base_sha1, fill(20)); - use(20); - delta_data = get_data(delta_size); - if (dry_run || !delta_data) { - free(delta_data); - return; - } - if (!has_sha1_file(base_sha1)) { - hashcpy(obj_list[nr].sha1, null_sha1); - add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size); - return; - } - } else { - unsigned base_found = 0; - unsigned char *pack, c; - unsigned long base_offset; - unsigned lo, mid, hi; - - pack = fill(1); - c = *pack; - use(1); - base_offset = c & 127; - while (c & 128) { - base_offset += 1; - if (!base_offset || base_offset & ~(~0UL >> 7)) - die("offset value overflow for delta base object"); - pack = fill(1); - c = *pack; - use(1); - base_offset = (base_offset << 7) + (c & 127); - } - base_offset = obj_list[nr].offset - base_offset; - - delta_data = get_data(delta_size); - if (dry_run || !delta_data) { - free(delta_data); - return; - } - lo = 0; - hi = nr; - while (lo < hi) { - mid = (lo + hi)/2; - if (base_offset < obj_list[mid].offset) { - hi = mid; - } else if (base_offset > obj_list[mid].offset) { - lo = mid + 1; - } else { - hashcpy(base_sha1, obj_list[mid].sha1); - base_found = !is_null_sha1(base_sha1); - break; - } - } - if (!base_found) { - /* The delta base object is itself a delta that - has not been resolved yet. */ - hashcpy(obj_list[nr].sha1, null_sha1); - add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size); - return; - } - } - - base = read_sha1_file(base_sha1, &type, &base_size); - if (!base) { - error("failed to read delta-pack base object %s", - sha1_to_hex(base_sha1)); - if (!recover) - exit(1); - has_errors = 1; - return; - } - resolve_delta(nr, type, base, base_size, delta_data, delta_size); - free(base); -} - -static void unpack_one(unsigned nr, unsigned total) -{ - unsigned shift; - unsigned char *pack, c; - unsigned long size; - enum object_type type; - - obj_list[nr].offset = consumed_bytes; - - pack = fill(1); - c = *pack; - use(1); - type = (c >> 4) & 7; - size = (c & 15); - shift = 4; - while (c & 0x80) { - pack = fill(1); - c = *pack; - use(1); - size += (c & 0x7f) << shift; - shift += 7; - } - if (!quiet) { - static unsigned long last_sec; - static unsigned last_percent; - struct timeval now; - unsigned percentage = ((nr+1) * 100) / total; - - gettimeofday(&now, NULL); - if (percentage != last_percent || now.tv_sec != last_sec) { - last_sec = now.tv_sec; - last_percent = percentage; - fprintf(stderr, "%4u%% (%u/%u) done\r", - percentage, (nr+1), total); - } - } - switch (type) { - case OBJ_COMMIT: - case OBJ_TREE: - case OBJ_BLOB: - case OBJ_TAG: - unpack_non_delta_entry(type, size, nr); - return; - case OBJ_REF_DELTA: - case OBJ_OFS_DELTA: - unpack_delta_entry(type, size, nr); - return; - default: - error("bad object type %d", type); - has_errors = 1; - if (recover) - return; - exit(1); - } -} - -static void unpack_all(void) -{ - int i; - struct pack_header *hdr = fill(sizeof(struct pack_header)); - unsigned nr_objects = ntohl(hdr->hdr_entries); - - if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE) - die("bad pack file"); - if (!pack_version_ok(hdr->hdr_version)) - die("unknown pack file version %d", ntohl(hdr->hdr_version)); - fprintf(stderr, "Unpacking %d objects\n", nr_objects); - - obj_list = xmalloc(nr_objects * sizeof(*obj_list)); - use(sizeof(struct pack_header)); - for (i = 0; i < nr_objects; i++) - unpack_one(i, nr_objects); - if (delta_list) - die("unresolved deltas left after unpacking"); -} - -int cmd_unpack_objects(int argc, const char **argv, const char *prefix) -{ - int i; - unsigned char sha1[20]; - - git_config(git_default_config); - - quiet = !isatty(2); - - for (i = 1 ; i < argc; i++) { - const char *arg = argv[i]; - - if (*arg == '-') { - if (!strcmp(arg, "-n")) { - dry_run = 1; - continue; - } - if (!strcmp(arg, "-q")) { - quiet = 1; - continue; - } - if (!strcmp(arg, "-r")) { - recover = 1; - continue; - } - if (!prefixcmp(arg, "--pack_header=")) { - struct pack_header *hdr; - char *c; - - hdr = (struct pack_header *)buffer; - hdr->hdr_signature = htonl(PACK_SIGNATURE); - hdr->hdr_version = htonl(strtoul(arg + 14, &c, 10)); - if (*c != ',') - die("bad %s", arg); - hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10)); - if (*c) - die("bad %s", arg); - len = sizeof(*hdr); - continue; - } - usage(unpack_usage); - } - - /* We don't take any non-flag arguments now.. Maybe some day */ - usage(unpack_usage); - } - SHA1_Init(&ctx); - unpack_all(); - SHA1_Update(&ctx, buffer, offset); - SHA1_Final(sha1, &ctx); - if (hashcmp(fill(20), sha1)) - die("final sha1 did not match"); - use(20); - - /* Write the last part of the buffer to stdout */ - while (len) { - int ret = xwrite(1, buffer + offset, len); - if (ret <= 0) - break; - len -= ret; - offset += ret; - } - - /* All done */ - if (!quiet) - fprintf(stderr, "\n"); - return has_errors; -} |