9
#include "refs.h"
10
#include "utf8.h"
11
12
+#define FOREACH_MSG_ID(FUNC) \
13
+ /* errors */ \
14
+ FUNC(BAD_DATE, ERROR) \
15
+ FUNC(BAD_DATE_OVERFLOW, ERROR) \
16
+ FUNC(BAD_EMAIL, ERROR) \
17
+ FUNC(BAD_NAME, ERROR) \
18
+ FUNC(BAD_OBJECT_SHA1, ERROR) \
19
+ FUNC(BAD_PARENT_SHA1, ERROR) \
20
+ FUNC(BAD_TAG_OBJECT, ERROR) \
21
+ FUNC(BAD_TIMEZONE, ERROR) \
22
+ FUNC(BAD_TREE, ERROR) \
23
+ FUNC(BAD_TREE_SHA1, ERROR) \
24
+ FUNC(BAD_TYPE, ERROR) \
25
+ FUNC(DUPLICATE_ENTRIES, ERROR) \
26
+ FUNC(MISSING_AUTHOR, ERROR) \
27
+ FUNC(MISSING_COMMITTER, ERROR) \
28
+ FUNC(MISSING_EMAIL, ERROR) \
29
+ FUNC(MISSING_GRAFT, ERROR) \
30
+ FUNC(MISSING_NAME_BEFORE_EMAIL, ERROR) \
31
+ FUNC(MISSING_OBJECT, ERROR) \
32
+ FUNC(MISSING_PARENT, ERROR) \
33
+ FUNC(MISSING_SPACE_BEFORE_DATE, ERROR) \
34
+ FUNC(MISSING_SPACE_BEFORE_EMAIL, ERROR) \
35
+ FUNC(MISSING_TAG, ERROR) \
36
+ FUNC(MISSING_TAG_ENTRY, ERROR) \
37
+ FUNC(MISSING_TAG_OBJECT, ERROR) \
38
+ FUNC(MISSING_TREE, ERROR) \
39
+ FUNC(MISSING_TYPE, ERROR) \
40
+ FUNC(MISSING_TYPE_ENTRY, ERROR) \
41
+ FUNC(NUL_IN_HEADER, ERROR) \
42
+ FUNC(TAG_OBJECT_NOT_TAG, ERROR) \
43
+ FUNC(TREE_NOT_SORTED, ERROR) \
44
+ FUNC(UNKNOWN_TYPE, ERROR) \
45
+ FUNC(UNTERMINATED_HEADER, ERROR) \
46
+ FUNC(ZERO_PADDED_DATE, ERROR) \
47
+ /* warnings */ \
48
+ FUNC(BAD_FILEMODE, WARN) \
49
+ FUNC(BAD_TAG_NAME, WARN) \
50
+ FUNC(EMPTY_NAME, WARN) \
51
+ FUNC(FULL_PATHNAME, WARN) \
52
+ FUNC(HAS_DOT, WARN) \
53
+ FUNC(HAS_DOTDOT, WARN) \
54
+ FUNC(HAS_DOTGIT, WARN) \
55
+ FUNC(MISSING_TAGGER_ENTRY, WARN) \
56
+ FUNC(NULL_SHA1, WARN) \
57
+ FUNC(ZERO_PADDED_FILEMODE, WARN)
58
+
59
+#define MSG_ID(id, msg_type) FSCK_MSG_##id,
60
+enum fsck_msg_id {
61
+ FOREACH_MSG_ID(MSG_ID)
62
+ FSCK_MSG_MAX
63
+};
64
+#undef MSG_ID
65
+
66
+#define MSG_ID(id, msg_type) { FSCK_##msg_type },
67
+static struct {
68
+ int msg_type;
69
+} msg_id_info[FSCK_MSG_MAX + 1] = {
70
+ FOREACH_MSG_ID(MSG_ID)
71
+ { -1 }
72
+};
73
+#undef MSG_ID
74
+
75
+static int fsck_msg_type(enum fsck_msg_id msg_id,
76
+ struct fsck_options *options)
77
+{
78
+ int msg_type;
79
+
80
+ msg_type = msg_id_info[msg_id].msg_type;
81
+ if (options->strict && msg_type == FSCK_WARN)
82
+ msg_type = FSCK_ERROR;
83
+
84
+ return msg_type;
85
+}
86
+
87
+__attribute__((format (printf, 4, 5)))
88
+static int report(struct fsck_options *options, struct object *object,
89
+ enum fsck_msg_id id, const char *fmt, ...)
90
+{
91
+ va_list ap;
92
+ struct strbuf sb = STRBUF_INIT;
93
+ int msg_type = fsck_msg_type(id, options), result;
94
+
95
+ va_start(ap, fmt);
96
+ strbuf_vaddf(&sb, fmt, ap);
97
+ result = options->error_func(object, msg_type, sb.buf);
98
+ strbuf_release(&sb);
99
+ va_end(ap);
100
+
101
+ return result;
102
+}
103
+
104
static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *options)
105
{
106
struct tree_desc desc;
311
312
retval = 0;
313
if (has_null_sha1)
222
- retval += options->error_func(&item->object, FSCK_WARN, "contains entries pointing to null sha1");
314
+ retval += report(options, &item->object, FSCK_MSG_NULL_SHA1, "contains entries pointing to null sha1");
315
if (has_full_path)
224
- retval += options->error_func(&item->object, FSCK_WARN, "contains full pathnames");
316
+ retval += report(options, &item->object, FSCK_MSG_FULL_PATHNAME, "contains full pathnames");
317
if (has_empty_name)
226
- retval += options->error_func(&item->object, FSCK_WARN, "contains empty pathname");
318
+ retval += report(options, &item->object, FSCK_MSG_EMPTY_NAME, "contains empty pathname");
319
if (has_dot)
228
- retval += options->error_func(&item->object, FSCK_WARN, "contains '.'");
320
+ retval += report(options, &item->object, FSCK_MSG_HAS_DOT, "contains '.'");
321
if (has_dotdot)
230
- retval += options->error_func(&item->object, FSCK_WARN, "contains '..'");
322
+ retval += report(options, &item->object, FSCK_MSG_HAS_DOTDOT, "contains '..'");
323
if (has_dotgit)
232
- retval += options->error_func(&item->object, FSCK_WARN, "contains '.git'");
324
+ retval += report(options, &item->object, FSCK_MSG_HAS_DOTGIT, "contains '.git'");
325
if (has_zero_pad)
234
- retval += options->error_func(&item->object, FSCK_WARN, "contains zero-padded file modes");
326
+ retval += report(options, &item->object, FSCK_MSG_ZERO_PADDED_FILEMODE, "contains zero-padded file modes");
327
if (has_bad_modes)
236
- retval += options->error_func(&item->object, FSCK_WARN, "contains bad file modes");
328
+ retval += report(options, &item->object, FSCK_MSG_BAD_FILEMODE, "contains bad file modes");
329
if (has_dup_entries)
238
- retval += options->error_func(&item->object, FSCK_ERROR, "contains duplicate file entries");
330
+ retval += report(options, &item->object, FSCK_MSG_DUPLICATE_ENTRIES, "contains duplicate file entries");
331
if (not_properly_sorted)
240
- retval += options->error_func(&item->object, FSCK_ERROR, "not properly sorted");
332
+ retval += report(options, &item->object, FSCK_MSG_TREE_NOT_SORTED, "not properly sorted");
333
return retval;
334
}
335
342
for (i = 0; i < size; i++) {
343
switch (buffer[i]) {
344
case '\0':
253
- return options->error_func(obj, FSCK_ERROR,
254
- "unterminated header: NUL at offset %d", i);
345
+ return report(options, obj,
346
+ FSCK_MSG_NUL_IN_HEADER,
347
+ "unterminated header: NUL at offset %ld", i);
348
case '\n':
349
if (i + 1 < size && buffer[i + 1] == '\n')
350
return 0;
351
}
352
}
353
261
- return options->error_func(obj, FSCK_ERROR, "unterminated header");
354
+ return report(options, obj,
355
+ FSCK_MSG_UNTERMINATED_HEADER, "unterminated header");
356
}
357
358
static int fsck_ident(const char **ident, struct object *obj, struct fsck_options *options)
360
char *end;
361
362
if (**ident == '<')
269
- return options->error_func(obj, FSCK_ERROR, "invalid author/committer line - missing space before email");
363
+ return report(options, obj, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
364
*ident += strcspn(*ident, "<>\n");
365
if (**ident == '>')
272
- return options->error_func(obj, FSCK_ERROR, "invalid author/committer line - bad name");
366
+ return report(options, obj, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name");
367
if (**ident != '<')
274
- return options->error_func(obj, FSCK_ERROR, "invalid author/committer line - missing email");
368
+ return report(options, obj, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email");
369
if ((*ident)[-1] != ' ')
276
- return options->error_func(obj, FSCK_ERROR, "invalid author/committer line - missing space before email");
370
+ return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
371
(*ident)++;
372
*ident += strcspn(*ident, "<>\n");
373
if (**ident != '>')
280
- return options->error_func(obj, FSCK_ERROR, "invalid author/committer line - bad email");
374
+ return report(options, obj, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email");
375
(*ident)++;
376
if (**ident != ' ')
283
- return options->error_func(obj, FSCK_ERROR, "invalid author/committer line - missing space before date");
377
+ return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
378
(*ident)++;
379
if (**ident == '0' && (*ident)[1] != ' ')
286
- return options->error_func(obj, FSCK_ERROR, "invalid author/committer line - zero-padded date");
380
+ return report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
381
if (date_overflows(strtoul(*ident, &end, 10)))
288
- return options->error_func(obj, FSCK_ERROR, "invalid author/committer line - date causes integer overflow");
382
+ return report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow");
383
if (end == *ident || *end != ' ')
290
- return options->error_func(obj, FSCK_ERROR, "invalid author/committer line - bad date");
384
+ return report(options, obj, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date");
385
*ident = end + 1;
386
if ((**ident != '+' && **ident != '-') ||
387
!isdigit((*ident)[1]) ||
389
!isdigit((*ident)[3]) ||
390
!isdigit((*ident)[4]) ||
391
((*ident)[5] != '\n'))
298
- return options->error_func(obj, FSCK_ERROR, "invalid author/committer line - bad time zone");
392
+ return report(options, obj, FSCK_MSG_BAD_TIMEZONE, "invalid author/committer line - bad time zone");
393
(*ident) += 6;
394
return 0;
395
}
406
return -1;
407
408
if (!skip_prefix(buffer, "tree ", &buffer))
315
- return options->error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line");
409
+ return report(options, &commit->object, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
410
if (get_sha1_hex(buffer, tree_sha1) || buffer[40] != '\n')
317
- return options->error_func(&commit->object, FSCK_ERROR, "invalid 'tree' line format - bad sha1");
411
+ return report(options, &commit->object, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
412
buffer += 41;
413
while (skip_prefix(buffer, "parent ", &buffer)) {
414
if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n')
321
- return options->error_func(&commit->object, FSCK_ERROR, "invalid 'parent' line format - bad sha1");
415
+ return report(options, &commit->object, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
416
buffer += 41;
417
parent_line_count++;
418
}
422
if (graft->nr_parent == -1 && !parent_count)
423
; /* shallow commit */
424
else if (graft->nr_parent != parent_count)
331
- return options->error_func(&commit->object, FSCK_ERROR, "graft objects missing");
425
+ return report(options, &commit->object, FSCK_MSG_MISSING_GRAFT, "graft objects missing");
426
} else {
427
if (parent_count != parent_line_count)
334
- return options->error_func(&commit->object, FSCK_ERROR, "parent objects missing");
428
+ return report(options, &commit->object, FSCK_MSG_MISSING_PARENT, "parent objects missing");
429
}
430
if (!skip_prefix(buffer, "author ", &buffer))
337
- return options->error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line");
431
+ return report(options, &commit->object, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line");
432
err = fsck_ident(&buffer, &commit->object, options);
433
if (err)
434
return err;
435
if (!skip_prefix(buffer, "committer ", &buffer))
342
- return options->error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'committer' line");
436
+ return report(options, &commit->object, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
437
err = fsck_ident(&buffer, &commit->object, options);
438
if (err)
439
return err;
440
if (!commit->tree)
347
- return options->error_func(&commit->object, FSCK_ERROR, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
441
+ return report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
442
443
return 0;
444
}
470
buffer = to_free =
471
read_sha1_file(tag->object.sha1, &type, &size);
472
if (!buffer)
379
- return options->error_func(&tag->object, FSCK_ERROR,
473
+ return report(options, &tag->object,
474
+ FSCK_MSG_MISSING_TAG_OBJECT,
475
"cannot read tag object");
476
477
if (type != OBJ_TAG) {
383
- ret = options->error_func(&tag->object, FSCK_ERROR,
478
+ ret = report(options, &tag->object,
479
+ FSCK_MSG_TAG_OBJECT_NOT_TAG,
480
"expected tag got %s",
481
typename(type));
482
goto done;
487
goto done;
488
489
if (!skip_prefix(buffer, "object ", &buffer)) {
394
- ret = options->error_func(&tag->object, FSCK_ERROR, "invalid format - expected 'object' line");
490
+ ret = report(options, &tag->object, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
491
goto done;
492
}
493
if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') {
398
- ret = options->error_func(&tag->object, FSCK_ERROR, "invalid 'object' line format - bad sha1");
494
+ ret = report(options, &tag->object, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
495
goto done;
496
}
497
buffer += 41;
498
499
if (!skip_prefix(buffer, "type ", &buffer)) {
404
- ret = options->error_func(&tag->object, FSCK_ERROR, "invalid format - expected 'type' line");
500
+ ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
501
goto done;
502
}
503
eol = strchr(buffer, '\n');
504
if (!eol) {
409
- ret = options->error_func(&tag->object, FSCK_ERROR, "invalid format - unexpected end after 'type' line");
505
+ ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
506
goto done;
507
}
508
if (type_from_string_gently(buffer, eol - buffer, 1) < 0)
413
- ret = options->error_func(&tag->object, FSCK_ERROR, "invalid 'type' value");
509
+ ret = report(options, &tag->object, FSCK_MSG_BAD_TYPE, "invalid 'type' value");
510
if (ret)
511
goto done;
512
buffer = eol + 1;
513
514
if (!skip_prefix(buffer, "tag ", &buffer)) {
419
- ret = options->error_func(&tag->object, FSCK_ERROR, "invalid format - expected 'tag' line");
515
+ ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line");
516
goto done;
517
}
518
eol = strchr(buffer, '\n');
519
if (!eol) {
424
- ret = options->error_func(&tag->object, FSCK_ERROR, "invalid format - unexpected end after 'type' line");
520
+ ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG, "invalid format - unexpected end after 'type' line");
521
goto done;
522
}
523
strbuf_addf(&sb, "refs/tags/%.*s", (int)(eol - buffer), buffer);
524
if (check_refname_format(sb.buf, 0))
429
- options->error_func(&tag->object, FSCK_WARN, "invalid 'tag' name: %.*s",
525
+ report(options, &tag->object, FSCK_MSG_BAD_TAG_NAME,
526
+ "invalid 'tag' name: %.*s",
527
(int)(eol - buffer), buffer);
528
buffer = eol + 1;
529
530
if (!skip_prefix(buffer, "tagger ", &buffer))
531
/* early tags do not contain 'tagger' lines; warn only */
435
- options->error_func(&tag->object, FSCK_WARN, "invalid format - expected 'tagger' line");
532
+ report(options, &tag->object, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line");
533
else
534
ret = fsck_ident(&buffer, &tag->object, options);
535
545
struct object *tagged = tag->tagged;
546
547
if (!tagged)
451
- return options->error_func(&tag->object, FSCK_ERROR, "could not load tagged object");
548
+ return report(options, &tag->object, FSCK_MSG_BAD_TAG_OBJECT, "could not load tagged object");
549
550
return fsck_tag_buffer(tag, data, size, options);
551
}
554
struct fsck_options *options)
555
{
556
if (!obj)
460
- return options->error_func(obj, FSCK_ERROR, "no valid object to fsck");
557
+ return report(options, obj, FSCK_MSG_BAD_OBJECT_SHA1, "no valid object to fsck");
558
559
if (obj->type == OBJ_BLOB)
560
return 0;
567
return fsck_tag((struct tag *) obj, (const char *) data,
568
size, options);
569
473
- return options->error_func(obj, FSCK_ERROR, "unknown type '%d' (internal fsck error)",
570
+ return report(options, obj, FSCK_MSG_UNKNOWN_TYPE, "unknown type '%d' (internal fsck error)",
571
obj->type);
572
}
573
477
-int fsck_error_function(struct object *obj, int type, const char *fmt, ...)
574
+int fsck_error_function(struct object *obj, int msg_type, const char *message)
575
{
479
- va_list ap;
480
- struct strbuf sb = STRBUF_INIT;
481
-
482
- strbuf_addf(&sb, "object %s:", sha1_to_hex(obj->sha1));
483
-
484
- va_start(ap, fmt);
485
- strbuf_vaddf(&sb, fmt, ap);
486
- va_end(ap);
487
-
488
- error("%s", sb.buf);
489
- strbuf_release(&sb);
576
+ error("object %s: %s", sha1_to_hex(obj->sha1), message);
577
return 1;
578
}