index-pack --verify: read anomalous offsets from v2 idx file
[gitweb.git] / builtin / index-pack.c
index 4df681885e30c7c9256d298e3a1fa0b632012be6..513fbbc55f0ed438ab11e0bc23c2057690aefd36 100644 (file)
@@ -11,7 +11,7 @@
 #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>])";
+"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
 
 struct object_entry
 {
@@ -891,9 +891,80 @@ static int git_index_pack_config(const char *k, const char *v, void *cb)
        return git_default_config(k, v, cb);
 }
 
+static int cmp_uint32(const void *a_, const void *b_)
+{
+       uint32_t a = *((uint32_t *)a_);
+       uint32_t b = *((uint32_t *)b_);
+
+       return (a < b) ? -1 : (a != b);
+}
+
+static void read_v2_anomalous_offsets(struct packed_git *p,
+                                     struct pack_idx_option *opts)
+{
+       const uint32_t *idx1, *idx2;
+       uint32_t i;
+
+       /* The address of the 4-byte offset table */
+       idx1 = (((const uint32_t *)p->index_data)
+               + 2 /* 8-byte header */
+               + 256 /* fan out */
+               + 5 * p->num_objects /* 20-byte SHA-1 table */
+               + p->num_objects /* CRC32 table */
+               );
+
+       /* The address of the 8-byte offset table */
+       idx2 = idx1 + p->num_objects;
+
+       for (i = 0; i < p->num_objects; i++) {
+               uint32_t off = ntohl(idx1[i]);
+               if (!(off & 0x80000000))
+                       continue;
+               off = off & 0x7fffffff;
+               if (idx2[off * 2])
+                       continue;
+               /*
+                * The real offset is ntohl(idx2[off * 2]) in high 4
+                * octets, and ntohl(idx2[off * 2 + 1]) in low 4
+                * octets.  But idx2[off * 2] is Zero!!!
+                */
+               ALLOC_GROW(opts->anomaly, opts->anomaly_nr + 1, opts->anomaly_alloc);
+               opts->anomaly[opts->anomaly_nr++] = ntohl(idx2[off * 2 + 1]);
+       }
+
+       if (1 < opts->anomaly_nr)
+               qsort(opts->anomaly, opts->anomaly_nr, sizeof(uint32_t), cmp_uint32);
+}
+
+static void read_idx_option(struct pack_idx_option *opts, const char *pack_name)
+{
+       struct packed_git *p = add_packed_git(pack_name, strlen(pack_name), 1);
+
+       if (!p)
+               die("Cannot open existing pack file '%s'", pack_name);
+       if (open_pack_index(p))
+               die("Cannot open existing pack idx file for '%s'", pack_name);
+
+       /* Read the attributes from the existing idx file */
+       opts->version = p->index_version;
+
+       if (opts->version == 2)
+               read_v2_anomalous_offsets(p, opts);
+
+       /*
+        * Get rid of the idx file as we do not need it anymore.
+        * NEEDSWORK: extract this bit from free_pack_by_name() in
+        * sha1_file.c, perhaps?  It shouldn't matter very much as we
+        * know we haven't installed this pack (hence we never have
+        * read anything from it).
+        */
+       close_pack_index(p);
+       free(p);
+}
+
 int cmd_index_pack(int argc, const char **argv, const char *prefix)
 {
-       int i, fix_thin_pack = 0;
+       int i, fix_thin_pack = 0, verify = 0;
        const char *curr_pack, *curr_index;
        const char *index_name = NULL, *pack_name = NULL;
        const char *keep_name = NULL, *keep_msg = NULL;
@@ -922,6 +993,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                                fix_thin_pack = 1;
                        } else if (!strcmp(arg, "--strict")) {
                                strict = 1;
+                       } else if (!strcmp(arg, "--verify")) {
+                               verify = 1;
                        } else if (!strcmp(arg, "--keep")) {
                                keep_msg = "";
                        } else if (!prefixcmp(arg, "--keep=")) {
@@ -988,6 +1061,12 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
                strcpy(keep_name_buf + len - 5, ".keep");
                keep_name = keep_name_buf;
        }
+       if (verify) {
+               if (!index_name)
+                       die("--verify with no packfile name given");
+               read_idx_option(&opts, index_name);
+               opts.flags |= WRITE_IDX_VERIFY;
+       }
 
        curr_pack = open_pack_file(pack_name);
        parse_pack_header();
@@ -1038,10 +1117,13 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_sha1);
        free(idx_objects);
 
-       final(pack_name, curr_pack,
-               index_name, curr_index,
-               keep_name, keep_msg,
-               pack_sha1);
+       if (!verify)
+               final(pack_name, curr_pack,
+                     index_name, curr_index,
+                     keep_name, keep_msg,
+                     pack_sha1);
+       else
+               close(input_fd);
        free(objects);
        free(index_name_buf);
        free(keep_name_buf);