pack-check.con commit Merge branch 'jc/nodelta' (96cbd57)
   1#include "cache.h"
   2#include "pack.h"
   3
   4static int verify_packfile(struct packed_git *p,
   5                struct pack_window **w_curs)
   6{
   7        off_t index_size = p->index_size;
   8        const unsigned char *index_base = p->index_data;
   9        SHA_CTX ctx;
  10        unsigned char sha1[20];
  11        off_t offset = 0, pack_sig = p->pack_size - 20;
  12        uint32_t nr_objects, i;
  13        int err;
  14
  15        /* Note that the pack header checks are actually performed by
  16         * use_pack when it first opens the pack file.  If anything
  17         * goes wrong during those checks then the call will die out
  18         * immediately.
  19         */
  20
  21        SHA1_Init(&ctx);
  22        while (offset < pack_sig) {
  23                unsigned int remaining;
  24                unsigned char *in = use_pack(p, w_curs, offset, &remaining);
  25                offset += remaining;
  26                if (offset > pack_sig)
  27                        remaining -= (unsigned int)(offset - pack_sig);
  28                SHA1_Update(&ctx, in, remaining);
  29        }
  30        SHA1_Final(sha1, &ctx);
  31        if (hashcmp(sha1, use_pack(p, w_curs, pack_sig, NULL)))
  32                return error("Packfile %s SHA1 mismatch with itself",
  33                             p->pack_name);
  34        if (hashcmp(sha1, index_base + index_size - 40))
  35                return error("Packfile %s SHA1 mismatch with idx",
  36                             p->pack_name);
  37        unuse_pack(w_curs);
  38
  39        /* Make sure everything reachable from idx is valid.  Since we
  40         * have verified that nr_objects matches between idx and pack,
  41         * we do not do scan-streaming check on the pack file.
  42         */
  43        nr_objects = p->num_objects;
  44        for (i = 0, err = 0; i < nr_objects; i++) {
  45                const unsigned char *sha1;
  46                void *data;
  47                enum object_type type;
  48                unsigned long size;
  49                off_t offset;
  50
  51                sha1 = nth_packed_object_sha1(p, i);
  52                if (!sha1)
  53                        die("internal error pack-check nth-packed-object");
  54                offset = find_pack_entry_one(sha1, p);
  55                if (!offset)
  56                        die("internal error pack-check find-pack-entry-one");
  57                data = unpack_entry(p, offset, &type, &size);
  58                if (!data) {
  59                        err = error("cannot unpack %s from %s",
  60                                    sha1_to_hex(sha1), p->pack_name);
  61                        continue;
  62                }
  63                if (check_sha1_signature(sha1, data, size, typename(type))) {
  64                        err = error("packed %s from %s is corrupt",
  65                                    sha1_to_hex(sha1), p->pack_name);
  66                        free(data);
  67                        continue;
  68                }
  69                free(data);
  70        }
  71
  72        return err;
  73}
  74
  75
  76#define MAX_CHAIN 50
  77
  78static void show_pack_info(struct packed_git *p)
  79{
  80        uint32_t nr_objects, i, chain_histogram[MAX_CHAIN+1];
  81        nr_objects = p->num_objects;
  82        memset(chain_histogram, 0, sizeof(chain_histogram));
  83
  84        for (i = 0; i < nr_objects; i++) {
  85                const unsigned char *sha1;
  86                unsigned char base_sha1[20];
  87                const char *type;
  88                unsigned long size;
  89                unsigned long store_size;
  90                off_t offset;
  91                unsigned int delta_chain_length;
  92
  93                sha1 = nth_packed_object_sha1(p, i);
  94                if (!sha1)
  95                        die("internal error pack-check nth-packed-object");
  96                offset = find_pack_entry_one(sha1, p);
  97                if (!offset)
  98                        die("internal error pack-check find-pack-entry-one");
  99
 100                type = packed_object_info_detail(p, offset, &size, &store_size,
 101                                                 &delta_chain_length,
 102                                                 base_sha1);
 103                printf("%s ", sha1_to_hex(sha1));
 104                if (!delta_chain_length)
 105                        printf("%-6s %lu %"PRIuMAX"\n",
 106                               type, size, (uintmax_t)offset);
 107                else {
 108                        printf("%-6s %lu %"PRIuMAX" %u %s\n",
 109                               type, size, (uintmax_t)offset,
 110                               delta_chain_length, sha1_to_hex(base_sha1));
 111                        if (delta_chain_length <= MAX_CHAIN)
 112                                chain_histogram[delta_chain_length]++;
 113                        else
 114                                chain_histogram[0]++;
 115                }
 116        }
 117
 118        for (i = 0; i <= MAX_CHAIN; i++) {
 119                if (!chain_histogram[i])
 120                        continue;
 121                printf("chain length = %d: %d object%s\n", i,
 122                       chain_histogram[i], chain_histogram[i] > 1 ? "s" : "");
 123        }
 124        if (chain_histogram[0])
 125                printf("chain length > %d: %d object%s\n", MAX_CHAIN,
 126                       chain_histogram[0], chain_histogram[0] > 1 ? "s" : "");
 127}
 128
 129int verify_pack(struct packed_git *p, int verbose)
 130{
 131        off_t index_size = p->index_size;
 132        const unsigned char *index_base = p->index_data;
 133        SHA_CTX ctx;
 134        unsigned char sha1[20];
 135        int ret;
 136
 137        ret = 0;
 138        /* Verify SHA1 sum of the index file */
 139        SHA1_Init(&ctx);
 140        SHA1_Update(&ctx, index_base, (unsigned int)(index_size - 20));
 141        SHA1_Final(sha1, &ctx);
 142        if (hashcmp(sha1, index_base + index_size - 20))
 143                ret = error("Packfile index for %s SHA1 mismatch",
 144                            p->pack_name);
 145
 146        if (!ret) {
 147                /* Verify pack file */
 148                struct pack_window *w_curs = NULL;
 149                ret = verify_packfile(p, &w_curs);
 150                unuse_pack(&w_curs);
 151        }
 152
 153        if (verbose) {
 154                if (ret)
 155                        printf("%s: bad\n", p->pack_name);
 156                else {
 157                        show_pack_info(p);
 158                        printf("%s: ok\n", p->pack_name);
 159                }
 160        }
 161
 162        return ret;
 163}