]>
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)); |
59c1e249 | 60 | return 0; |
20222118 LT |
61 | } |
62 | ||
ff5ebe39 DB |
63 | static int fsck_entry(unsigned char *sha1, char *tag, void *data, |
64 | unsigned long size) | |
20222118 | 65 | { |
1ea34e36 | 66 | if (!strcmp(tag, "blob")) { |
ff5ebe39 | 67 | lookup_blob(sha1); /* Nothing to check; but notice it. */ |
1ea34e36 LT |
68 | } else if (!strcmp(tag, "tree")) { |
69 | if (fsck_tree(sha1, data, size) < 0) | |
70 | return -1; | |
71 | } else if (!strcmp(tag, "commit")) { | |
72 | if (fsck_commit(sha1, data, size) < 0) | |
73 | return -1; | |
74 | } else | |
20222118 | 75 | return -1; |
ff5ebe39 | 76 | return 0; |
20222118 LT |
77 | } |
78 | ||
79 | static int fsck_name(char *hex) | |
80 | { | |
81 | unsigned char sha1[20]; | |
82 | if (!get_sha1_hex(hex, sha1)) { | |
83 | unsigned long mapsize; | |
84 | void *map = map_sha1_file(sha1, &mapsize); | |
85 | if (map) { | |
86 | char type[100]; | |
87 | unsigned long size; | |
d98b46f8 LT |
88 | void *buffer = unpack_sha1_file(map, mapsize, type, &size); |
89 | if (!buffer) | |
90 | return -1; | |
91 | if (check_sha1_signature(sha1, buffer, size, type) < 0) | |
92 | printf("sha1 mismatch %s\n", sha1_to_hex(sha1)); | |
20222118 | 93 | munmap(map, mapsize); |
d98b46f8 | 94 | if (!fsck_entry(sha1, type, buffer, size)) |
20222118 LT |
95 | return 0; |
96 | } | |
97 | } | |
98 | return -1; | |
99 | } | |
100 | ||
101 | static int fsck_dir(int i, char *path) | |
102 | { | |
103 | DIR *dir = opendir(path); | |
104 | struct dirent *de; | |
105 | ||
106 | if (!dir) { | |
2de381f9 | 107 | return error("missing sha1 directory '%s'", path); |
20222118 LT |
108 | } |
109 | ||
110 | while ((de = readdir(dir)) != NULL) { | |
111 | char name[100]; | |
112 | int len = strlen(de->d_name); | |
113 | ||
114 | switch (len) { | |
115 | case 2: | |
116 | if (de->d_name[1] != '.') | |
117 | break; | |
118 | case 1: | |
119 | if (de->d_name[0] != '.') | |
120 | break; | |
121 | continue; | |
122 | case 38: | |
123 | sprintf(name, "%02x", i); | |
124 | memcpy(name+2, de->d_name, len+1); | |
125 | if (!fsck_name(name)) | |
126 | continue; | |
127 | } | |
128 | fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name); | |
129 | } | |
130 | closedir(dir); | |
131 | return 0; | |
132 | } | |
133 | ||
134 | int main(int argc, char **argv) | |
135 | { | |
bcee6fd8 | 136 | int i, heads; |
20222118 LT |
137 | char *sha1_dir; |
138 | ||
bcee6fd8 LT |
139 | sha1_dir = getenv(DB_ENVIRONMENT) ? : DEFAULT_DB_ENVIRONMENT; |
140 | for (i = 0; i < 256; i++) { | |
141 | static char dir[4096]; | |
142 | sprintf(dir, "%s/%02x", sha1_dir, i); | |
143 | fsck_dir(i, dir); | |
144 | } | |
145 | ||
146 | heads = 0; | |
d9839e03 LT |
147 | for (i = 1; i < argc; i++) { |
148 | if (!strcmp(argv[i], "--unreachable")) { | |
149 | show_unreachable = 1; | |
150 | continue; | |
151 | } | |
152 | if (!get_sha1_hex(argv[i], head_sha1)) { | |
b51ad431 | 153 | struct object *obj = &lookup_commit(head_sha1)->object; |
ff5ebe39 DB |
154 | obj->used = 1; |
155 | mark_reachable(obj, REACHABLE); | |
bcee6fd8 | 156 | heads++; |
d9839e03 LT |
157 | continue; |
158 | } | |
bcee6fd8 | 159 | error("fsck-cache [[--unreachable] <head-sha1>*]"); |
d9839e03 | 160 | } |
d9839e03 | 161 | |
bcee6fd8 LT |
162 | if (!heads) { |
163 | if (show_unreachable) { | |
164 | fprintf(stderr, "unable to do reachability without a head\n"); | |
165 | show_unreachable = 0; | |
166 | } | |
167 | fprintf(stderr, "expect dangling commits - potential heads - due to lack of head information\n"); | |
20222118 | 168 | } |
bcee6fd8 | 169 | |
8ba0bbb2 | 170 | check_connectivity(); |
20222118 LT |
171 | return 0; |
172 | } |