pack-check.con commit git-svn: fix clone when a target directory has been specified (f30603f)
   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        int nr_objects, err, i;
  13
  14        /* Note that the pack header checks are actually performed by
  15         * use_pack when it first opens the pack file.  If anything
  16         * goes wrong during those checks then the call will die out
  17         * immediately.
  18         */
  19
  20        SHA1_Init(&ctx);
  21        while (offset < pack_sig) {
  22                unsigned int remaining;
  23                unsigned char *in = use_pack(p, w_curs, offset, &remaining);
  24                offset += remaining;
  25                if (offset > pack_sig)
  26                        remaining -= offset - pack_sig;
  27                SHA1_Update(&ctx, in, remaining);
  28        }
  29        SHA1_Final(sha1, &ctx);
  30        if (hashcmp(sha1, use_pack(p, w_curs, pack_sig, NULL)))
  31                return error("Packfile %s SHA1 mismatch with itself",
  32                             p->pack_name);
  33        if (hashcmp(sha1, (unsigned char *)index_base + index_size - 40))
  34                return error("Packfile %s SHA1 mismatch with idx",
  35                             p->pack_name);
  36        unuse_pack(w_curs);
  37
  38        /* Make sure everything reachable from idx is valid.  Since we
  39         * have verified that nr_objects matches between idx and pack,
  40         * we do not do scan-streaming check on the pack file.
  41         */
  42        nr_objects = num_packed_objects(p);
  43        for (i = err = 0; i < nr_objects; i++) {
  44                unsigned char sha1[20];
  45                void *data;
  46                char type[20];
  47                unsigned long size, offset;
  48
  49                if (nth_packed_object_sha1(p, i, sha1))
  50                        die("internal error pack-check nth-packed-object");
  51                offset = find_pack_entry_one(sha1, p);
  52                if (!offset)
  53                        die("internal error pack-check find-pack-entry-one");
  54                data = unpack_entry(p, offset, type, &size);
  55                if (!data) {
  56                        err = error("cannot unpack %s from %s",
  57                                    sha1_to_hex(sha1), p->pack_name);
  58                        continue;
  59                }
  60                if (check_sha1_signature(sha1, data, size, type)) {
  61                        err = error("packed %s from %s is corrupt",
  62                                    sha1_to_hex(sha1), p->pack_name);
  63                        free(data);
  64                        continue;
  65                }
  66                free(data);
  67        }
  68
  69        return err;
  70}
  71
  72
  73#define MAX_CHAIN 40
  74
  75static void show_pack_info(struct packed_git *p)
  76{
  77        int nr_objects, i;
  78        unsigned int 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                char type[20];
  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                packed_object_info_detail(p, offset, type, &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}