Documentation: help: explain 'man.viewer' multiple values
[gitweb.git] / builtin-unpack-objects.c
index 3956c5633448a5c29c60cad370ec7da6a8bfeb64..50e07faa12f495b3270e1446573b88a255336877 100644 (file)
@@ -7,15 +7,30 @@
 #include "commit.h"
 #include "tag.h"
 #include "tree.h"
+#include "progress.h"
+#include "decorate.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 unsigned int offset, len;
+static off_t consumed_bytes;
 static SHA_CTX ctx;
 
+struct obj_buffer {
+       char *buffer;
+       unsigned long size;
+};
+
+static struct decoration obj_decorate;
+
+static struct obj_buffer *lookup_object_buffer(struct object *base)
+{
+       return lookup_decoration(&obj_decorate, base);
+}
+
 /*
  * Make sure at least "min" bytes are available in the buffer, and
  * return the pointer to the buffer.
@@ -32,7 +47,7 @@ static void *fill(int min)
                offset = 0;
        }
        do {
-               int ret = xread(0, buffer + len, sizeof(buffer) - len);
+               ssize_t ret = xread(0, buffer + len, sizeof(buffer) - len);
                if (ret <= 0) {
                        if (!ret)
                                die("early EOF");
@@ -49,6 +64,10 @@ static void use(int bytes)
                die("used more bytes than were available");
        len -= bytes;
        offset += bytes;
+
+       /* make sure off_t is sufficiently large not to wrap */
+       if (consumed_bytes > consumed_bytes + bytes)
+               die("pack too large for current definition of off_t");
        consumed_bytes += bytes;
 }
 
@@ -88,17 +107,17 @@ static void *get_data(unsigned long size)
 
 struct delta_info {
        unsigned char base_sha1[20];
-       unsigned long base_offset;
+       unsigned nr;
+       off_t 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,
+                             off_t base_offset,
                              void *delta, unsigned long size)
 {
        struct delta_info *info = xmalloc(sizeof(*info));
@@ -113,7 +132,7 @@ static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
 }
 
 struct obj_info {
-       unsigned long offset;
+       off_t offset;
        unsigned char sha1[20];
 };
 
@@ -183,6 +202,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
        void *delta_data, *base;
        unsigned long base_size;
        unsigned char base_sha1[20];
+       struct object *obj;
 
        if (type == OBJ_REF_DELTA) {
                hashcpy(base_sha1, fill(20));
@@ -200,7 +220,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
        } else {
                unsigned base_found = 0;
                unsigned char *pack, c;
-               unsigned long base_offset;
+               off_t base_offset;
                unsigned lo, mid, hi;
 
                pack = fill(1);
@@ -209,7 +229,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                base_offset = c & 127;
                while (c & 128) {
                        base_offset += 1;
-                       if (!base_offset || base_offset & ~(~0UL >> 7))
+                       if (!base_offset || MSB(base_offset, 7))
                                die("offset value overflow for delta base object");
                        pack = fill(1);
                        c = *pack;
@@ -246,6 +266,15 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                }
        }
 
+       obj = lookup_object(base_sha1);
+       if (obj) {
+               struct obj_buffer *obj_buf = lookup_object_buffer(obj);
+               if (obj_buf) {
+                       resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, 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",
@@ -259,7 +288,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
        free(base);
 }
 
-static void unpack_one(unsigned nr, unsigned total)
+static void unpack_one(unsigned nr)
 {
        unsigned shift;
        unsigned char *pack, c;
@@ -281,20 +310,7 @@ static void unpack_one(unsigned nr, unsigned total)
                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:
@@ -318,6 +334,7 @@ static void unpack_one(unsigned nr, unsigned total)
 static void unpack_all(void)
 {
        int i;
+       struct progress *progress = NULL;
        struct pack_header *hdr = fill(sizeof(struct pack_header));
        unsigned nr_objects = ntohl(hdr->hdr_entries);
 
@@ -325,12 +342,17 @@ static void unpack_all(void)
                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);
+       use(sizeof(struct pack_header));
 
+       if (!quiet)
+               progress = start_progress("Unpacking objects", 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);
+       for (i = 0; i < nr_objects; i++) {
+               unpack_one(i);
+               display_progress(progress, i + 1);
+       }
+       stop_progress(&progress);
+
        if (delta_list)
                die("unresolved deltas left after unpacking");
 }
@@ -399,7 +421,5 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
        }
 
        /* All done */
-       if (!quiet)
-               fprintf(stderr, "\n");
        return has_errors;
 }