pack-check.con commit Use uint32_t for all packed object counts. (326bf39)
   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        unsigned long index_size = p->index_size;
   8        void *index_base = p->index_base;
   9        SHA_CTX ctx;
  10        unsigned char sha1[20];
  11        unsigned long 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 -= 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, (unsigned char *)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 = num_packed_objects(p);
  44        for (i = 0, err = 0; i < nr_objects; i++) {
  45                unsigned char sha1[20];
  46                void *data;
  47                enum object_type type;
  48                unsigned long size, offset;
  49
  50                if (nth_packed_object_sha1(p, i, sha1))
  51                        die("internal error pack-check nth-packed-object");
  52                offset = find_pack_entry_one(sha1, p);
  53                if (!offset)
  54                        die("internal error pack-check find-pack-entry-one");
  55                data = unpack_entry(p, offset, &type, &size);
  56                if (!data) {
  57                        err = error("cannot unpack %s from %s",
  58                                    sha1_to_hex(sha1), p->pack_name);
  59                        continue;
  60                }
  61                if (check_sha1_signature(sha1, data, size, typename(type))) {
  62                        err = error("packed %s from %s is corrupt",
  63                                    sha1_to_hex(sha1), p->pack_name);
  64                        free(data);
  65                        continue;
  66                }
  67                free(data);
  68        }
  69
  70        return err;
  71}
  72
  73
  74#define MAX_CHAIN 40
  75
  76static void show_pack_info(struct packed_git *p)
  77{
  78        uint32_t nr_objects, i, chain_histogram[MAX_CHAIN];
  79
  80        nr_objects = num_packed_objects(p);
  81        memset(chain_histogram, 0, sizeof(chain_histogram));
  82
  83        for (i = 0; i < nr_objects; i++) {
  84                unsigned char sha1[20], base_sha1[20];
  85                const char *type;
  86                unsigned long size;
  87                unsigned long store_size;
  88                unsigned long offset;
  89                unsigned int delta_chain_length;
  90
  91                if (nth_packed_object_sha1(p, i, sha1))
  92                        die("internal error pack-check nth-packed-object");
  93                offset = find_pack_entry_one(sha1, p);
  94                if (!offset)
  95                        die("internal error pack-check find-pack-entry-one");
  96
  97                type = packed_object_info_detail(p, offset, &size, &store_size,
  98                                                 &delta_chain_length,
  99                                                 base_sha1);
 100                printf("%s ", sha1_to_hex(sha1));
 101                if (!delta_chain_length)
 102                        printf("%-6s %lu %lu\n", type, size, offset);
 103                else {
 104                        printf("%-6s %lu %lu %u %s\n", type, size, offset,
 105                               delta_chain_length, sha1_to_hex(base_sha1));
 106                        if (delta_chain_length < MAX_CHAIN)
 107                                chain_histogram[delta_chain_length]++;
 108                        else
 109                                chain_histogram[0]++;
 110                }
 111        }
 112
 113        for (i = 0; i < MAX_CHAIN; i++) {
 114                if (!chain_histogram[i])
 115                        continue;
 116                printf("chain length %s %d: %d object%s\n",
 117                       i ? "=" : ">=",
 118                       i ? i : MAX_CHAIN,
 119                       chain_histogram[i],
 120                       1 < chain_histogram[i] ? "s" : "");
 121        }
 122}
 123
 124int verify_pack(struct packed_git *p, int verbose)
 125{
 126        unsigned long index_size = p->index_size;
 127        void *index_base = p->index_base;
 128        SHA_CTX ctx;
 129        unsigned char sha1[20];
 130        int ret;
 131
 132        ret = 0;
 133        /* Verify SHA1 sum of the index file */
 134        SHA1_Init(&ctx);
 135        SHA1_Update(&ctx, index_base, index_size - 20);
 136        SHA1_Final(sha1, &ctx);
 137        if (hashcmp(sha1, (unsigned char *)index_base + index_size - 20))
 138                ret = error("Packfile index for %s SHA1 mismatch",
 139                            p->pack_name);
 140
 141        if (!ret) {
 142                /* Verify pack file */
 143                struct pack_window *w_curs = NULL;
 144                ret = verify_packfile(p, &w_curs);
 145                unuse_pack(&w_curs);
 146        }
 147
 148        if (verbose) {
 149                if (ret)
 150                        printf("%s: bad\n", p->pack_name);
 151                else {
 152                        show_pack_info(p);
 153                        printf("%s: ok\n", p->pack_name);
 154                }
 155        }
 156
 157        return ret;
 158}