7 unsigned char parent
[20];
8 unsigned char needs
[20];
13 unsigned char sha1
[20];
18 static struct needs
*needs
;
19 static struct seen
*seen
;
21 static int nr_seen
, alloc_seen
, nr_needs
, alloc_needs
;
24 * These two functions build up a graph in memory about
25 * what objects we've referenced, and found, and types..
27 static int compare_seen(const void *s1
, const void *s2
)
29 return memcmp(s1
, s2
, 20);
32 static int lookup_seen(unsigned char *sha1
, char *tag
)
34 int first
= 0, last
= nr_seen
;
36 while (last
> first
) {
37 int next
= (last
+ first
) / 2;
38 struct seen
*s
= seen
+ next
;
39 int cmp
= memcmp(sha1
, s
->sha1
, 20);
49 if (strcmp(tag
, s
->tag
))
57 static void check_connectivity(void)
61 /* Sort the "seen" tags for quicker lookup */
62 qsort(seen
, nr_seen
, sizeof(struct seen
), compare_seen
);
64 /* Look up all the requirements, warn about missing objects.. */
65 for (i
= 0; i
< nr_needs
; i
++) {
66 struct needs
*n
= needs
+ i
;
69 if (lookup_seen(n
->needs
, n
->tag
))
71 strcpy(hex
, sha1_to_hex(n
->parent
));
72 printf("missing %s: %s referenced by %s\n", n
->tag
, sha1_to_hex(n
->needs
), hex
);
75 /* Tell the user about things not referenced.. */
76 for (i
= 0; i
< nr_seen
; i
++) {
77 struct seen
*s
= seen
+ i
;
81 printf("unreferenced %s: %s\n", s
->tag
, sha1_to_hex(s
->sha1
));
85 static void mark_needs_sha1(unsigned char *parent
, const char * tag
, unsigned char *child
)
89 if (nr_needs
== alloc_needs
) {
90 alloc_needs
= alloc_nr(alloc_needs
);
91 needs
= realloc(needs
, alloc_needs
*sizeof(struct needs
));
95 memcpy(n
->parent
, parent
, 20);
96 memcpy(n
->needs
, child
, 20);
97 strncpy(n
->tag
, tag
, sizeof(n
->tag
));
100 static int mark_sha1_seen(unsigned char *sha1
, char *tag
)
104 if (nr_seen
== alloc_seen
) {
105 alloc_seen
= alloc_nr(alloc_seen
);
106 seen
= realloc(seen
, alloc_seen
*sizeof(struct seen
));
109 memset(s
, 0, sizeof(*s
));
111 memcpy(s
->sha1
, sha1
, 20);
112 strncpy(s
->tag
, tag
, sizeof(s
->tag
));
117 static int fsck_tree(unsigned char *sha1
, void *data
, unsigned long size
)
119 int warn_old_tree
= 1;
122 int len
= 1+strlen(data
);
123 unsigned char *file_sha1
= data
+ len
;
124 char *path
= strchr(data
, ' ');
126 if (size
< len
+ 20 || !path
|| sscanf(data
, "%o", &mode
) != 1)
129 /* Warn about trees that don't do the recursive thing.. */
130 if (warn_old_tree
&& strchr(path
, '/')) {
131 fprintf(stderr
, "warning: fsck-cache: tree %s has full pathnames in it\n", sha1_to_hex(sha1
));
137 mark_needs_sha1(sha1
, S_ISDIR(mode
) ? "tree" : "blob", file_sha1
);
142 static int fsck_commit(unsigned char *sha1
, void *data
, unsigned long size
)
145 unsigned char tree_sha1
[20];
146 unsigned char parent_sha1
[20];
148 if (memcmp(data
, "tree ", 5))
150 if (get_sha1_hex(data
+ 5, tree_sha1
) < 0)
152 mark_needs_sha1(sha1
, "tree", tree_sha1
);
153 data
+= 5 + 40 + 1; /* "tree " + <hex sha1> + '\n' */
155 while (!memcmp(data
, "parent ", 7)) {
156 if (get_sha1_hex(data
+ 7, parent_sha1
) < 0)
158 mark_needs_sha1(sha1
, "commit", parent_sha1
);
159 data
+= 7 + 40 + 1; /* "parent " + <hex sha1> + '\n' */
163 printf("root: %s\n", sha1_to_hex(sha1
));
167 static int fsck_entry(unsigned char *sha1
, char *tag
, void *data
, unsigned long size
)
169 if (!strcmp(tag
, "blob")) {
170 /* Nothing to check */;
171 } else if (!strcmp(tag
, "tree")) {
172 if (fsck_tree(sha1
, data
, size
) < 0)
174 } else if (!strcmp(tag
, "commit")) {
175 if (fsck_commit(sha1
, data
, size
) < 0)
179 return mark_sha1_seen(sha1
, tag
);
182 static int fsck_name(char *hex
)
184 unsigned char sha1
[20];
185 if (!get_sha1_hex(hex
, sha1
)) {
186 unsigned long mapsize
;
187 void *map
= map_sha1_file(sha1
, &mapsize
);
192 if (!check_sha1_signature(sha1
, map
, mapsize
))
193 buffer
= unpack_sha1_file(map
, mapsize
, type
, &size
);
194 munmap(map
, mapsize
);
195 if (buffer
&& !fsck_entry(sha1
, type
, buffer
, size
))
202 static int fsck_dir(int i
, char *path
)
204 DIR *dir
= opendir(path
);
208 return error("missing sha1 directory '%s'", path
);
211 while ((de
= readdir(dir
)) != NULL
) {
213 int len
= strlen(de
->d_name
);
217 if (de
->d_name
[1] != '.')
220 if (de
->d_name
[0] != '.')
224 sprintf(name
, "%02x", i
);
225 memcpy(name
+2, de
->d_name
, len
+1);
226 if (!fsck_name(name
))
229 fprintf(stderr
, "bad sha1 file: %s/%s\n", path
, de
->d_name
);
235 int main(int argc
, char **argv
)
242 sha1_dir
= getenv(DB_ENVIRONMENT
) ? : DEFAULT_DB_ENVIRONMENT
;
243 for (i
= 0; i
< 256; i
++) {
244 static char dir
[4096];
245 sprintf(dir
, "%s/%02x", sha1_dir
, i
);
248 check_connectivity();