]>
Commit | Line | Data |
---|---|---|
20222118 LT |
1 | #include "cache.h" |
2 | ||
3 | #include <sys/types.h> | |
4 | #include <dirent.h> | |
5 | ||
ff5ebe39 DB |
6 | #include "commit.h" |
7 | #include "tree.h" | |
8 | #include "blob.h" | |
9 | ||
10 | #define REACHABLE 0x0001 | |
d9839e03 LT |
11 | |
12 | static int show_unreachable = 0; | |
d9839e03 LT |
13 | static unsigned char head_sha1[20]; |
14 | ||
8ba0bbb2 LT |
15 | static void check_connectivity(void) |
16 | { | |
17 | int i; | |
18 | ||
8ba0bbb2 | 19 | /* Look up all the requirements, warn about missing objects.. */ |
ff5ebe39 DB |
20 | for (i = 0; i < nr_objs; i++) { |
21 | struct object *obj = objs[i]; | |
8ba0bbb2 | 22 | |
ff5ebe39 | 23 | if (show_unreachable && !(obj->flags & REACHABLE)) { |
f43b8abc | 24 | printf("unreachable %s %s\n", obj->type, sha1_to_hex(obj->sha1)); |
8ba0bbb2 | 25 | continue; |
d9839e03 | 26 | } |
8ba0bbb2 | 27 | |
ff5ebe39 DB |
28 | if (!obj->parsed) { |
29 | printf("missing %s %s\n", obj->type, | |
30 | sha1_to_hex(obj->sha1)); | |
31 | } | |
32 | if (!obj->used) { | |
33 | printf("dangling %s %s\n", obj->type, | |
34 | sha1_to_hex(obj->sha1)); | |
d9839e03 | 35 | } |
8ba0bbb2 LT |
36 | } |
37 | } | |
38 | ||
1ea34e36 | 39 | static int fsck_tree(unsigned char *sha1, void *data, unsigned long size) |
20222118 | 40 | { |
ff5ebe39 DB |
41 | struct tree *item = lookup_tree(sha1); |
42 | if (parse_tree(item)) | |
43 | return -1; | |
44 | if (item->has_full_path) { | |
45 | fprintf(stderr, "warning: fsck-cache: tree %s " | |
46 | "has full pathnames in it\n", sha1_to_hex(sha1)); | |
1ea34e36 | 47 | } |
59c1e249 | 48 | return 0; |
1ea34e36 LT |
49 | } |
50 | ||
51 | static int fsck_commit(unsigned char *sha1, void *data, unsigned long size) | |
52 | { | |
ff5ebe39 DB |
53 | struct commit *commit = lookup_commit(sha1); |
54 | if (parse_commit(commit)) | |
1ea34e36 | 55 | return -1; |
ff5ebe39 | 56 | if (!commit->tree) |
1ea34e36 | 57 | return -1; |
ff5ebe39 | 58 | if (!commit->parents) |
d9839e03 | 59 | printf("root %s\n", sha1_to_hex(sha1)); |
e6948b6d LT |
60 | if (!commit->date) |
61 | printf("bad commit date in %s\n", sha1_to_hex(sha1)); | |
59c1e249 | 62 | return 0; |
20222118 LT |
63 | } |
64 | ||
4728b861 LT |
65 | static int fsck_blob(unsigned char *sha1, void *data, unsigned long size) |
66 | { | |
67 | struct blob *blob = lookup_blob(sha1); | |
68 | blob->object.parsed = 1; | |
69 | return 0; | |
70 | } | |
71 | ||
ec4465ad LT |
72 | static int fsck_tag(unsigned char *sha1, void *data, unsigned long size) |
73 | { | |
74 | int typelen, taglen; | |
75 | unsigned char object[20]; | |
56ce69f7 | 76 | char object_hex[60]; |
ec4465ad LT |
77 | const char *type_line, *tag_line, *sig_line; |
78 | ||
79 | if (size < 64) | |
80 | return -1; | |
81 | if (memcmp("object ", data, 7) || get_sha1_hex(data + 7, object)) | |
82 | return -1; | |
83 | ||
84 | type_line = data + 48; | |
85 | if (memcmp("\ntype ", type_line-1, 6)) | |
86 | return -1; | |
87 | ||
88 | tag_line = strchr(type_line, '\n'); | |
89 | if (!tag_line || memcmp("tag ", ++tag_line, 4)) | |
90 | return -1; | |
91 | ||
92 | sig_line = strchr(tag_line, '\n'); | |
93 | if (!sig_line) | |
94 | return -1; | |
95 | sig_line++; | |
96 | ||
97 | typelen = tag_line - type_line - strlen("type \n"); | |
98 | if (typelen >= 20) | |
99 | return -1; | |
100 | taglen = sig_line - tag_line - strlen("tag \n"); | |
101 | ||
56ce69f7 LT |
102 | strcpy(object_hex, sha1_to_hex(object)); |
103 | printf("tagged %.*s %s (%.*s) in %s\n", | |
ec4465ad | 104 | typelen, type_line + 5, |
56ce69f7 LT |
105 | object_hex, |
106 | taglen, tag_line + 4, | |
107 | sha1_to_hex(sha1)); | |
ec4465ad LT |
108 | return 0; |
109 | } | |
110 | ||
ff5ebe39 DB |
111 | static int fsck_entry(unsigned char *sha1, char *tag, void *data, |
112 | unsigned long size) | |
20222118 | 113 | { |
1ea34e36 | 114 | if (!strcmp(tag, "blob")) { |
4728b861 LT |
115 | if (fsck_blob(sha1, data, size) < 0) |
116 | return -1; | |
1ea34e36 LT |
117 | } else if (!strcmp(tag, "tree")) { |
118 | if (fsck_tree(sha1, data, size) < 0) | |
119 | return -1; | |
120 | } else if (!strcmp(tag, "commit")) { | |
121 | if (fsck_commit(sha1, data, size) < 0) | |
122 | return -1; | |
ec4465ad LT |
123 | } else if (!strcmp(tag, "tag")) { |
124 | if (fsck_tag(sha1, data, size) < 0) | |
125 | return -1; | |
1ea34e36 | 126 | } else |
20222118 | 127 | return -1; |
ff5ebe39 | 128 | return 0; |
20222118 LT |
129 | } |
130 | ||
131 | static int fsck_name(char *hex) | |
132 | { | |
133 | unsigned char sha1[20]; | |
134 | if (!get_sha1_hex(hex, sha1)) { | |
135 | unsigned long mapsize; | |
136 | void *map = map_sha1_file(sha1, &mapsize); | |
137 | if (map) { | |
138 | char type[100]; | |
139 | unsigned long size; | |
d98b46f8 LT |
140 | void *buffer = unpack_sha1_file(map, mapsize, type, &size); |
141 | if (!buffer) | |
142 | return -1; | |
143 | if (check_sha1_signature(sha1, buffer, size, type) < 0) | |
144 | printf("sha1 mismatch %s\n", sha1_to_hex(sha1)); | |
20222118 | 145 | munmap(map, mapsize); |
d98b46f8 | 146 | if (!fsck_entry(sha1, type, buffer, size)) |
20222118 LT |
147 | return 0; |
148 | } | |
149 | } | |
150 | return -1; | |
151 | } | |
152 | ||
153 | static int fsck_dir(int i, char *path) | |
154 | { | |
155 | DIR *dir = opendir(path); | |
156 | struct dirent *de; | |
157 | ||
158 | if (!dir) { | |
2de381f9 | 159 | return error("missing sha1 directory '%s'", path); |
20222118 LT |
160 | } |
161 | ||
162 | while ((de = readdir(dir)) != NULL) { | |
163 | char name[100]; | |
164 | int len = strlen(de->d_name); | |
165 | ||
166 | switch (len) { | |
167 | case 2: | |
168 | if (de->d_name[1] != '.') | |
169 | break; | |
170 | case 1: | |
171 | if (de->d_name[0] != '.') | |
172 | break; | |
173 | continue; | |
174 | case 38: | |
175 | sprintf(name, "%02x", i); | |
176 | memcpy(name+2, de->d_name, len+1); | |
177 | if (!fsck_name(name)) | |
178 | continue; | |
179 | } | |
180 | fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name); | |
181 | } | |
182 | closedir(dir); | |
183 | return 0; | |
184 | } | |
185 | ||
186 | int main(int argc, char **argv) | |
187 | { | |
bcee6fd8 | 188 | int i, heads; |
20222118 LT |
189 | char *sha1_dir; |
190 | ||
bcee6fd8 LT |
191 | sha1_dir = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT; |
192 | for (i = 0; i < 256; i++) { | |
193 | static char dir[4096]; | |
194 | sprintf(dir, "%s/%02x", sha1_dir, i); | |
195 | fsck_dir(i, dir); | |
196 | } | |
197 | ||
198 | heads = 0; | |
d9839e03 LT |
199 | for (i = 1; i < argc; i++) { |
200 | if (!strcmp(argv[i], "--unreachable")) { | |
201 | show_unreachable = 1; | |
202 | continue; | |
203 | } | |
204 | if (!get_sha1_hex(argv[i], head_sha1)) { | |
b51ad431 | 205 | struct object *obj = &lookup_commit(head_sha1)->object; |
ff5ebe39 DB |
206 | obj->used = 1; |
207 | mark_reachable(obj, REACHABLE); | |
bcee6fd8 | 208 | heads++; |
d9839e03 LT |
209 | continue; |
210 | } | |
bcee6fd8 | 211 | error("fsck-cache [[--unreachable] <head-sha1>*]"); |
d9839e03 | 212 | } |
d9839e03 | 213 | |
bcee6fd8 LT |
214 | if (!heads) { |
215 | if (show_unreachable) { | |
216 | fprintf(stderr, "unable to do reachability without a head\n"); | |
217 | show_unreachable = 0; | |
218 | } | |
219 | fprintf(stderr, "expect dangling commits - potential heads - due to lack of head information\n"); | |
20222118 | 220 | } |
bcee6fd8 | 221 | |
8ba0bbb2 | 222 | check_connectivity(); |
20222118 LT |
223 | return 0; |
224 | } |