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