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