Be more careful about tree entry modes.
[git.git] / fsck-cache.c
1 #include <sys/types.h>
2 #include <dirent.h>
3
4 #include "cache.h"
5 #include "commit.h"
6 #include "tree.h"
7 #include "blob.h"
8 #include "tag.h"
9
10 #define REACHABLE 0x0001
11
12 static int show_root = 0;
13 static int show_tags = 0;
14 static int show_unreachable = 0;
15 static int keep_cache_objects = 0; 
16 static unsigned char head_sha1[20];
17
18 static void check_connectivity(void)
19 {
20         int i;
21
22         /* Look up all the requirements, warn about missing objects.. */
23         for (i = 0; i < nr_objs; i++) {
24                 struct object *obj = objs[i];
25                 struct object_list *refs;
26
27                 if (!obj->parsed) {
28                         printf("missing %s %s\n", obj->type, sha1_to_hex(obj->sha1));
29                         continue;
30                 }
31
32                 for (refs = obj->refs; refs; refs = refs->next) {
33                         if (refs->item->parsed)
34                                 continue;
35                         printf("broken link from %7s %s\n",
36                                obj->type, sha1_to_hex(obj->sha1));
37                         printf("              to %7s %s\n",
38                                refs->item->type, sha1_to_hex(refs->item->sha1));
39                 }
40
41                 /* Don't bother with tag reachability. */
42                 if (obj->type == tag_type)
43                         continue;
44
45                 if (show_unreachable && !(obj->flags & REACHABLE)) {
46                         printf("unreachable %s %s\n", obj->type, sha1_to_hex(obj->sha1));
47                         continue;
48                 }
49
50                 if (!obj->used) {
51                         printf("dangling %s %s\n", obj->type, 
52                                sha1_to_hex(obj->sha1));
53                 }
54         }
55 }
56
57 /*
58  * The entries in a tree are ordered in the _path_ order,
59  * which means that a directory entry is ordered by adding
60  * a slash to the end of it.
61  *
62  * So a directory called "a" is ordered _after_ a file
63  * called "a.c", because "a/" sorts after "a.c".
64  */
65 static int verify_ordered(struct tree_entry_list *a, struct tree_entry_list *b)
66 {
67         int len1 = strlen(a->name);
68         int len2 = strlen(b->name);
69         int len = len1 < len2 ? len1 : len2;
70         unsigned char c1, c2;
71         int cmp;
72
73         cmp = memcmp(a->name, b->name, len);
74         if (cmp < 0)
75                 return 0;
76         if (cmp > 0)
77                 return -1;
78
79         /*
80          * Ok, the first <len> characters are the same.
81          * Now we need to order the next one, but turn
82          * a '\0' into a '/' for a directory entry.
83          */
84         c1 = a->name[len];
85         c2 = b->name[len];
86         if (!c1 && a->directory)
87                 c1 = '/';
88         if (!c2 && b->directory)
89                 c2 = '/';
90         return c1 < c2 ? 0 : -1;
91 }
92
93 static int fsck_tree(struct tree *item)
94 {
95         int has_full_path = 0;
96         struct tree_entry_list *entry, *last;
97
98         last = NULL;
99         for (entry = item->entries; entry; entry = entry->next) {
100                 if (strchr(entry->name, '/'))
101                         has_full_path = 1;
102
103                 switch (entry->mode) {
104                 /*
105                  * Standard modes.. 
106                  */
107                 case S_IFREG | 0755:
108                 case S_IFREG | 0644:
109                 case S_IFLNK:
110                 case S_IFDIR:
111                         break;
112                 /*
113                  * This is nonstandard, but we had a few of these
114                  * early on when we honored the full set of mode
115                  * bits..
116                  */
117                 case S_IFREG | 0664:
118                         break;
119                 default:
120                         printf("tree %s has entry %o %s\n",
121                                 sha1_to_hex(item->object.sha1),
122                                 entry->mode, entry->name);
123                 }
124
125                 if (last) {
126                         if (verify_ordered(last, entry) < 0) {
127                                 fprintf(stderr, "tree %s not ordered\n",
128                                         sha1_to_hex(item->object.sha1));
129                                 return -1;
130                         }
131                 }
132
133                 last = entry;
134         }
135
136         if (has_full_path) {
137                 fprintf(stderr, "warning: fsck-cache: tree %s "
138                         "has full pathnames in it\n", 
139                         sha1_to_hex(item->object.sha1));
140         }
141
142         return 0;
143 }
144
145 static int fsck_commit(struct commit *commit)
146 {
147         if (!commit->tree)
148                 return -1;
149         if (!commit->parents && show_root)
150                 printf("root %s\n", sha1_to_hex(commit->object.sha1));
151         if (!commit->date)
152                 printf("bad commit date in %s\n", 
153                        sha1_to_hex(commit->object.sha1));
154         return 0;
155 }
156
157 static int fsck_tag(struct tag *tag)
158 {
159         struct object *tagged = tag->tagged;
160
161         if (!tagged) {
162                 printf("bad object in tag %s\n", sha1_to_hex(tag->object.sha1));
163                 return -1;
164         }
165         if (!show_tags)
166                 return 0;
167
168         printf("tagged %s %s", tagged->type, sha1_to_hex(tagged->sha1));
169         printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
170         return 0;
171 }
172
173 static int fsck_sha1(unsigned char *sha1)
174 {
175         struct object *obj = parse_object(sha1);
176         if (!obj)
177                 return -1;
178         if (obj->type == blob_type)
179                 return 0;
180         if (obj->type == tree_type)
181                 return fsck_tree((struct tree *) obj);
182         if (obj->type == commit_type)
183                 return fsck_commit((struct commit *) obj);
184         if (obj->type == tag_type)
185                 return fsck_tag((struct tag *) obj);
186         return -1;
187 }
188
189 /*
190  * This is the sorting chunk size: make it reasonably
191  * big so that we can sort well..
192  */
193 #define MAX_SHA1_ENTRIES (1024)
194
195 struct sha1_entry {
196         unsigned long ino;
197         unsigned char sha1[20];
198 };
199
200 static struct {
201         unsigned long nr;
202         struct sha1_entry *entry[MAX_SHA1_ENTRIES];
203 } sha1_list;
204
205 static int ino_compare(const void *_a, const void *_b)
206 {
207         const struct sha1_entry *a = _a, *b = _b;
208         unsigned long ino1 = a->ino, ino2 = b->ino;
209         return ino1 < ino2 ? -1 : ino1 > ino2 ? 1 : 0;
210 }
211
212 static void fsck_sha1_list(void)
213 {
214         int i, nr = sha1_list.nr;
215
216         qsort(sha1_list.entry, nr, sizeof(struct sha1_entry *), ino_compare);
217         for (i = 0; i < nr; i++) {
218                 struct sha1_entry *entry = sha1_list.entry[i];
219                 unsigned char *sha1 = entry->sha1;
220
221                 sha1_list.entry[i] = NULL;
222                 if (fsck_sha1(sha1) < 0)
223                         fprintf(stderr, "bad sha1 entry '%s'\n", sha1_to_hex(sha1));
224                 free(entry);
225         }
226         sha1_list.nr = 0;
227 }
228
229 static void add_sha1_list(unsigned char *sha1, unsigned long ino)
230 {
231         struct sha1_entry *entry = xmalloc(sizeof(*entry));
232         int nr;
233
234         entry->ino = ino;
235         memcpy(entry->sha1, sha1, 20);
236         nr = sha1_list.nr;
237         if (nr == MAX_SHA1_ENTRIES) {
238                 fsck_sha1_list();
239                 nr = 0;
240         }
241         sha1_list.entry[nr] = entry;
242         sha1_list.nr = ++nr;
243 }
244
245 static int fsck_dir(int i, char *path)
246 {
247         DIR *dir = opendir(path);
248         struct dirent *de;
249
250         if (!dir) {
251                 return error("missing sha1 directory '%s'", path);
252         }
253
254         while ((de = readdir(dir)) != NULL) {
255                 char name[100];
256                 unsigned char sha1[20];
257                 int len = strlen(de->d_name);
258
259                 switch (len) {
260                 case 2:
261                         if (de->d_name[1] != '.')
262                                 break;
263                 case 1:
264                         if (de->d_name[0] != '.')
265                                 break;
266                         continue;
267                 case 38:
268                         sprintf(name, "%02x", i);
269                         memcpy(name+2, de->d_name, len+1);
270                         if (get_sha1_hex(name, sha1) < 0)
271                                 break;
272                         add_sha1_list(sha1, de->d_ino);
273                         continue;
274                 }
275                 fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
276         }
277         closedir(dir);
278         return 0;
279 }
280
281 int main(int argc, char **argv)
282 {
283         int i, heads;
284         char *sha1_dir;
285
286         for (i = 1; i < argc; i++) {
287                 const char *arg = argv[i];
288
289                 if (!strcmp(arg, "--unreachable")) {
290                         show_unreachable = 1;
291                         continue;
292                 }
293                 if (!strcmp(arg, "--tags")) {
294                         show_tags = 1;
295                         continue;
296                 }
297                 if (!strcmp(arg, "--root")) {
298                         show_root = 1;
299                         continue;
300                 }
301                 if (!strcmp(arg, "--cache")) {
302                         keep_cache_objects = 1;
303                         continue;
304                 }
305                 if (*arg == '-')
306                         usage("fsck-cache [--tags] [[--unreachable] [--cache] <head-sha1>*]");
307         }
308
309         sha1_dir = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
310         for (i = 0; i < 256; i++) {
311                 static char dir[4096];
312                 sprintf(dir, "%s/%02x", sha1_dir, i);
313                 fsck_dir(i, dir);
314         }
315         fsck_sha1_list();
316
317         heads = 0;
318         for (i = 1; i < argc; i++) {
319                 const char *arg = argv[i]; 
320
321                 if (*arg == '-')
322                         continue;
323
324                 if (!get_sha1(arg, head_sha1)) {
325                         struct object *obj = lookup_object(head_sha1);
326
327                         /* Error is printed by lookup_object(). */
328                         if (!obj)
329                                 continue;
330
331                         obj->used = 1;
332                         mark_reachable(obj, REACHABLE);
333                         heads++;
334                         continue;
335                 }
336                 error("expected sha1, got %s", arg);
337         }
338
339         if (keep_cache_objects) {
340                 int i;
341                 read_cache();
342                 for (i = 0; i < active_nr; i++) {
343                         struct blob *blob = lookup_blob(active_cache[i]->sha1);
344                         struct object *obj;
345                         if (!blob)
346                                 continue;
347                         obj = &blob->object;
348                         obj->used = 1;
349                         mark_reachable(obj, REACHABLE);
350                 }
351         }
352
353         if (!heads && !keep_cache_objects) {
354                 if (show_unreachable) {
355                         fprintf(stderr, "unable to do reachability without a head nor --cache\n");
356                         show_unreachable = 0; 
357                 }
358                 if (!heads)
359                         fprintf(stderr, "expect dangling commits - potential heads - due to lack of head information\n");
360         }
361
362         check_connectivity();
363         return 0;
364 }