builtin-verify-pack.con commit diff-tree: Note that the commit ID is printed with --stdin (7cccfaa)
   1#include "builtin.h"
   2#include "cache.h"
   3#include "pack.h"
   4
   5
   6#define MAX_CHAIN 50
   7
   8static void show_pack_info(struct packed_git *p)
   9{
  10        uint32_t nr_objects, i, chain_histogram[MAX_CHAIN+1];
  11
  12        nr_objects = p->num_objects;
  13        memset(chain_histogram, 0, sizeof(chain_histogram));
  14
  15        for (i = 0; i < nr_objects; i++) {
  16                const unsigned char *sha1;
  17                unsigned char base_sha1[20];
  18                const char *type;
  19                unsigned long size;
  20                unsigned long store_size;
  21                off_t offset;
  22                unsigned int delta_chain_length;
  23
  24                sha1 = nth_packed_object_sha1(p, i);
  25                if (!sha1)
  26                        die("internal error pack-check nth-packed-object");
  27                offset = nth_packed_object_offset(p, i);
  28                type = packed_object_info_detail(p, offset, &size, &store_size,
  29                                                 &delta_chain_length,
  30                                                 base_sha1);
  31                printf("%s ", sha1_to_hex(sha1));
  32                if (!delta_chain_length)
  33                        printf("%-6s %lu %lu %"PRIuMAX"\n",
  34                               type, size, store_size, (uintmax_t)offset);
  35                else {
  36                        printf("%-6s %lu %lu %"PRIuMAX" %u %s\n",
  37                               type, size, store_size, (uintmax_t)offset,
  38                               delta_chain_length, sha1_to_hex(base_sha1));
  39                        if (delta_chain_length <= MAX_CHAIN)
  40                                chain_histogram[delta_chain_length]++;
  41                        else
  42                                chain_histogram[0]++;
  43                }
  44        }
  45
  46        for (i = 0; i <= MAX_CHAIN; i++) {
  47                if (!chain_histogram[i])
  48                        continue;
  49                printf("chain length = %"PRIu32": %"PRIu32" object%s\n", i,
  50                       chain_histogram[i], chain_histogram[i] > 1 ? "s" : "");
  51        }
  52        if (chain_histogram[0])
  53                printf("chain length > %d: %"PRIu32" object%s\n", MAX_CHAIN,
  54                       chain_histogram[0], chain_histogram[0] > 1 ? "s" : "");
  55}
  56
  57static int verify_one_pack(const char *path, int verbose)
  58{
  59        char arg[PATH_MAX];
  60        int len;
  61        struct packed_git *pack;
  62        int err;
  63
  64        len = strlcpy(arg, path, PATH_MAX);
  65        if (len >= PATH_MAX)
  66                return error("name too long: %s", path);
  67
  68        /*
  69         * In addition to "foo.idx" we accept "foo.pack" and "foo";
  70         * normalize these forms to "foo.idx" for add_packed_git().
  71         */
  72        if (has_extension(arg, ".pack")) {
  73                strcpy(arg + len - 5, ".idx");
  74                len--;
  75        } else if (!has_extension(arg, ".idx")) {
  76                if (len + 4 >= PATH_MAX)
  77                        return error("name too long: %s.idx", arg);
  78                strcpy(arg + len, ".idx");
  79                len += 4;
  80        }
  81
  82        /*
  83         * add_packed_git() uses our buffer (containing "foo.idx") to
  84         * build the pack filename ("foo.pack").  Make sure it fits.
  85         */
  86        if (len + 1 >= PATH_MAX) {
  87                arg[len - 4] = '\0';
  88                return error("name too long: %s.pack", arg);
  89        }
  90
  91        pack = add_packed_git(arg, len, 1);
  92        if (!pack)
  93                return error("packfile %s not found.", arg);
  94
  95        install_packed_git(pack);
  96        err = verify_pack(pack);
  97
  98        if (verbose) {
  99                if (err)
 100                        printf("%s: bad\n", pack->pack_name);
 101                else {
 102                        show_pack_info(pack);
 103                        printf("%s: ok\n", pack->pack_name);
 104                }
 105        }
 106
 107        return err;
 108}
 109
 110static const char verify_pack_usage[] = "git-verify-pack [-v] <pack>...";
 111
 112int cmd_verify_pack(int argc, const char **argv, const char *prefix)
 113{
 114        int err = 0;
 115        int verbose = 0;
 116        int no_more_options = 0;
 117        int nothing_done = 1;
 118
 119        git_config(git_default_config, NULL);
 120        while (1 < argc) {
 121                if (!no_more_options && argv[1][0] == '-') {
 122                        if (!strcmp("-v", argv[1]))
 123                                verbose = 1;
 124                        else if (!strcmp("--", argv[1]))
 125                                no_more_options = 1;
 126                        else
 127                                usage(verify_pack_usage);
 128                }
 129                else {
 130                        if (verify_one_pack(argv[1], verbose))
 131                                err = 1;
 132                        nothing_done = 0;
 133                }
 134                argc--; argv++;
 135        }
 136
 137        if (nothing_done)
 138                usage(verify_pack_usage);
 139
 140        return err;
 141}