recv_sideband: Bands #2 and #3 always go to stderr
[gitweb.git] / index-pack.c
index 745ac0bfa02aafc00b3379011259a6bfc5a47f7b..7fee8725333860dbbd13d8de5ae7baf1ef33976d 100644 (file)
@@ -8,6 +8,7 @@
 #include "tree.h"
 #include "progress.h"
 #include "fsck.h"
+#include "exec_cmd.h"
 
 static const char index_pack_usage[] =
 "git index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
@@ -67,7 +68,7 @@ static struct progress *progress;
 static unsigned char input_buffer[4096];
 static unsigned int input_offset, input_len;
 static off_t consumed_bytes;
-static SHA_CTX input_ctx;
+static git_SHA_CTX input_ctx;
 static uint32_t input_crc32;
 static int input_fd, output_fd, pack_fd;
 
@@ -119,7 +120,7 @@ static void flush(void)
        if (input_offset) {
                if (output_fd >= 0)
                        write_or_die(output_fd, input_buffer, input_offset);
-               SHA1_Update(&input_ctx, input_buffer, input_offset);
+               git_SHA1_Update(&input_ctx, input_buffer, input_offset);
                memmove(input_buffer, input_buffer + input_offset, input_len);
                input_offset = 0;
        }
@@ -177,7 +178,7 @@ static char *open_pack_file(char *pack_name)
                } else
                        output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
                if (output_fd < 0)
-                       die("unable to create %s: %s\n", pack_name, strerror(errno));
+                       die("unable to create %s: %s", pack_name, strerror(errno));
                pack_fd = output_fd;
        } else {
                input_fd = open(pack_name, O_RDONLY);
@@ -187,7 +188,7 @@ static char *open_pack_file(char *pack_name)
                output_fd = -1;
                pack_fd = input_fd;
        }
-       SHA1_Init(&input_ctx);
+       git_SHA1_Init(&input_ctx);
        return pack_name;
 }
 
@@ -220,17 +221,23 @@ static void bad_object(unsigned long offset, const char *format, ...)
        die("pack has bad object at offset %lu: %s", offset, buf);
 }
 
+static void free_base_data(struct base_data *c)
+{
+       if (c->data) {
+               free(c->data);
+               c->data = NULL;
+               base_cache_used -= c->size;
+       }
+}
+
 static void prune_base_data(struct base_data *retain)
 {
        struct base_data *b = base_cache;
        for (b = base_cache;
             base_cache_used > delta_base_cache_limit && b;
             b = b->child) {
-               if (b->data && b != retain) {
-                       free(b->data);
-                       b->data = NULL;
-                       base_cache_used -= b->size;
-               }
+               if (b->data && b != retain)
+                       free_base_data(b);
        }
 }
 
@@ -243,7 +250,8 @@ static void link_base_data(struct base_data *base, struct base_data *c)
 
        c->base = base;
        c->child = NULL;
-       base_cache_used += c->size;
+       if (c->data)
+               base_cache_used += c->size;
        prune_base_data(c);
 }
 
@@ -254,10 +262,7 @@ static void unlink_base_data(struct base_data *c)
                base->child = NULL;
        else
                base_cache = NULL;
-       if (c->data) {
-               free(c->data);
-               base_cache_used -= c->size;
-       }
+       free_base_data(c);
 }
 
 static void *unpack_entry_data(unsigned long offset, unsigned long size)
@@ -270,10 +275,10 @@ static void *unpack_entry_data(unsigned long offset, unsigned long size)
        stream.avail_out = size;
        stream.next_in = fill(1);
        stream.avail_in = input_len;
-       inflateInit(&stream);
+       git_inflate_init(&stream);
 
        for (;;) {
-               int ret = inflate(&stream, 0);
+               int ret = git_inflate(&stream, 0);
                use(input_len - stream.avail_in);
                if (stream.total_out == size && ret == Z_STREAM_END)
                        break;
@@ -282,7 +287,7 @@ static void *unpack_entry_data(unsigned long offset, unsigned long size)
                stream.next_in = fill(1);
                stream.avail_in = input_len;
        }
-       inflateEnd(&stream);
+       git_inflate_end(&stream);
        return buf;
 }
 
@@ -333,7 +338,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
                        base_offset = (base_offset << 7) + (c & 127);
                }
                delta_base->offset = obj->idx.offset - base_offset;
-               if (delta_base->offset >= obj->idx.offset)
+               if (delta_base->offset <= 0 || delta_base->offset >= obj->idx.offset)
                        bad_object(obj->idx.offset, "delta base offset is out of bound");
                break;
        case OBJ_COMMIT:
@@ -377,9 +382,9 @@ static void *get_data_from_pack(struct object_entry *obj)
        stream.avail_out = obj->size;
        stream.next_in = src;
        stream.avail_in = len;
-       inflateInit(&stream);
-       while ((st = inflate(&stream, Z_FINISH)) == Z_OK);
-       inflateEnd(&stream);
+       git_inflate_init(&stream);
+       while ((st = git_inflate(&stream, Z_FINISH)) == Z_OK);
+       git_inflate_end(&stream);
        if (st != Z_STREAM_END || stream.total_out != obj->size)
                die("serious inflate inconsistency");
        free(src);
@@ -407,22 +412,24 @@ static int find_delta(const union delta_base *base)
         return -first-1;
 }
 
-static int find_delta_children(const union delta_base *base,
-                              int *first_index, int *last_index)
+static void find_delta_children(const union delta_base *base,
+                               int *first_index, int *last_index)
 {
        int first = find_delta(base);
        int last = first;
        int end = nr_deltas - 1;
 
-       if (first < 0)
-               return -1;
+       if (first < 0) {
+               *first_index = 0;
+               *last_index = -1;
+               return;
+       }
        while (first > 0 && !memcmp(&deltas[first - 1].base, base, UNION_BASE_SZ))
                --first;
        while (last < end && !memcmp(&deltas[last + 1].base, base, UNION_BASE_SZ))
                ++last;
        *first_index = first;
        *last_index = last;
-       return 0;
 }
 
 static void sha1_object(const void *data, unsigned long size,
@@ -493,8 +500,10 @@ static void *get_base_data(struct base_data *c)
                        free(raw);
                        if (!c->data)
                                bad_object(obj->idx.offset, "failed to apply delta");
-               } else
+               } else {
                        c->data = get_data_from_pack(obj);
+                       c->size = obj->size;
+               }
 
                base_cache_used += c->size;
                prune_base_data(c);
@@ -503,49 +512,74 @@ static void *get_base_data(struct base_data *c)
 }
 
 static void resolve_delta(struct object_entry *delta_obj,
-                         struct base_data *base_obj, enum object_type type)
+                         struct base_data *base, struct base_data *result)
 {
-       void *delta_data;
-       unsigned long delta_size;
-       union delta_base delta_base;
-       int j, first, last;
-       struct base_data result;
+       void *base_data, *delta_data;
 
-       delta_obj->real_type = type;
+       delta_obj->real_type = base->obj->real_type;
        delta_data = get_data_from_pack(delta_obj);
-       delta_size = delta_obj->size;
-       result.data = patch_delta(get_base_data(base_obj), base_obj->size,
-                            delta_data, delta_size,
-                            &result.size);
+       base_data = get_base_data(base);
+       result->obj = delta_obj;
+       result->data = patch_delta(base_data, base->size,
+                                  delta_data, delta_obj->size, &result->size);
        free(delta_data);
-       if (!result.data)
+       if (!result->data)
                bad_object(delta_obj->idx.offset, "failed to apply delta");
-       sha1_object(result.data, result.size, type, delta_obj->idx.sha1);
+       sha1_object(result->data, result->size, delta_obj->real_type,
+                   delta_obj->idx.sha1);
        nr_resolved_deltas++;
+}
 
-       result.obj = delta_obj;
-       link_base_data(base_obj, &result);
+static void find_unresolved_deltas(struct base_data *base,
+                                  struct base_data *prev_base)
+{
+       int i, ref_first, ref_last, ofs_first, ofs_last;
+
+       /*
+        * This is a recursive function. Those brackets should help reducing
+        * stack usage by limiting the scope of the delta_base union.
+        */
+       {
+               union delta_base base_spec;
+
+               hashcpy(base_spec.sha1, base->obj->idx.sha1);
+               find_delta_children(&base_spec, &ref_first, &ref_last);
+
+               memset(&base_spec, 0, sizeof(base_spec));
+               base_spec.offset = base->obj->idx.offset;
+               find_delta_children(&base_spec, &ofs_first, &ofs_last);
+       }
+
+       if (ref_last == -1 && ofs_last == -1) {
+               free(base->data);
+               return;
+       }
+
+       link_base_data(prev_base, base);
 
-       hashcpy(delta_base.sha1, delta_obj->idx.sha1);
-       if (!find_delta_children(&delta_base, &first, &last)) {
-               for (j = first; j <= last; j++) {
-                       struct object_entry *child = objects + deltas[j].obj_no;
-                       if (child->real_type == OBJ_REF_DELTA)
-                               resolve_delta(child, &result, type);
+       for (i = ref_first; i <= ref_last; i++) {
+               struct object_entry *child = objects + deltas[i].obj_no;
+               if (child->real_type == OBJ_REF_DELTA) {
+                       struct base_data result;
+                       resolve_delta(child, base, &result);
+                       if (i == ref_last && ofs_last == -1)
+                               free_base_data(base);
+                       find_unresolved_deltas(&result, base);
                }
        }
 
-       memset(&delta_base, 0, sizeof(delta_base));
-       delta_base.offset = delta_obj->idx.offset;
-       if (!find_delta_children(&delta_base, &first, &last)) {
-               for (j = first; j <= last; j++) {
-                       struct object_entry *child = objects + deltas[j].obj_no;
-                       if (child->real_type == OBJ_OFS_DELTA)
-                               resolve_delta(child, &result, type);
+       for (i = ofs_first; i <= ofs_last; i++) {
+               struct object_entry *child = objects + deltas[i].obj_no;
+               if (child->real_type == OBJ_OFS_DELTA) {
+                       struct base_data result;
+                       resolve_delta(child, base, &result);
+                       if (i == ofs_last)
+                               free_base_data(base);
+                       find_unresolved_deltas(&result, base);
                }
        }
 
-       unlink_base_data(&result);
+       unlink_base_data(base);
 }
 
 static int compare_delta_entry(const void *a, const void *b)
@@ -590,7 +624,7 @@ static void parse_pack_objects(unsigned char *sha1)
 
        /* Check pack integrity */
        flush();
-       SHA1_Final(sha1, &input_ctx);
+       git_SHA1_Final(sha1, &input_ctx);
        if (hashcmp(fill(20), sha1))
                die("pack is corrupted (SHA1 mismatch)");
        use(20);
@@ -621,37 +655,13 @@ static void parse_pack_objects(unsigned char *sha1)
                progress = start_progress("Resolving deltas", nr_deltas);
        for (i = 0; i < nr_objects; i++) {
                struct object_entry *obj = &objects[i];
-               union delta_base base;
-               int j, ref, ref_first, ref_last, ofs, ofs_first, ofs_last;
                struct base_data base_obj;
 
                if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA)
                        continue;
-               hashcpy(base.sha1, obj->idx.sha1);
-               ref = !find_delta_children(&base, &ref_first, &ref_last);
-               memset(&base, 0, sizeof(base));
-               base.offset = obj->idx.offset;
-               ofs = !find_delta_children(&base, &ofs_first, &ofs_last);
-               if (!ref && !ofs)
-                       continue;
-               base_obj.data = get_data_from_pack(obj);
-               base_obj.size = obj->size;
                base_obj.obj = obj;
-               link_base_data(NULL, &base_obj);
-
-               if (ref)
-                       for (j = ref_first; j <= ref_last; j++) {
-                               struct object_entry *child = objects + deltas[j].obj_no;
-                               if (child->real_type == OBJ_REF_DELTA)
-                                       resolve_delta(child, &base_obj, obj->type);
-                       }
-               if (ofs)
-                       for (j = ofs_first; j <= ofs_last; j++) {
-                               struct object_entry *child = objects + deltas[j].obj_no;
-                               if (child->real_type == OBJ_OFS_DELTA)
-                                       resolve_delta(child, &base_obj, obj->type);
-                       }
-               unlink_base_data(&base_obj);
+               base_obj.data = NULL;
+               find_unresolved_deltas(&base_obj, NULL);
                display_progress(progress, nr_resolved_deltas);
        }
 }
@@ -744,7 +754,6 @@ static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved)
        for (i = 0; i < n; i++) {
                struct delta_entry *d = sorted_by_pos[i];
                enum object_type type;
-               int j, first, last;
                struct base_data base_obj;
 
                if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
@@ -758,16 +767,7 @@ static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved)
                        die("local object %s is corrupt", sha1_to_hex(d->base.sha1));
                base_obj.obj = append_obj_to_pack(f, d->base.sha1,
                                        base_obj.data, base_obj.size, type);
-               link_base_data(NULL, &base_obj);
-
-               find_delta_children(&d->base, &first, &last);
-               for (j = first; j <= last; j++) {
-                       struct object_entry *child = objects + deltas[j].obj_no;
-                       if (child->real_type == OBJ_REF_DELTA)
-                               resolve_delta(child, &base_obj, type);
-               }
-
-               unlink_base_data(&base_obj);
+               find_unresolved_deltas(&base_obj, NULL);
                display_progress(progress, nr_resolved_deltas);
        }
        free(sorted_by_pos);
@@ -789,7 +789,6 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                err = close(output_fd);
                if (err)
                        die("error while closing pack file: %s", strerror(errno));
-               chmod(curr_pack_name, 0444);
        }
 
        if (keep_msg) {
@@ -825,8 +824,9 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                if (move_temp_to_file(curr_pack_name, final_pack_name))
                        die("cannot store pack file");
        }
+       if (from_stdin)
+               chmod(final_pack_name, 0444);
 
-       chmod(curr_index_name, 0444);
        if (final_index_name != curr_index_name) {
                if (!final_index_name) {
                        snprintf(name, sizeof(name), "%s/pack/pack-%s.idx",
@@ -836,6 +836,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                if (move_temp_to_file(curr_index_name, final_index_name))
                        die("cannot store index file");
        }
+       chmod(final_index_name, 0444);
 
        if (!from_stdin) {
                printf("%s\n", sha1_to_hex(sha1));
@@ -881,6 +882,8 @@ int main(int argc, char **argv)
        struct pack_idx_entry **idx_objects;
        unsigned char pack_sha1[20];
 
+       git_extract_argv0_path(argv[0]);
+
        /*
         * We wish to read the repository's config file if any, and
         * for that it is necessary to call setup_git_directory_gently().