Merge branch 'maint' to sync with GIT 1.6.0.6
[gitweb.git] / builtin-pack-objects.c
index c05fb944b0e5d4d26cb2ba1995a787f08d5228ad..cedef52fd3d62a3dd2e439a46579362b22c69642 100644 (file)
@@ -71,6 +71,7 @@ static int reuse_delta = 1, reuse_object = 1;
 static int keep_unreachable, unpack_unreachable, include_tag;
 static int local;
 static int incremental;
+static int ignore_packed_keep;
 static int allow_ofs_delta;
 static const char *base_name;
 static int progress = 1;
@@ -245,8 +246,16 @@ static unsigned long write_object(struct sha1file *f,
        type = entry->type;
 
        /* write limit if limited packsize and not first object */
-       limit = pack_size_limit && nr_written ?
-                       pack_size_limit - write_offset : 0;
+       if (!pack_size_limit || !nr_written)
+               limit = 0;
+       else if (pack_size_limit <= write_offset)
+               /*
+                * the earlier object did not fit the limit; avoid
+                * mistaking this with unlimited (i.e. limit = 0).
+                */
+               limit = 1;
+       else
+               limit = pack_size_limit - write_offset;
 
        if (!entry->delta)
                usable_delta = 0;       /* no delta */
@@ -277,6 +286,7 @@ static unsigned long write_object(struct sha1file *f,
                                 */
 
        if (!to_reuse) {
+               no_reuse:
                if (!usable_delta) {
                        buf = read_sha1_file(entry->idx.sha1, &type, &size);
                        if (!buf)
@@ -358,46 +368,60 @@ static unsigned long write_object(struct sha1file *f,
                struct revindex_entry *revidx;
                off_t offset;
 
-               if (entry->delta) {
+               if (entry->delta)
                        type = (allow_ofs_delta && entry->delta->idx.offset) ?
                                OBJ_OFS_DELTA : OBJ_REF_DELTA;
-                       reused_delta++;
-               }
                hdrlen = encode_header(type, entry->size, header);
+
                offset = entry->in_pack_offset;
                revidx = find_pack_revindex(p, offset);
                datalen = revidx[1].offset - offset;
                if (!pack_to_stdout && p->index_version > 1 &&
-                   check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))
-                       die("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
+                   check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) {
+                       error("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
+                       unuse_pack(&w_curs);
+                       goto no_reuse;
+               }
+
                offset += entry->in_pack_header_size;
                datalen -= entry->in_pack_header_size;
+               if (!pack_to_stdout && p->index_version == 1 &&
+                   check_pack_inflate(p, &w_curs, offset, datalen, entry->size)) {
+                       error("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
+                       unuse_pack(&w_curs);
+                       goto no_reuse;
+               }
+
                if (type == OBJ_OFS_DELTA) {
                        off_t ofs = entry->idx.offset - entry->delta->idx.offset;
                        unsigned pos = sizeof(dheader) - 1;
                        dheader[pos] = ofs & 127;
                        while (ofs >>= 7)
                                dheader[--pos] = 128 | (--ofs & 127);
-                       if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit)
+                       if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
+                               unuse_pack(&w_curs);
                                return 0;
+                       }
                        sha1write(f, header, hdrlen);
                        sha1write(f, dheader + pos, sizeof(dheader) - pos);
                        hdrlen += sizeof(dheader) - pos;
+                       reused_delta++;
                } else if (type == OBJ_REF_DELTA) {
-                       if (limit && hdrlen + 20 + datalen + 20 >= limit)
+                       if (limit && hdrlen + 20 + datalen + 20 >= limit) {
+                               unuse_pack(&w_curs);
                                return 0;
+                       }
                        sha1write(f, header, hdrlen);
                        sha1write(f, entry->delta->idx.sha1, 20);
                        hdrlen += 20;
+                       reused_delta++;
                } else {
-                       if (limit && hdrlen + datalen + 20 >= limit)
+                       if (limit && hdrlen + datalen + 20 >= limit) {
+                               unuse_pack(&w_curs);
                                return 0;
+                       }
                        sha1write(f, header, hdrlen);
                }
-
-               if (!pack_to_stdout && p->index_version == 1 &&
-                   check_pack_inflate(p, &w_curs, offset, datalen, entry->size))
-                       die("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
                copy_pack_data(f, p, &w_curs, offset, datalen);
                unuse_pack(&w_curs);
                reused++;
@@ -511,6 +535,7 @@ static void write_pack_file(void)
 
                        snprintf(tmpname, sizeof(tmpname), "%s-%s.pack",
                                 base_name, sha1_to_hex(sha1));
+                       free_pack_by_name(tmpname);
                        if (adjust_perm(pack_tmp_name, mode))
                                die("unable to make temporary pack file readable: %s",
                                    strerror(errno));
@@ -690,6 +715,9 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
                return 0;
        }
 
+       if (!exclude && local && has_loose_object_nonlocal(sha1))
+               return 0;
+
        for (p = packed_git; p; p = p->next) {
                off_t offset = find_pack_entry_one(sha1, p);
                if (offset) {
@@ -703,6 +731,8 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
                                return 0;
                        if (local && !p->pack_local)
                                return 0;
+                       if (ignore_packed_keep && p->pack_local && p->pack_keep)
+                               return 0;
                }
        }
 
@@ -1053,6 +1083,8 @@ static void check_object(struct object_entry *entry)
                        if (reuse_delta && !entry->preferred_base) {
                                struct revindex_entry *revidx;
                                revidx = find_pack_revindex(p, ofs);
+                               if (!revidx)
+                                       goto give_up;
                                base_ref = nth_packed_object_sha1(p, revidx->nr);
                        }
                        entry->in_pack_header_size = used + used_0;
@@ -1072,6 +1104,7 @@ static void check_object(struct object_entry *entry)
                         */
                        entry->type = entry->in_pack_type;
                        entry->delta = base_entry;
+                       entry->delta_size = entry->size;
                        entry->delta_sibling = base_entry->delta_child;
                        base_entry->delta_child = entry;
                        unuse_pack(&w_curs);
@@ -2069,6 +2102,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                        incremental = 1;
                        continue;
                }
+               if (!strcmp("--honor-pack-keep", arg)) {
+                       ignore_packed_keep = 1;
+                       continue;
+               }
                if (!prefixcmp(arg, "--compression=")) {
                        char *end;
                        int level = strtoul(arg+14, &end, 0);