972916f4064386e033ada16e6badc3a174ef5b23
   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 pack_size = p->pack_size;
  12        void *pack_base;
  13        struct pack_header *hdr;
  14        int nr_objects, err, i;
  15
  16        /* Header consistency check */
  17        pack_base = use_pack(p, w_curs, 0, NULL);
  18        hdr = (struct pack_header*)pack_base;
  19        if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
  20                return error("Packfile %s signature mismatch", p->pack_name);
  21        if (!pack_version_ok(hdr->hdr_version))
  22                return error("Packfile version %d unsupported",
  23                             ntohl(hdr->hdr_version));
  24        nr_objects = ntohl(hdr->hdr_entries);
  25        if (num_packed_objects(p) != nr_objects)
  26                return error("Packfile claims to have %d objects, "
  27                             "while idx size expects %d", nr_objects,
  28                             num_packed_objects(p));
  29
  30        SHA1_Init(&ctx);
  31        SHA1_Update(&ctx, pack_base, pack_size - 20);
  32        SHA1_Final(sha1, &ctx);
  33        if (hashcmp(sha1, (unsigned char *)pack_base + pack_size - 20))
  34                return error("Packfile %s SHA1 mismatch with itself",
  35                             p->pack_name);
  36        if (hashcmp(sha1, (unsigned char *)index_base + index_size - 40))
  37                return error("Packfile %s SHA1 mismatch with idx",
  38                             p->pack_name);
  39
  40        /* Make sure everything reachable from idx is valid.  Since we
  41         * have verified that nr_objects matches between idx and pack,
  42         * we do not do scan-streaming check on the pack file.
  43         */
  44        for (i = err = 0; i < nr_objects; i++) {
  45                unsigned char sha1[20];
  46                void *data;
  47                char type[20];
  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, 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                struct pack_window **w_curs)
  78{
  79        struct pack_header *hdr;
  80        int nr_objects, i;
  81        unsigned int chain_histogram[MAX_CHAIN];
  82
  83        hdr = (struct pack_header*)use_pack(p, w_curs, 0, NULL);
  84        nr_objects = ntohl(hdr->hdr_entries);
  85        memset(chain_histogram, 0, sizeof(chain_histogram));
  86
  87        for (i = 0; i < nr_objects; i++) {
  88                unsigned char sha1[20], base_sha1[20];
  89                char type[20];
  90                unsigned long size;
  91                unsigned long store_size;
  92                unsigned long offset;
  93                unsigned int delta_chain_length;
  94
  95                if (nth_packed_object_sha1(p, i, sha1))
  96                        die("internal error pack-check nth-packed-object");
  97                offset = find_pack_entry_one(sha1, p);
  98                if (!offset)
  99                        die("internal error pack-check find-pack-entry-one");
 100
 101                packed_object_info_detail(p, offset, type, &size, &store_size,
 102                                          &delta_chain_length,
 103                                          base_sha1);
 104                printf("%s ", sha1_to_hex(sha1));
 105                if (!delta_chain_length)
 106                        printf("%-6s %lu %lu\n", type, size, offset);
 107                else {
 108                        printf("%-6s %lu %lu %u %s\n", type, size, offset,
 109                               delta_chain_length, sha1_to_hex(base_sha1));
 110                        if (delta_chain_length < MAX_CHAIN)
 111                                chain_histogram[delta_chain_length]++;
 112                        else
 113                                chain_histogram[0]++;
 114                }
 115        }
 116
 117        for (i = 0; i < MAX_CHAIN; i++) {
 118                if (!chain_histogram[i])
 119                        continue;
 120                printf("chain length %s %d: %d object%s\n",
 121                       i ? "=" : ">=",
 122                       i ? i : MAX_CHAIN,
 123                       chain_histogram[i],
 124                       1 < chain_histogram[i] ? "s" : "");
 125        }
 126}
 127
 128int verify_pack(struct packed_git *p, int verbose)
 129{
 130        unsigned long index_size = p->index_size;
 131        void *index_base = p->index_base;
 132        SHA_CTX ctx;
 133        unsigned char sha1[20];
 134        int ret;
 135
 136        ret = 0;
 137        /* Verify SHA1 sum of the index file */
 138        SHA1_Init(&ctx);
 139        SHA1_Update(&ctx, index_base, index_size - 20);
 140        SHA1_Final(sha1, &ctx);
 141        if (hashcmp(sha1, (unsigned char *)index_base + index_size - 20))
 142                ret = error("Packfile index for %s SHA1 mismatch",
 143                            p->pack_name);
 144
 145        if (!ret) {
 146                /* Verify pack file */
 147                struct pack_window *w_curs = NULL;
 148                ret = verify_packfile(p, &w_curs);
 149                unuse_pack(&w_curs);
 150        }
 151
 152        if (verbose) {
 153                if (ret)
 154                        printf("%s: bad\n", p->pack_name);
 155                else {
 156                        struct pack_window *w_curs = NULL;
 157                        show_pack_info(p, &w_curs);
 158                        unuse_pack(&w_curs);
 159                        printf("%s: ok\n", p->pack_name);
 160                }
 161        }
 162
 163        return ret;
 164}