Add first cut at "fsck-cache" that validates the SHA1 object store.
[git.git] / fsck-cache.c
1 #include "cache.h"
2
3 #include <sys/types.h>
4 #include <dirent.h>
5
6 /*
7  * These three functions should build up a graph in memory about
8  * what objects we've referenced, and found, and types..
9  *
10  * Right now we don't do that kind of reachability checking. Yet.
11  */
12 static void fsck_tree(void *data, unsigned long size)
13 {
14 }
15
16 static void fsck_commit(void *data, unsigned long size)
17 {
18 }
19
20 static int mark_sha1_seen(unsigned char *sha1, char *tag)
21 {
22         return 0;
23 }
24
25 static int fsck_entry(unsigned char *sha1, char *tag, void *data, unsigned long size)
26 {
27         if (!strcmp(tag, "blob")) 
28                 /* Nothing to check */;
29         else if (!strcmp(tag, "tree"))
30                 fsck_tree(data, size);
31         else if (!strcmp(tag, "commit"))
32                 fsck_commit(data, size);
33         else
34                 return -1;
35         return mark_sha1_seen(sha1, tag);
36 }
37
38 static int fsck_name(char *hex)
39 {
40         unsigned char sha1[20];
41         if (!get_sha1_hex(hex, sha1)) {
42                 unsigned long mapsize;
43                 void *map = map_sha1_file(sha1, &mapsize);
44                 if (map) {
45                         char type[100];
46                         unsigned long size;
47                         void *buffer = NULL;
48                         if (!check_sha1_signature(sha1, map, mapsize))
49                                 buffer = unpack_sha1_file(map, mapsize, type, &size);
50                         munmap(map, mapsize);
51                         if (buffer && !fsck_entry(sha1, type, buffer, size))
52                                 return 0;
53                 }
54         }
55         return -1;
56 }
57
58 static int fsck_dir(int i, char *path)
59 {
60         DIR *dir = opendir(path);
61         struct dirent *de;
62
63         if (!dir) {
64                 fprintf(stderr, "missing sha1 directory '%s'", path);
65                 return -1;
66         }
67
68         while ((de = readdir(dir)) != NULL) {
69                 char name[100];
70                 int len = strlen(de->d_name);
71
72                 switch (len) {
73                 case 2:
74                         if (de->d_name[1] != '.')
75                                 break;
76                 case 1:
77                         if (de->d_name[0] != '.')
78                                 break;
79                         continue;
80                 case 38:
81                         sprintf(name, "%02x", i);
82                         memcpy(name+2, de->d_name, len+1);
83                         if (!fsck_name(name))
84                                 continue;
85                 }
86                 fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
87         }
88         closedir(dir);
89         return 0;
90 }
91
92 int main(int argc, char **argv)
93 {
94         int i;
95         char *sha1_dir;
96
97         if (argc != 1)
98                 usage("fsck-cache");
99         sha1_dir = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT;
100         for (i = 0; i < 256; i++) {
101                 static char dir[4096];
102                 sprintf(dir, "%s/%02x", sha1_dir, i);
103                 fsck_dir(i, dir);
104         }
105         return 0;
106 }