pack-check.con commit Document gitattributes(5) (88e7fdf)
   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 = num_packed_objects(p);
  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 40
  77
  78static void show_pack_info(struct packed_git *p)
  79{
  80        uint32_t nr_objects, i, chain_histogram[MAX_CHAIN];
  81
  82        nr_objects = num_packed_objects(p);
  83        memset(chain_histogram, 0, sizeof(chain_histogram));
  84
  85        for (i = 0; i < nr_objects; i++) {
  86                const unsigned char *sha1;
  87                unsigned char base_sha1[20];
  88                const char *type;
  89                unsigned long size;
  90                unsigned long store_size;
  91                off_t offset;
  92                unsigned int delta_chain_length;
  93
  94                sha1 = nth_packed_object_sha1(p, i);
  95                if (!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                type = packed_object_info_detail(p, offset, &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 %"PRIuMAX"\n",
 107                               type, size, (uintmax_t)offset);
 108                else {
 109                        printf("%-6s %lu %"PRIuMAX" %u %s\n",
 110                               type, size, (uintmax_t)offset,
 111                               delta_chain_length, sha1_to_hex(base_sha1));
 112                        if (delta_chain_length < MAX_CHAIN)
 113                                chain_histogram[delta_chain_length]++;
 114                        else
 115                                chain_histogram[0]++;
 116                }
 117        }
 118
 119        for (i = 0; i < MAX_CHAIN; i++) {
 120                if (!chain_histogram[i])
 121                        continue;
 122                printf("chain length %s %d: %d object%s\n",
 123                       i ? "=" : ">=",
 124                       i ? i : MAX_CHAIN,
 125                       chain_histogram[i],
 126                       1 < chain_histogram[i] ? "s" : "");
 127        }
 128}
 129
 130int verify_pack(struct packed_git *p, int verbose)
 131{
 132        off_t index_size = p->index_size;
 133        const unsigned char *index_base = p->index_data;
 134        SHA_CTX ctx;
 135        unsigned char sha1[20];
 136        int ret;
 137
 138        ret = 0;
 139        /* Verify SHA1 sum of the index file */
 140        SHA1_Init(&ctx);
 141        SHA1_Update(&ctx, index_base, (unsigned int)(index_size - 20));
 142        SHA1_Final(sha1, &ctx);
 143        if (hashcmp(sha1, index_base + index_size - 20))
 144                ret = error("Packfile index for %s SHA1 mismatch",
 145                            p->pack_name);
 146
 147        if (!ret) {
 148                /* Verify pack file */
 149                struct pack_window *w_curs = NULL;
 150                ret = verify_packfile(p, &w_curs);
 151                unuse_pack(&w_curs);
 152        }
 153
 154        if (verbose) {
 155                if (ret)
 156                        printf("%s: bad\n", p->pack_name);
 157                else {
 158                        show_pack_info(p);
 159                        printf("%s: ok\n", p->pack_name);
 160                }
 161        }
 162
 163        return ret;
 164}