@matheusbsbs / matheus-bagliano / commits / ba002f3b28
Fork 0

builtin-fsck: move common object checking code to fsck.c

Signed-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Martin Koegler committed Feb 25, 2008 at 22:46 UTC ba002f3b28ab9febea432d4c415dbe581836d9a0
3 files changed +257 -235
builtin-fsck.c
+35 -235
@@ -55,13 +55,13 @@ static int objerror(struct object *obj, const char *err, ...)
55 return -1;
56 }
57
58 -static int objwarning(struct object *obj, const char *err, ...)
58 +static int fsck_error_func(struct object *obj, int type, const char *err, ...)
59 {
60 va_list params;
61 va_start(params, err);
62 - objreport(obj, "warning", err, params);
62 + objreport(obj, (type == FSCK_WARN) ? "warning" : "error", err, params);
63 va_end(params);
64 - return -1;
64 + return (type == FSCK_WARN) ? 0 : 1;
65 }
66
67 static int mark_object(struct object *obj, int type, void *data)
@@ -246,256 +246,56 @@ static void check_connectivity(void)
246 }
247 }
248
249 -/*
250 - * The entries in a tree are ordered in the _path_ order,
251 - * which means that a directory entry is ordered by adding
252 - * a slash to the end of it.
253 - *
254 - * So a directory called "a" is ordered _after_ a file
255 - * called "a.c", because "a/" sorts after "a.c".
256 - */
257 -#define TREE_UNORDERED (-1)
258 -#define TREE_HAS_DUPS (-2)
259 -
260 -static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
249 +static int fsck_sha1(const unsigned char *sha1)
250 {
262 - int len1 = strlen(name1);
263 - int len2 = strlen(name2);
264 - int len = len1 < len2 ? len1 : len2;
265 - unsigned char c1, c2;
266 - int cmp;
267 -
268 - cmp = memcmp(name1, name2, len);
269 - if (cmp < 0)
251 + struct object *obj = parse_object(sha1);
252 + if (!obj) {
253 + errors_found |= ERROR_OBJECT;
254 + return error("%s: object corrupt or missing",
255 + sha1_to_hex(sha1));
256 + }
257 + if (obj->flags & SEEN)
258 return 0;
271 - if (cmp > 0)
272 - return TREE_UNORDERED;
273 -
274 - /*
275 - * Ok, the first <len> characters are the same.
276 - * Now we need to order the next one, but turn
277 - * a '\0' into a '/' for a directory entry.
278 - */
279 - c1 = name1[len];
280 - c2 = name2[len];
281 - if (!c1 && !c2)
282 - /*
283 - * git-write-tree used to write out a nonsense tree that has
284 - * entries with the same name, one blob and one tree. Make
285 - * sure we do not have duplicate entries.
286 - */
287 - return TREE_HAS_DUPS;
288 - if (!c1 && S_ISDIR(mode1))
289 - c1 = '/';
290 - if (!c2 && S_ISDIR(mode2))
291 - c2 = '/';
292 - return c1 < c2 ? 0 : TREE_UNORDERED;
293 -}
294 -
295 -static int fsck_tree(struct tree *item)
296 -{
297 - int retval;
298 - int has_full_path = 0;
299 - int has_empty_name = 0;
300 - int has_zero_pad = 0;
301 - int has_bad_modes = 0;
302 - int has_dup_entries = 0;
303 - int not_properly_sorted = 0;
304 - struct tree_desc desc;
305 - unsigned o_mode;
306 - const char *o_name;
307 - const unsigned char *o_sha1;
259 + obj->flags |= SEEN;
260
261 if (verbose)
310 - fprintf(stderr, "Checking tree %s\n",
311 - sha1_to_hex(item->object.sha1));
312 -
313 - init_tree_desc(&desc, item->buffer, item->size);
314 -
315 - o_mode = 0;
316 - o_name = NULL;
317 - o_sha1 = NULL;
318 - while (desc.size) {
319 - unsigned mode;
320 - const char *name;
321 - const unsigned char *sha1;
322 -
323 - sha1 = tree_entry_extract(&desc, &name, &mode);
324 -
325 - if (strchr(name, '/'))
326 - has_full_path = 1;
327 - if (!*name)
328 - has_empty_name = 1;
329 - has_zero_pad |= *(char *)desc.buffer == '0';
330 - update_tree_entry(&desc);
331 -
332 - switch (mode) {
333 - /*
334 - * Standard modes..
335 - */
336 - case S_IFREG | 0755:
337 - case S_IFREG | 0644:
338 - case S_IFLNK:
339 - case S_IFDIR:
340 - case S_IFGITLINK:
341 - break;
342 - /*
343 - * This is nonstandard, but we had a few of these
344 - * early on when we honored the full set of mode
345 - * bits..
346 - */
347 - case S_IFREG | 0664:
348 - if (!check_strict)
349 - break;
350 - default:
351 - has_bad_modes = 1;
352 - }
262 + fprintf(stderr, "Checking %s %s\n",
263 + typename(obj->type), sha1_to_hex(obj->sha1));
264
354 - if (o_name) {
355 - switch (verify_ordered(o_mode, o_name, mode, name)) {
356 - case TREE_UNORDERED:
357 - not_properly_sorted = 1;
358 - break;
359 - case TREE_HAS_DUPS:
360 - has_dup_entries = 1;
361 - break;
362 - default:
363 - break;
364 - }
365 - }
265 + if (fsck_walk(obj, mark_used, 0))
266 + objerror(obj, "broken links");
267 + if (fsck_object(obj, check_strict, fsck_error_func))
268 + return -1;
269
367 - o_mode = mode;
368 - o_name = name;
369 - o_sha1 = sha1;
370 - }
371 - free(item->buffer);
372 - item->buffer = NULL;
270 + if (obj->type == OBJ_TREE) {
271 + struct tree *item = (struct tree *) obj;
272
374 - retval = 0;
375 - if (has_full_path) {
376 - objwarning(&item->object, "contains full pathnames");
377 - }
378 - if (has_empty_name) {
379 - objwarning(&item->object, "contains empty pathname");
380 - }
381 - if (has_zero_pad) {
382 - objwarning(&item->object, "contains zero-padded file modes");
383 - }
384 - if (has_bad_modes) {
385 - objwarning(&item->object, "contains bad file modes");
273 + free(item->buffer);
274 + item->buffer = NULL;
275 }
387 - if (has_dup_entries) {
388 - retval = objerror(&item->object, "contains duplicate file entries");
389 - }
390 - if (not_properly_sorted) {
391 - retval = objerror(&item->object, "not properly sorted");
392 - }
393 - return retval;
394 -}
276
396 -static int fsck_commit(struct commit *commit)
397 -{
398 - char *buffer = commit->buffer;
399 - unsigned char tree_sha1[20], sha1[20];
400 - struct commit_graft *graft;
401 - int parents = 0;
277 + if (obj->type == OBJ_COMMIT) {
278 + struct commit *commit = (struct commit *) obj;
279
403 - if (verbose)
404 - fprintf(stderr, "Checking commit %s\n",
405 - sha1_to_hex(commit->object.sha1));
406 -
407 - if (memcmp(buffer, "tree ", 5))
408 - return objerror(&commit->object, "invalid format - expected 'tree' line");
409 - if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
410 - return objerror(&commit->object, "invalid 'tree' line format - bad sha1");
411 - buffer += 46;
412 - while (!memcmp(buffer, "parent ", 7)) {
413 - if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n')
414 - return objerror(&commit->object, "invalid 'parent' line format - bad sha1");
415 - buffer += 48;
416 - parents++;
417 - }
418 - graft = lookup_commit_graft(commit->object.sha1);
419 - if (graft) {
420 - struct commit_list *p = commit->parents;
421 - parents = 0;
422 - while (p) {
423 - p = p->next;
424 - parents++;
425 - }
426 - if (graft->nr_parent == -1 && !parents)
427 - ; /* shallow commit */
428 - else if (graft->nr_parent != parents)
429 - return objerror(&commit->object, "graft objects missing");
430 - } else {
431 - struct commit_list *p = commit->parents;
432 - while (p && parents) {
433 - p = p->next;
434 - parents--;
435 - }
436 - if (p || parents)
437 - return objerror(&commit->object, "parent objects missing");
438 - }
439 - if (memcmp(buffer, "author ", 7))
440 - return objerror(&commit->object, "invalid format - expected 'author' line");
441 - free(commit->buffer);
442 - commit->buffer = NULL;
443 - if (!commit->tree)
444 - return objerror(&commit->object, "could not load commit's tree %s", tree_sha1);
445 - if (!commit->parents && show_root)
446 - printf("root %s\n", sha1_to_hex(commit->object.sha1));
447 - if (!commit->date)
448 - printf("bad commit date in %s\n",
449 - sha1_to_hex(commit->object.sha1));
450 - return 0;
451 -}
280 + free(commit->buffer);
281 + commit->buffer = NULL;
282
453 -static int fsck_tag(struct tag *tag)
454 -{
455 - struct object *tagged = tag->tagged;
283 + if (!commit->parents && show_root)
284 + printf("root %s\n", sha1_to_hex(commit->object.sha1));
285 + }
286
457 - if (verbose)
458 - fprintf(stderr, "Checking tag %s\n",
459 - sha1_to_hex(tag->object.sha1));
287 + if (obj->type == OBJ_TAG) {
288 + struct tag *tag = (struct tag *) obj;
289
461 - if (!tagged) {
462 - return objerror(&tag->object, "could not load tagged object");
290 + if (show_tags && tag->tagged) {
291 + printf("tagged %s %s", typename(tag->tagged->type), sha1_to_hex(tag->tagged->sha1));
292 + printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
293 + }
294 }
464 - if (!show_tags)
465 - return 0;
295
467 - printf("tagged %s %s", typename(tagged->type), sha1_to_hex(tagged->sha1));
468 - printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
296 return 0;
297 }
298
472 -static int fsck_sha1(const unsigned char *sha1)
473 -{
474 - struct object *obj = parse_object(sha1);
475 - if (!obj) {
476 - errors_found |= ERROR_OBJECT;
477 - return error("%s: object corrupt or missing",
478 - sha1_to_hex(sha1));
479 - }
480 - if (obj->flags & SEEN)
481 - return 0;
482 - obj->flags |= SEEN;
483 - if (fsck_walk(obj, mark_used, 0))
484 - objerror(obj, "broken links");
485 - if (obj->type == OBJ_BLOB)
486 - return 0;
487 - if (obj->type == OBJ_TREE)
488 - return fsck_tree((struct tree *) obj);
489 - if (obj->type == OBJ_COMMIT)
490 - return fsck_commit((struct commit *) obj);
491 - if (obj->type == OBJ_TAG)
492 - return fsck_tag((struct tag *) obj);
493 -
494 - /* By now, parse_object() would've returned NULL instead. */
495 - return objerror(obj, "unknown type '%d' (internal fsck error)",
496 - obj->type);
497 -}
498 -
299 /*
300 * This is the sorting chunk size: make it reasonably
301 * big so that we can sort well..
fsck.c
+215
@@ -89,3 +89,218 @@ int fsck_walk(struct object *obj, fsck_walk_func walk, void *data)
89 return -1;
90 }
91 }
92 +
93 +/*
94 + * The entries in a tree are ordered in the _path_ order,
95 + * which means that a directory entry is ordered by adding
96 + * a slash to the end of it.
97 + *
98 + * So a directory called "a" is ordered _after_ a file
99 + * called "a.c", because "a/" sorts after "a.c".
100 + */
101 +#define TREE_UNORDERED (-1)
102 +#define TREE_HAS_DUPS (-2)
103 +
104 +static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
105 +{
106 + int len1 = strlen(name1);
107 + int len2 = strlen(name2);
108 + int len = len1 < len2 ? len1 : len2;
109 + unsigned char c1, c2;
110 + int cmp;
111 +
112 + cmp = memcmp(name1, name2, len);
113 + if (cmp < 0)
114 + return 0;
115 + if (cmp > 0)
116 + return TREE_UNORDERED;
117 +
118 + /*
119 + * Ok, the first <len> characters are the same.
120 + * Now we need to order the next one, but turn
121 + * a '\0' into a '/' for a directory entry.
122 + */
123 + c1 = name1[len];
124 + c2 = name2[len];
125 + if (!c1 && !c2)
126 + /*
127 + * git-write-tree used to write out a nonsense tree that has
128 + * entries with the same name, one blob and one tree. Make
129 + * sure we do not have duplicate entries.
130 + */
131 + return TREE_HAS_DUPS;
132 + if (!c1 && S_ISDIR(mode1))
133 + c1 = '/';
134 + if (!c2 && S_ISDIR(mode2))
135 + c2 = '/';
136 + return c1 < c2 ? 0 : TREE_UNORDERED;
137 +}
138 +
139 +static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
140 +{
141 + int retval;
142 + int has_full_path = 0;
143 + int has_empty_name = 0;
144 + int has_zero_pad = 0;
145 + int has_bad_modes = 0;
146 + int has_dup_entries = 0;
147 + int not_properly_sorted = 0;
148 + struct tree_desc desc;
149 + unsigned o_mode;
150 + const char *o_name;
151 + const unsigned char *o_sha1;
152 +
153 + init_tree_desc(&desc, item->buffer, item->size);
154 +
155 + o_mode = 0;
156 + o_name = NULL;
157 + o_sha1 = NULL;
158 + if (!desc.size)
159 + return error_func(&item->object, FSCK_ERROR, "empty tree");
160 +
161 + while (desc.size) {
162 + unsigned mode;
163 + const char *name;
164 + const unsigned char *sha1;
165 +
166 + sha1 = tree_entry_extract(&desc, &name, &mode);
167 +
168 + if (strchr(name, '/'))
169 + has_full_path = 1;
170 + if (!*name)
171 + has_empty_name = 1;
172 + has_zero_pad |= *(char *)desc.buffer == '0';
173 + update_tree_entry(&desc);
174 +
175 + switch (mode) {
176 + /*
177 + * Standard modes..
178 + */
179 + case S_IFREG | 0755:
180 + case S_IFREG | 0644:
181 + case S_IFLNK:
182 + case S_IFDIR:
183 + case S_IFGITLINK:
184 + break;
185 + /*
186 + * This is nonstandard, but we had a few of these
187 + * early on when we honored the full set of mode
188 + * bits..
189 + */
190 + case S_IFREG | 0664:
191 + if (!strict)
192 + break;
193 + default:
194 + has_bad_modes = 1;
195 + }
196 +
197 + if (o_name) {
198 + switch (verify_ordered(o_mode, o_name, mode, name)) {
199 + case TREE_UNORDERED:
200 + not_properly_sorted = 1;
201 + break;
202 + case TREE_HAS_DUPS:
203 + has_dup_entries = 1;
204 + break;
205 + default:
206 + break;
207 + }
208 + }
209 +
210 + o_mode = mode;
211 + o_name = name;
212 + o_sha1 = sha1;
213 + }
214 +
215 + retval = 0;
216 + if (has_full_path)
217 + retval += error_func(&item->object, FSCK_WARN, "contains full pathnames");
218 + if (has_empty_name)
219 + retval += error_func(&item->object, FSCK_WARN, "contains empty pathname");
220 + if (has_zero_pad)
221 + retval += error_func(&item->object, FSCK_WARN, "contains zero-padded file modes");
222 + if (has_bad_modes)
223 + retval += error_func(&item->object, FSCK_WARN, "contains bad file modes");
224 + if (has_dup_entries)
225 + retval += error_func(&item->object, FSCK_ERROR, "contains duplicate file entries");
226 + if (not_properly_sorted)
227 + retval += error_func(&item->object, FSCK_ERROR, "not properly sorted");
228 + return retval;
229 +}
230 +
231 +static int fsck_commit(struct commit *commit, fsck_error error_func)
232 +{
233 + char *buffer = commit->buffer;
234 + unsigned char tree_sha1[20], sha1[20];
235 + struct commit_graft *graft;
236 + int parents = 0;
237 +
238 + if (!commit->date)
239 + return error_func(&commit->object, FSCK_ERROR, "invalid author/committer line");
240 +
241 + if (memcmp(buffer, "tree ", 5))
242 + return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line");
243 + if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
244 + return error_func(&commit->object, FSCK_ERROR, "invalid 'tree' line format - bad sha1");
245 + buffer += 46;
246 + while (!memcmp(buffer, "parent ", 7)) {
247 + if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n')
248 + return error_func(&commit->object, FSCK_ERROR, "invalid 'parent' line format - bad sha1");
249 + buffer += 48;
250 + parents++;
251 + }
252 + graft = lookup_commit_graft(commit->object.sha1);
253 + if (graft) {
254 + struct commit_list *p = commit->parents;
255 + parents = 0;
256 + while (p) {
257 + p = p->next;
258 + parents++;
259 + }
260 + if (graft->nr_parent == -1 && !parents)
261 + ; /* shallow commit */
262 + else if (graft->nr_parent != parents)
263 + return error_func(&commit->object, FSCK_ERROR, "graft objects missing");
264 + } else {
265 + struct commit_list *p = commit->parents;
266 + while (p && parents) {
267 + p = p->next;
268 + parents--;
269 + }
270 + if (p || parents)
271 + return error_func(&commit->object, FSCK_ERROR, "parent objects missing");
272 + }
273 + if (memcmp(buffer, "author ", 7))
274 + return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line");
275 + if (!commit->tree)
276 + return error_func(&commit->object, FSCK_ERROR, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
277 +
278 + return 0;
279 +}
280 +
281 +static int fsck_tag(struct tag *tag, fsck_error error_func)
282 +{
283 + struct object *tagged = tag->tagged;
284 +
285 + if (!tagged)
286 + return error_func(&tag->object, FSCK_ERROR, "could not load tagged object");
287 + return 0;
288 +}
289 +
290 +int fsck_object(struct object *obj, int strict, fsck_error error_func)
291 +{
292 + if (!obj)
293 + return error_func(obj, FSCK_ERROR, "no valid object to fsck");
294 +
295 + if (obj->type == OBJ_BLOB)
296 + return 0;
297 + if (obj->type == OBJ_TREE)
298 + return fsck_tree((struct tree *) obj, strict, error_func);
299 + if (obj->type == OBJ_COMMIT)
300 + return fsck_commit((struct commit *) obj, error_func);
301 + if (obj->type == OBJ_TAG)
302 + return fsck_tag((struct tag *) obj, error_func);
303 +
304 + return error_func(obj, FSCK_ERROR, "unknown type '%d' (internal fsck error)",
305 + obj->type);
306 +}
fsck.h
+7
@@ -1,6 +1,9 @@
1 #ifndef GIT_FSCK_H
2 #define GIT_FSCK_H
3
4 +#define FSCK_ERROR 1
5 +#define FSCK_WARN 2
6 +
7 /*
8 * callback function for fsck_walk
9 * type is the expected type of the object or OBJ_ANY
@@ -11,6 +14,9 @@
14 */
15 typedef int (*fsck_walk_func)(struct object *obj, int type, void *data);
16
17 +/* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */
18 +typedef int (*fsck_error)(struct object *obj, int type, const char *err, ...);
19 +
20 /* descend in all linked child objects
21 * the return value is:
22 * -1 error in processing the object
@@ -19,5 +25,6 @@ typedef int (*fsck_walk_func)(struct object *obj, int type, void *data);
25 * 0 everything OK
26 */
27 int fsck_walk(struct object *obj, fsck_walk_func walk, void *data);
28 +int fsck_object(struct object *obj, int strict, fsck_error error_func);
29
30 #endif