1 #include "cache.h"
2 #include "object-store.h"
3 #include "repository.h"
4 #include "object.h"
5 #include "blob.h"
6 #include "tree.h"
7 #include "tree-walk.h"
8 #include "commit.h"
9 #include "tag.h"
10 #include "fsck.h"
11 #include "refs.h"
12 #include "url.h"
13 #include "utf8.h"
14 #include "decorate.h"
15 #include "oidset.h"
16 #include "packfile.h"
17 #include "submodule-config.h"
18 #include "config.h"
19 #include "credential.h"
20 #include "help.h"
21 
22 #define STR(x) #x
23 #define MSG_ID(id, msg_type) { STR(id), NULL, NULL, FSCK_##msg_type },
24 static struct {
25 	const char *id_string;
26 	const char *downcased;
27 	const char *camelcased;
28 	enum fsck_msg_type msg_type;
29 } msg_id_info[FSCK_MSG_MAX + 1] = {
30 	FOREACH_FSCK_MSG_ID(MSG_ID)
31 	{ NULL, NULL, NULL, -1 }
32 };
33 #undef MSG_ID
34 #undef STR
35 
prepare_msg_ids(void)36 static void prepare_msg_ids(void)
37 {
38 	int i;
39 
40 	if (msg_id_info[0].downcased)
41 		return;
42 
43 	/* convert id_string to lower case, without underscores. */
44 	for (i = 0; i < FSCK_MSG_MAX; i++) {
45 		const char *p = msg_id_info[i].id_string;
46 		int len = strlen(p);
47 		char *q = xmalloc(len);
48 
49 		msg_id_info[i].downcased = q;
50 		while (*p)
51 			if (*p == '_')
52 				p++;
53 			else
54 				*(q)++ = tolower(*(p)++);
55 		*q = '\0';
56 
57 		p = msg_id_info[i].id_string;
58 		q = xmalloc(len);
59 		msg_id_info[i].camelcased = q;
60 		while (*p) {
61 			if (*p == '_') {
62 				p++;
63 				if (*p)
64 					*q++ = *p++;
65 			} else {
66 				*q++ = tolower(*p++);
67 			}
68 		}
69 		*q = '\0';
70 	}
71 }
72 
parse_msg_id(const char * text)73 static int parse_msg_id(const char *text)
74 {
75 	int i;
76 
77 	prepare_msg_ids();
78 
79 	for (i = 0; i < FSCK_MSG_MAX; i++)
80 		if (!strcmp(text, msg_id_info[i].downcased))
81 			return i;
82 
83 	return -1;
84 }
85 
list_config_fsck_msg_ids(struct string_list * list,const char * prefix)86 void list_config_fsck_msg_ids(struct string_list *list, const char *prefix)
87 {
88 	int i;
89 
90 	prepare_msg_ids();
91 
92 	for (i = 0; i < FSCK_MSG_MAX; i++)
93 		list_config_item(list, prefix, msg_id_info[i].camelcased);
94 }
95 
fsck_msg_type(enum fsck_msg_id msg_id,struct fsck_options * options)96 static enum fsck_msg_type fsck_msg_type(enum fsck_msg_id msg_id,
97 	struct fsck_options *options)
98 {
99 	assert(msg_id >= 0 && msg_id < FSCK_MSG_MAX);
100 
101 	if (!options->msg_type) {
102 		enum fsck_msg_type msg_type = msg_id_info[msg_id].msg_type;
103 
104 		if (options->strict && msg_type == FSCK_WARN)
105 			msg_type = FSCK_ERROR;
106 		return msg_type;
107 	}
108 
109 	return options->msg_type[msg_id];
110 }
111 
parse_msg_type(const char * str)112 static enum fsck_msg_type parse_msg_type(const char *str)
113 {
114 	if (!strcmp(str, "error"))
115 		return FSCK_ERROR;
116 	else if (!strcmp(str, "warn"))
117 		return FSCK_WARN;
118 	else if (!strcmp(str, "ignore"))
119 		return FSCK_IGNORE;
120 	else
121 		die("Unknown fsck message type: '%s'", str);
122 }
123 
is_valid_msg_type(const char * msg_id,const char * msg_type)124 int is_valid_msg_type(const char *msg_id, const char *msg_type)
125 {
126 	if (parse_msg_id(msg_id) < 0)
127 		return 0;
128 	parse_msg_type(msg_type);
129 	return 1;
130 }
131 
fsck_set_msg_type_from_ids(struct fsck_options * options,enum fsck_msg_id msg_id,enum fsck_msg_type msg_type)132 void fsck_set_msg_type_from_ids(struct fsck_options *options,
133 				enum fsck_msg_id msg_id,
134 				enum fsck_msg_type msg_type)
135 {
136 	if (!options->msg_type) {
137 		int i;
138 		enum fsck_msg_type *severity;
139 		ALLOC_ARRAY(severity, FSCK_MSG_MAX);
140 		for (i = 0; i < FSCK_MSG_MAX; i++)
141 			severity[i] = fsck_msg_type(i, options);
142 		options->msg_type = severity;
143 	}
144 
145 	options->msg_type[msg_id] = msg_type;
146 }
147 
fsck_set_msg_type(struct fsck_options * options,const char * msg_id_str,const char * msg_type_str)148 void fsck_set_msg_type(struct fsck_options *options,
149 		       const char *msg_id_str, const char *msg_type_str)
150 {
151 	int msg_id = parse_msg_id(msg_id_str);
152 	enum fsck_msg_type msg_type = parse_msg_type(msg_type_str);
153 
154 	if (msg_id < 0)
155 		die("Unhandled message id: %s", msg_id_str);
156 
157 	if (msg_type != FSCK_ERROR && msg_id_info[msg_id].msg_type == FSCK_FATAL)
158 		die("Cannot demote %s to %s", msg_id_str, msg_type_str);
159 
160 	fsck_set_msg_type_from_ids(options, msg_id, msg_type);
161 }
162 
fsck_set_msg_types(struct fsck_options * options,const char * values)163 void fsck_set_msg_types(struct fsck_options *options, const char *values)
164 {
165 	char *buf = xstrdup(values), *to_free = buf;
166 	int done = 0;
167 
168 	while (!done) {
169 		int len = strcspn(buf, " ,|"), equal;
170 
171 		done = !buf[len];
172 		if (!len) {
173 			buf++;
174 			continue;
175 		}
176 		buf[len] = '\0';
177 
178 		for (equal = 0;
179 		     equal < len && buf[equal] != '=' && buf[equal] != ':';
180 		     equal++)
181 			buf[equal] = tolower(buf[equal]);
182 		buf[equal] = '\0';
183 
184 		if (!strcmp(buf, "skiplist")) {
185 			if (equal == len)
186 				die("skiplist requires a path");
187 			oidset_parse_file(&options->skiplist, buf + equal + 1);
188 			buf += len + 1;
189 			continue;
190 		}
191 
192 		if (equal == len)
193 			die("Missing '=': '%s'", buf);
194 
195 		fsck_set_msg_type(options, buf, buf + equal + 1);
196 		buf += len + 1;
197 	}
198 	free(to_free);
199 }
200 
object_on_skiplist(struct fsck_options * opts,const struct object_id * oid)201 static int object_on_skiplist(struct fsck_options *opts,
202 			      const struct object_id *oid)
203 {
204 	return opts && oid && oidset_contains(&opts->skiplist, oid);
205 }
206 
207 __attribute__((format (printf, 5, 6)))
report(struct fsck_options * options,const struct object_id * oid,enum object_type object_type,enum fsck_msg_id msg_id,const char * fmt,...)208 static int report(struct fsck_options *options,
209 		  const struct object_id *oid, enum object_type object_type,
210 		  enum fsck_msg_id msg_id, const char *fmt, ...)
211 {
212 	va_list ap;
213 	struct strbuf sb = STRBUF_INIT;
214 	enum fsck_msg_type msg_type = fsck_msg_type(msg_id, options);
215 	int result;
216 
217 	if (msg_type == FSCK_IGNORE)
218 		return 0;
219 
220 	if (object_on_skiplist(options, oid))
221 		return 0;
222 
223 	if (msg_type == FSCK_FATAL)
224 		msg_type = FSCK_ERROR;
225 	else if (msg_type == FSCK_INFO)
226 		msg_type = FSCK_WARN;
227 
228 	prepare_msg_ids();
229 	strbuf_addf(&sb, "%s: ", msg_id_info[msg_id].camelcased);
230 
231 	va_start(ap, fmt);
232 	strbuf_vaddf(&sb, fmt, ap);
233 	result = options->error_func(options, oid, object_type,
234 				     msg_type, msg_id, sb.buf);
235 	strbuf_release(&sb);
236 	va_end(ap);
237 
238 	return result;
239 }
240 
fsck_enable_object_names(struct fsck_options * options)241 void fsck_enable_object_names(struct fsck_options *options)
242 {
243 	if (!options->object_names)
244 		options->object_names = kh_init_oid_map();
245 }
246 
fsck_get_object_name(struct fsck_options * options,const struct object_id * oid)247 const char *fsck_get_object_name(struct fsck_options *options,
248 				 const struct object_id *oid)
249 {
250 	khiter_t pos;
251 	if (!options->object_names)
252 		return NULL;
253 	pos = kh_get_oid_map(options->object_names, *oid);
254 	if (pos >= kh_end(options->object_names))
255 		return NULL;
256 	return kh_value(options->object_names, pos);
257 }
258 
fsck_put_object_name(struct fsck_options * options,const struct object_id * oid,const char * fmt,...)259 void fsck_put_object_name(struct fsck_options *options,
260 			  const struct object_id *oid,
261 			  const char *fmt, ...)
262 {
263 	va_list ap;
264 	struct strbuf buf = STRBUF_INIT;
265 	khiter_t pos;
266 	int hashret;
267 
268 	if (!options->object_names)
269 		return;
270 
271 	pos = kh_put_oid_map(options->object_names, *oid, &hashret);
272 	if (!hashret)
273 		return;
274 	va_start(ap, fmt);
275 	strbuf_vaddf(&buf, fmt, ap);
276 	kh_value(options->object_names, pos) = strbuf_detach(&buf, NULL);
277 	va_end(ap);
278 }
279 
fsck_describe_object(struct fsck_options * options,const struct object_id * oid)280 const char *fsck_describe_object(struct fsck_options *options,
281 				 const struct object_id *oid)
282 {
283 	static struct strbuf bufs[] = {
284 		STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
285 	};
286 	static int b = 0;
287 	struct strbuf *buf;
288 	const char *name = fsck_get_object_name(options, oid);
289 
290 	buf = bufs + b;
291 	b = (b + 1) % ARRAY_SIZE(bufs);
292 	strbuf_reset(buf);
293 	strbuf_addstr(buf, oid_to_hex(oid));
294 	if (name)
295 		strbuf_addf(buf, " (%s)", name);
296 
297 	return buf->buf;
298 }
299 
fsck_walk_tree(struct tree * tree,void * data,struct fsck_options * options)300 static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *options)
301 {
302 	struct tree_desc desc;
303 	struct name_entry entry;
304 	int res = 0;
305 	const char *name;
306 
307 	if (parse_tree(tree))
308 		return -1;
309 
310 	name = fsck_get_object_name(options, &tree->object.oid);
311 	if (init_tree_desc_gently(&desc, tree->buffer, tree->size))
312 		return -1;
313 	while (tree_entry_gently(&desc, &entry)) {
314 		struct object *obj;
315 		int result;
316 
317 		if (S_ISGITLINK(entry.mode))
318 			continue;
319 
320 		if (S_ISDIR(entry.mode)) {
321 			obj = (struct object *)lookup_tree(the_repository, &entry.oid);
322 			if (name && obj)
323 				fsck_put_object_name(options, &entry.oid, "%s%s/",
324 						     name, entry.path);
325 			result = options->walk(obj, OBJ_TREE, data, options);
326 		}
327 		else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
328 			obj = (struct object *)lookup_blob(the_repository, &entry.oid);
329 			if (name && obj)
330 				fsck_put_object_name(options, &entry.oid, "%s%s",
331 						     name, entry.path);
332 			result = options->walk(obj, OBJ_BLOB, data, options);
333 		}
334 		else {
335 			result = error("in tree %s: entry %s has bad mode %.6o",
336 				       fsck_describe_object(options, &tree->object.oid),
337 				       entry.path, entry.mode);
338 		}
339 		if (result < 0)
340 			return result;
341 		if (!res)
342 			res = result;
343 	}
344 	return res;
345 }
346 
fsck_walk_commit(struct commit * commit,void * data,struct fsck_options * options)347 static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_options *options)
348 {
349 	int counter = 0, generation = 0, name_prefix_len = 0;
350 	struct commit_list *parents;
351 	int res;
352 	int result;
353 	const char *name;
354 
355 	if (parse_commit(commit))
356 		return -1;
357 
358 	name = fsck_get_object_name(options, &commit->object.oid);
359 	if (name)
360 		fsck_put_object_name(options, get_commit_tree_oid(commit),
361 				     "%s:", name);
362 
363 	result = options->walk((struct object *)get_commit_tree(commit),
364 			       OBJ_TREE, data, options);
365 	if (result < 0)
366 		return result;
367 	res = result;
368 
369 	parents = commit->parents;
370 	if (name && parents) {
371 		int len = strlen(name), power;
372 
373 		if (len && name[len - 1] == '^') {
374 			generation = 1;
375 			name_prefix_len = len - 1;
376 		}
377 		else { /* parse ~<generation> suffix */
378 			for (generation = 0, power = 1;
379 			     len && isdigit(name[len - 1]);
380 			     power *= 10)
381 				generation += power * (name[--len] - '0');
382 			if (power > 1 && len && name[len - 1] == '~')
383 				name_prefix_len = len - 1;
384 			else {
385 				/* Maybe a non-first parent, e.g. HEAD^2 */
386 				generation = 0;
387 				name_prefix_len = len;
388 			}
389 		}
390 	}
391 
392 	while (parents) {
393 		if (name) {
394 			struct object_id *oid = &parents->item->object.oid;
395 
396 			if (counter++)
397 				fsck_put_object_name(options, oid, "%s^%d",
398 						     name, counter);
399 			else if (generation > 0)
400 				fsck_put_object_name(options, oid, "%.*s~%d",
401 						     name_prefix_len, name,
402 						     generation + 1);
403 			else
404 				fsck_put_object_name(options, oid, "%s^", name);
405 		}
406 		result = options->walk((struct object *)parents->item, OBJ_COMMIT, data, options);
407 		if (result < 0)
408 			return result;
409 		if (!res)
410 			res = result;
411 		parents = parents->next;
412 	}
413 	return res;
414 }
415 
fsck_walk_tag(struct tag * tag,void * data,struct fsck_options * options)416 static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *options)
417 {
418 	const char *name = fsck_get_object_name(options, &tag->object.oid);
419 
420 	if (parse_tag(tag))
421 		return -1;
422 	if (name)
423 		fsck_put_object_name(options, &tag->tagged->oid, "%s", name);
424 	return options->walk(tag->tagged, OBJ_ANY, data, options);
425 }
426 
fsck_walk(struct object * obj,void * data,struct fsck_options * options)427 int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
428 {
429 	if (!obj)
430 		return -1;
431 
432 	if (obj->type == OBJ_NONE)
433 		parse_object(the_repository, &obj->oid);
434 
435 	switch (obj->type) {
436 	case OBJ_BLOB:
437 		return 0;
438 	case OBJ_TREE:
439 		return fsck_walk_tree((struct tree *)obj, data, options);
440 	case OBJ_COMMIT:
441 		return fsck_walk_commit((struct commit *)obj, data, options);
442 	case OBJ_TAG:
443 		return fsck_walk_tag((struct tag *)obj, data, options);
444 	default:
445 		error("Unknown object type for %s",
446 		      fsck_describe_object(options, &obj->oid));
447 		return -1;
448 	}
449 }
450 
451 struct name_stack {
452 	const char **names;
453 	size_t nr, alloc;
454 };
455 
name_stack_push(struct name_stack * stack,const char * name)456 static void name_stack_push(struct name_stack *stack, const char *name)
457 {
458 	ALLOC_GROW(stack->names, stack->nr + 1, stack->alloc);
459 	stack->names[stack->nr++] = name;
460 }
461 
name_stack_pop(struct name_stack * stack)462 static const char *name_stack_pop(struct name_stack *stack)
463 {
464 	return stack->nr ? stack->names[--stack->nr] : NULL;
465 }
466 
name_stack_clear(struct name_stack * stack)467 static void name_stack_clear(struct name_stack *stack)
468 {
469 	FREE_AND_NULL(stack->names);
470 	stack->nr = stack->alloc = 0;
471 }
472 
473 /*
474  * The entries in a tree are ordered in the _path_ order,
475  * which means that a directory entry is ordered by adding
476  * a slash to the end of it.
477  *
478  * So a directory called "a" is ordered _after_ a file
479  * called "a.c", because "a/" sorts after "a.c".
480  */
481 #define TREE_UNORDERED (-1)
482 #define TREE_HAS_DUPS  (-2)
483 
is_less_than_slash(unsigned char c)484 static int is_less_than_slash(unsigned char c)
485 {
486 	return '\0' < c && c < '/';
487 }
488 
verify_ordered(unsigned mode1,const char * name1,unsigned mode2,const char * name2,struct name_stack * candidates)489 static int verify_ordered(unsigned mode1, const char *name1,
490 			  unsigned mode2, const char *name2,
491 			  struct name_stack *candidates)
492 {
493 	int len1 = strlen(name1);
494 	int len2 = strlen(name2);
495 	int len = len1 < len2 ? len1 : len2;
496 	unsigned char c1, c2;
497 	int cmp;
498 
499 	cmp = memcmp(name1, name2, len);
500 	if (cmp < 0)
501 		return 0;
502 	if (cmp > 0)
503 		return TREE_UNORDERED;
504 
505 	/*
506 	 * Ok, the first <len> characters are the same.
507 	 * Now we need to order the next one, but turn
508 	 * a '\0' into a '/' for a directory entry.
509 	 */
510 	c1 = name1[len];
511 	c2 = name2[len];
512 	if (!c1 && !c2)
513 		/*
514 		 * git-write-tree used to write out a nonsense tree that has
515 		 * entries with the same name, one blob and one tree.  Make
516 		 * sure we do not have duplicate entries.
517 		 */
518 		return TREE_HAS_DUPS;
519 	if (!c1 && S_ISDIR(mode1))
520 		c1 = '/';
521 	if (!c2 && S_ISDIR(mode2))
522 		c2 = '/';
523 
524 	/*
525 	 * There can be non-consecutive duplicates due to the implicitly
526 	 * added slash, e.g.:
527 	 *
528 	 *   foo
529 	 *   foo.bar
530 	 *   foo.bar.baz
531 	 *   foo.bar/
532 	 *   foo/
533 	 *
534 	 * Record non-directory candidates (like "foo" and "foo.bar" in
535 	 * the example) on a stack and check directory candidates (like
536 	 * foo/" and "foo.bar/") against that stack.
537 	 */
538 	if (!c1 && is_less_than_slash(c2)) {
539 		name_stack_push(candidates, name1);
540 	} else if (c2 == '/' && is_less_than_slash(c1)) {
541 		for (;;) {
542 			const char *p;
543 			const char *f_name = name_stack_pop(candidates);
544 
545 			if (!f_name)
546 				break;
547 			if (!skip_prefix(name2, f_name, &p))
548 				continue;
549 			if (!*p)
550 				return TREE_HAS_DUPS;
551 			if (is_less_than_slash(*p)) {
552 				name_stack_push(candidates, f_name);
553 				break;
554 			}
555 		}
556 	}
557 
558 	return c1 < c2 ? 0 : TREE_UNORDERED;
559 }
560 
fsck_tree(const struct object_id * tree_oid,const char * buffer,unsigned long size,struct fsck_options * options)561 static int fsck_tree(const struct object_id *tree_oid,
562 		     const char *buffer, unsigned long size,
563 		     struct fsck_options *options)
564 {
565 	int retval = 0;
566 	int has_null_sha1 = 0;
567 	int has_full_path = 0;
568 	int has_empty_name = 0;
569 	int has_dot = 0;
570 	int has_dotdot = 0;
571 	int has_dotgit = 0;
572 	int has_zero_pad = 0;
573 	int has_bad_modes = 0;
574 	int has_dup_entries = 0;
575 	int not_properly_sorted = 0;
576 	struct tree_desc desc;
577 	unsigned o_mode;
578 	const char *o_name;
579 	struct name_stack df_dup_candidates = { NULL };
580 
581 	if (init_tree_desc_gently(&desc, buffer, size)) {
582 		retval += report(options, tree_oid, OBJ_TREE,
583 				 FSCK_MSG_BAD_TREE,
584 				 "cannot be parsed as a tree");
585 		return retval;
586 	}
587 
588 	o_mode = 0;
589 	o_name = NULL;
590 
591 	while (desc.size) {
592 		unsigned short mode;
593 		const char *name, *backslash;
594 		const struct object_id *entry_oid;
595 
596 		entry_oid = tree_entry_extract(&desc, &name, &mode);
597 
598 		has_null_sha1 |= is_null_oid(entry_oid);
599 		has_full_path |= !!strchr(name, '/');
600 		has_empty_name |= !*name;
601 		has_dot |= !strcmp(name, ".");
602 		has_dotdot |= !strcmp(name, "..");
603 		has_dotgit |= is_hfs_dotgit(name) || is_ntfs_dotgit(name);
604 		has_zero_pad |= *(char *)desc.buffer == '0';
605 
606 		if (is_hfs_dotgitmodules(name) || is_ntfs_dotgitmodules(name)) {
607 			if (!S_ISLNK(mode))
608 				oidset_insert(&options->gitmodules_found,
609 					      entry_oid);
610 			else
611 				retval += report(options,
612 						 tree_oid, OBJ_TREE,
613 						 FSCK_MSG_GITMODULES_SYMLINK,
614 						 ".gitmodules is a symbolic link");
615 		}
616 
617 		if (S_ISLNK(mode)) {
618 			if (is_hfs_dotgitignore(name) ||
619 			    is_ntfs_dotgitignore(name))
620 				retval += report(options, tree_oid, OBJ_TREE,
621 						 FSCK_MSG_GITIGNORE_SYMLINK,
622 						 ".gitignore is a symlink");
623 			if (is_hfs_dotgitattributes(name) ||
624 			    is_ntfs_dotgitattributes(name))
625 				retval += report(options, tree_oid, OBJ_TREE,
626 						 FSCK_MSG_GITATTRIBUTES_SYMLINK,
627 						 ".gitattributes is a symlink");
628 			if (is_hfs_dotmailmap(name) ||
629 			    is_ntfs_dotmailmap(name))
630 				retval += report(options, tree_oid, OBJ_TREE,
631 						 FSCK_MSG_MAILMAP_SYMLINK,
632 						 ".mailmap is a symlink");
633 		}
634 
635 		if ((backslash = strchr(name, '\\'))) {
636 			while (backslash) {
637 				backslash++;
638 				has_dotgit |= is_ntfs_dotgit(backslash);
639 				if (is_ntfs_dotgitmodules(backslash)) {
640 					if (!S_ISLNK(mode))
641 						oidset_insert(&options->gitmodules_found,
642 							      entry_oid);
643 					else
644 						retval += report(options, tree_oid, OBJ_TREE,
645 								 FSCK_MSG_GITMODULES_SYMLINK,
646 								 ".gitmodules is a symbolic link");
647 				}
648 				backslash = strchr(backslash, '\\');
649 			}
650 		}
651 
652 		if (update_tree_entry_gently(&desc)) {
653 			retval += report(options, tree_oid, OBJ_TREE,
654 					 FSCK_MSG_BAD_TREE,
655 					 "cannot be parsed as a tree");
656 			break;
657 		}
658 
659 		switch (mode) {
660 		/*
661 		 * Standard modes..
662 		 */
663 		case S_IFREG | 0755:
664 		case S_IFREG | 0644:
665 		case S_IFLNK:
666 		case S_IFDIR:
667 		case S_IFGITLINK:
668 			break;
669 		/*
670 		 * This is nonstandard, but we had a few of these
671 		 * early on when we honored the full set of mode
672 		 * bits..
673 		 */
674 		case S_IFREG | 0664:
675 			if (!options->strict)
676 				break;
677 			/* fallthrough */
678 		default:
679 			has_bad_modes = 1;
680 		}
681 
682 		if (o_name) {
683 			switch (verify_ordered(o_mode, o_name, mode, name,
684 					       &df_dup_candidates)) {
685 			case TREE_UNORDERED:
686 				not_properly_sorted = 1;
687 				break;
688 			case TREE_HAS_DUPS:
689 				has_dup_entries = 1;
690 				break;
691 			default:
692 				break;
693 			}
694 		}
695 
696 		o_mode = mode;
697 		o_name = name;
698 	}
699 
700 	name_stack_clear(&df_dup_candidates);
701 
702 	if (has_null_sha1)
703 		retval += report(options, tree_oid, OBJ_TREE,
704 				 FSCK_MSG_NULL_SHA1,
705 				 "contains entries pointing to null sha1");
706 	if (has_full_path)
707 		retval += report(options, tree_oid, OBJ_TREE,
708 				 FSCK_MSG_FULL_PATHNAME,
709 				 "contains full pathnames");
710 	if (has_empty_name)
711 		retval += report(options, tree_oid, OBJ_TREE,
712 				 FSCK_MSG_EMPTY_NAME,
713 				 "contains empty pathname");
714 	if (has_dot)
715 		retval += report(options, tree_oid, OBJ_TREE,
716 				 FSCK_MSG_HAS_DOT,
717 				 "contains '.'");
718 	if (has_dotdot)
719 		retval += report(options, tree_oid, OBJ_TREE,
720 				 FSCK_MSG_HAS_DOTDOT,
721 				 "contains '..'");
722 	if (has_dotgit)
723 		retval += report(options, tree_oid, OBJ_TREE,
724 				 FSCK_MSG_HAS_DOTGIT,
725 				 "contains '.git'");
726 	if (has_zero_pad)
727 		retval += report(options, tree_oid, OBJ_TREE,
728 				 FSCK_MSG_ZERO_PADDED_FILEMODE,
729 				 "contains zero-padded file modes");
730 	if (has_bad_modes)
731 		retval += report(options, tree_oid, OBJ_TREE,
732 				 FSCK_MSG_BAD_FILEMODE,
733 				 "contains bad file modes");
734 	if (has_dup_entries)
735 		retval += report(options, tree_oid, OBJ_TREE,
736 				 FSCK_MSG_DUPLICATE_ENTRIES,
737 				 "contains duplicate file entries");
738 	if (not_properly_sorted)
739 		retval += report(options, tree_oid, OBJ_TREE,
740 				 FSCK_MSG_TREE_NOT_SORTED,
741 				 "not properly sorted");
742 	return retval;
743 }
744 
verify_headers(const void * data,unsigned long size,const struct object_id * oid,enum object_type type,struct fsck_options * options)745 static int verify_headers(const void *data, unsigned long size,
746 			  const struct object_id *oid, enum object_type type,
747 			  struct fsck_options *options)
748 {
749 	const char *buffer = (const char *)data;
750 	unsigned long i;
751 
752 	for (i = 0; i < size; i++) {
753 		switch (buffer[i]) {
754 		case '\0':
755 			return report(options, oid, type,
756 				FSCK_MSG_NUL_IN_HEADER,
757 				"unterminated header: NUL at offset %ld", i);
758 		case '\n':
759 			if (i + 1 < size && buffer[i + 1] == '\n')
760 				return 0;
761 		}
762 	}
763 
764 	/*
765 	 * We did not find double-LF that separates the header
766 	 * and the body.  Not having a body is not a crime but
767 	 * we do want to see the terminating LF for the last header
768 	 * line.
769 	 */
770 	if (size && buffer[size - 1] == '\n')
771 		return 0;
772 
773 	return report(options, oid, type,
774 		FSCK_MSG_UNTERMINATED_HEADER, "unterminated header");
775 }
776 
fsck_ident(const char ** ident,const struct object_id * oid,enum object_type type,struct fsck_options * options)777 static int fsck_ident(const char **ident,
778 		      const struct object_id *oid, enum object_type type,
779 		      struct fsck_options *options)
780 {
781 	const char *p = *ident;
782 	char *end;
783 
784 	*ident = strchrnul(*ident, '\n');
785 	if (**ident == '\n')
786 		(*ident)++;
787 
788 	if (*p == '<')
789 		return report(options, oid, type, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
790 	p += strcspn(p, "<>\n");
791 	if (*p == '>')
792 		return report(options, oid, type, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name");
793 	if (*p != '<')
794 		return report(options, oid, type, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email");
795 	if (p[-1] != ' ')
796 		return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
797 	p++;
798 	p += strcspn(p, "<>\n");
799 	if (*p != '>')
800 		return report(options, oid, type, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email");
801 	p++;
802 	if (*p != ' ')
803 		return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
804 	p++;
805 	if (*p == '0' && p[1] != ' ')
806 		return report(options, oid, type, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
807 	if (date_overflows(parse_timestamp(p, &end, 10)))
808 		return report(options, oid, type, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow");
809 	if ((end == p || *end != ' '))
810 		return report(options, oid, type, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date");
811 	p = end + 1;
812 	if ((*p != '+' && *p != '-') ||
813 	    !isdigit(p[1]) ||
814 	    !isdigit(p[2]) ||
815 	    !isdigit(p[3]) ||
816 	    !isdigit(p[4]) ||
817 	    (p[5] != '\n'))
818 		return report(options, oid, type, FSCK_MSG_BAD_TIMEZONE, "invalid author/committer line - bad time zone");
819 	p += 6;
820 	return 0;
821 }
822 
fsck_commit(const struct object_id * oid,const char * buffer,unsigned long size,struct fsck_options * options)823 static int fsck_commit(const struct object_id *oid,
824 		       const char *buffer, unsigned long size,
825 		       struct fsck_options *options)
826 {
827 	struct object_id tree_oid, parent_oid;
828 	unsigned author_count;
829 	int err;
830 	const char *buffer_begin = buffer;
831 	const char *p;
832 
833 	if (verify_headers(buffer, size, oid, OBJ_COMMIT, options))
834 		return -1;
835 
836 	if (!skip_prefix(buffer, "tree ", &buffer))
837 		return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
838 	if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') {
839 		err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
840 		if (err)
841 			return err;
842 	}
843 	buffer = p + 1;
844 	while (skip_prefix(buffer, "parent ", &buffer)) {
845 		if (parse_oid_hex(buffer, &parent_oid, &p) || *p != '\n') {
846 			err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
847 			if (err)
848 				return err;
849 		}
850 		buffer = p + 1;
851 	}
852 	author_count = 0;
853 	while (skip_prefix(buffer, "author ", &buffer)) {
854 		author_count++;
855 		err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
856 		if (err)
857 			return err;
858 	}
859 	if (author_count < 1)
860 		err = report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line");
861 	else if (author_count > 1)
862 		err = report(options, oid, OBJ_COMMIT, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines");
863 	if (err)
864 		return err;
865 	if (!skip_prefix(buffer, "committer ", &buffer))
866 		return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
867 	err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
868 	if (err)
869 		return err;
870 	if (memchr(buffer_begin, '\0', size)) {
871 		err = report(options, oid, OBJ_COMMIT, FSCK_MSG_NUL_IN_COMMIT,
872 			     "NUL byte in the commit object body");
873 		if (err)
874 			return err;
875 	}
876 	return 0;
877 }
878 
fsck_tag(const struct object_id * oid,const char * buffer,unsigned long size,struct fsck_options * options)879 static int fsck_tag(const struct object_id *oid, const char *buffer,
880 		    unsigned long size, struct fsck_options *options)
881 {
882 	struct object_id tagged_oid;
883 	int tagged_type;
884 	return fsck_tag_standalone(oid, buffer, size, options, &tagged_oid,
885 				   &tagged_type);
886 }
887 
fsck_tag_standalone(const struct object_id * oid,const char * buffer,unsigned long size,struct fsck_options * options,struct object_id * tagged_oid,int * tagged_type)888 int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
889 			unsigned long size, struct fsck_options *options,
890 			struct object_id *tagged_oid,
891 			int *tagged_type)
892 {
893 	int ret = 0;
894 	char *eol;
895 	struct strbuf sb = STRBUF_INIT;
896 	const char *p;
897 
898 	ret = verify_headers(buffer, size, oid, OBJ_TAG, options);
899 	if (ret)
900 		goto done;
901 
902 	if (!skip_prefix(buffer, "object ", &buffer)) {
903 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
904 		goto done;
905 	}
906 	if (parse_oid_hex(buffer, tagged_oid, &p) || *p != '\n') {
907 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
908 		if (ret)
909 			goto done;
910 	}
911 	buffer = p + 1;
912 
913 	if (!skip_prefix(buffer, "type ", &buffer)) {
914 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
915 		goto done;
916 	}
917 	eol = strchr(buffer, '\n');
918 	if (!eol) {
919 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
920 		goto done;
921 	}
922 	*tagged_type = type_from_string_gently(buffer, eol - buffer, 1);
923 	if (*tagged_type < 0)
924 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_TYPE, "invalid 'type' value");
925 	if (ret)
926 		goto done;
927 	buffer = eol + 1;
928 
929 	if (!skip_prefix(buffer, "tag ", &buffer)) {
930 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line");
931 		goto done;
932 	}
933 	eol = strchr(buffer, '\n');
934 	if (!eol) {
935 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG, "invalid format - unexpected end after 'type' line");
936 		goto done;
937 	}
938 	strbuf_addf(&sb, "refs/tags/%.*s", (int)(eol - buffer), buffer);
939 	if (check_refname_format(sb.buf, 0)) {
940 		ret = report(options, oid, OBJ_TAG,
941 			     FSCK_MSG_BAD_TAG_NAME,
942 			     "invalid 'tag' name: %.*s",
943 			     (int)(eol - buffer), buffer);
944 		if (ret)
945 			goto done;
946 	}
947 	buffer = eol + 1;
948 
949 	if (!skip_prefix(buffer, "tagger ", &buffer)) {
950 		/* early tags do not contain 'tagger' lines; warn only */
951 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line");
952 		if (ret)
953 			goto done;
954 	}
955 	else
956 		ret = fsck_ident(&buffer, oid, OBJ_TAG, options);
957 	if (!*buffer)
958 		goto done;
959 
960 	if (!starts_with(buffer, "\n")) {
961 		/*
962 		 * The verify_headers() check will allow
963 		 * e.g. "[...]tagger <tagger>\nsome
964 		 * garbage\n\nmessage" to pass, thinking "some
965 		 * garbage" could be a custom header. E.g. "mktag"
966 		 * doesn't want any unknown headers.
967 		 */
968 		ret = report(options, oid, OBJ_TAG, FSCK_MSG_EXTRA_HEADER_ENTRY, "invalid format - extra header(s) after 'tagger'");
969 		if (ret)
970 			goto done;
971 	}
972 
973 done:
974 	strbuf_release(&sb);
975 	return ret;
976 }
977 
978 /*
979  * Like builtin/submodule--helper.c's starts_with_dot_slash, but without
980  * relying on the platform-dependent is_dir_sep helper.
981  *
982  * This is for use in checking whether a submodule URL is interpreted as
983  * relative to the current directory on any platform, since \ is a
984  * directory separator on Windows but not on other platforms.
985  */
starts_with_dot_slash(const char * str)986 static int starts_with_dot_slash(const char *str)
987 {
988 	return str[0] == '.' && (str[1] == '/' || str[1] == '\\');
989 }
990 
991 /*
992  * Like starts_with_dot_slash, this is a variant of submodule--helper's
993  * helper of the same name with the twist that it accepts backslash as a
994  * directory separator even on non-Windows platforms.
995  */
starts_with_dot_dot_slash(const char * str)996 static int starts_with_dot_dot_slash(const char *str)
997 {
998 	return str[0] == '.' && starts_with_dot_slash(str + 1);
999 }
1000 
submodule_url_is_relative(const char * url)1001 static int submodule_url_is_relative(const char *url)
1002 {
1003 	return starts_with_dot_slash(url) || starts_with_dot_dot_slash(url);
1004 }
1005 
1006 /*
1007  * Count directory components that a relative submodule URL should chop
1008  * from the remote_url it is to be resolved against.
1009  *
1010  * In other words, this counts "../" components at the start of a
1011  * submodule URL.
1012  *
1013  * Returns the number of directory components to chop and writes a
1014  * pointer to the next character of url after all leading "./" and
1015  * "../" components to out.
1016  */
count_leading_dotdots(const char * url,const char ** out)1017 static int count_leading_dotdots(const char *url, const char **out)
1018 {
1019 	int result = 0;
1020 	while (1) {
1021 		if (starts_with_dot_dot_slash(url)) {
1022 			result++;
1023 			url += strlen("../");
1024 			continue;
1025 		}
1026 		if (starts_with_dot_slash(url)) {
1027 			url += strlen("./");
1028 			continue;
1029 		}
1030 		*out = url;
1031 		return result;
1032 	}
1033 }
1034 /*
1035  * Check whether a transport is implemented by git-remote-curl.
1036  *
1037  * If it is, returns 1 and writes the URL that would be passed to
1038  * git-remote-curl to the "out" parameter.
1039  *
1040  * Otherwise, returns 0 and leaves "out" untouched.
1041  *
1042  * Examples:
1043  *   http::https://example.com/repo.git -> 1, https://example.com/repo.git
1044  *   https://example.com/repo.git -> 1, https://example.com/repo.git
1045  *   git://example.com/repo.git -> 0
1046  *
1047  * This is for use in checking for previously exploitable bugs that
1048  * required a submodule URL to be passed to git-remote-curl.
1049  */
url_to_curl_url(const char * url,const char ** out)1050 static int url_to_curl_url(const char *url, const char **out)
1051 {
1052 	/*
1053 	 * We don't need to check for case-aliases, "http.exe", and so
1054 	 * on because in the default configuration, is_transport_allowed
1055 	 * prevents URLs with those schemes from being cloned
1056 	 * automatically.
1057 	 */
1058 	if (skip_prefix(url, "http::", out) ||
1059 	    skip_prefix(url, "https::", out) ||
1060 	    skip_prefix(url, "ftp::", out) ||
1061 	    skip_prefix(url, "ftps::", out))
1062 		return 1;
1063 	if (starts_with(url, "http://") ||
1064 	    starts_with(url, "https://") ||
1065 	    starts_with(url, "ftp://") ||
1066 	    starts_with(url, "ftps://")) {
1067 		*out = url;
1068 		return 1;
1069 	}
1070 	return 0;
1071 }
1072 
check_submodule_url(const char * url)1073 static int check_submodule_url(const char *url)
1074 {
1075 	const char *curl_url;
1076 
1077 	if (looks_like_command_line_option(url))
1078 		return -1;
1079 
1080 	if (submodule_url_is_relative(url) || starts_with(url, "git://")) {
1081 		char *decoded;
1082 		const char *next;
1083 		int has_nl;
1084 
1085 		/*
1086 		 * This could be appended to an http URL and url-decoded;
1087 		 * check for malicious characters.
1088 		 */
1089 		decoded = url_decode(url);
1090 		has_nl = !!strchr(decoded, '\n');
1091 
1092 		free(decoded);
1093 		if (has_nl)
1094 			return -1;
1095 
1096 		/*
1097 		 * URLs which escape their root via "../" can overwrite
1098 		 * the host field and previous components, resolving to
1099 		 * URLs like https::example.com/submodule.git and
1100 		 * https:///example.com/submodule.git that were
1101 		 * susceptible to CVE-2020-11008.
1102 		 */
1103 		if (count_leading_dotdots(url, &next) > 0 &&
1104 		    (*next == ':' || *next == '/'))
1105 			return -1;
1106 	}
1107 
1108 	else if (url_to_curl_url(url, &curl_url)) {
1109 		struct credential c = CREDENTIAL_INIT;
1110 		int ret = 0;
1111 		if (credential_from_url_gently(&c, curl_url, 1) ||
1112 		    !*c.host)
1113 			ret = -1;
1114 		credential_clear(&c);
1115 		return ret;
1116 	}
1117 
1118 	return 0;
1119 }
1120 
1121 struct fsck_gitmodules_data {
1122 	const struct object_id *oid;
1123 	struct fsck_options *options;
1124 	int ret;
1125 };
1126 
fsck_gitmodules_fn(const char * var,const char * value,void * vdata)1127 static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
1128 {
1129 	struct fsck_gitmodules_data *data = vdata;
1130 	const char *subsection, *key;
1131 	size_t subsection_len;
1132 	char *name;
1133 
1134 	if (parse_config_key(var, "submodule", &subsection, &subsection_len, &key) < 0 ||
1135 	    !subsection)
1136 		return 0;
1137 
1138 	name = xmemdupz(subsection, subsection_len);
1139 	if (check_submodule_name(name) < 0)
1140 		data->ret |= report(data->options,
1141 				    data->oid, OBJ_BLOB,
1142 				    FSCK_MSG_GITMODULES_NAME,
1143 				    "disallowed submodule name: %s",
1144 				    name);
1145 	if (!strcmp(key, "url") && value &&
1146 	    check_submodule_url(value) < 0)
1147 		data->ret |= report(data->options,
1148 				    data->oid, OBJ_BLOB,
1149 				    FSCK_MSG_GITMODULES_URL,
1150 				    "disallowed submodule url: %s",
1151 				    value);
1152 	if (!strcmp(key, "path") && value &&
1153 	    looks_like_command_line_option(value))
1154 		data->ret |= report(data->options,
1155 				    data->oid, OBJ_BLOB,
1156 				    FSCK_MSG_GITMODULES_PATH,
1157 				    "disallowed submodule path: %s",
1158 				    value);
1159 	if (!strcmp(key, "update") && value &&
1160 	    parse_submodule_update_type(value) == SM_UPDATE_COMMAND)
1161 		data->ret |= report(data->options, data->oid, OBJ_BLOB,
1162 				    FSCK_MSG_GITMODULES_UPDATE,
1163 				    "disallowed submodule update setting: %s",
1164 				    value);
1165 	free(name);
1166 
1167 	return 0;
1168 }
1169 
fsck_blob(const struct object_id * oid,const char * buf,unsigned long size,struct fsck_options * options)1170 static int fsck_blob(const struct object_id *oid, const char *buf,
1171 		     unsigned long size, struct fsck_options *options)
1172 {
1173 	struct fsck_gitmodules_data data;
1174 	struct config_options config_opts = { 0 };
1175 
1176 	if (!oidset_contains(&options->gitmodules_found, oid))
1177 		return 0;
1178 	oidset_insert(&options->gitmodules_done, oid);
1179 
1180 	if (object_on_skiplist(options, oid))
1181 		return 0;
1182 
1183 	if (!buf) {
1184 		/*
1185 		 * A missing buffer here is a sign that the caller found the
1186 		 * blob too gigantic to load into memory. Let's just consider
1187 		 * that an error.
1188 		 */
1189 		return report(options, oid, OBJ_BLOB,
1190 			      FSCK_MSG_GITMODULES_LARGE,
1191 			      ".gitmodules too large to parse");
1192 	}
1193 
1194 	data.oid = oid;
1195 	data.options = options;
1196 	data.ret = 0;
1197 	config_opts.error_action = CONFIG_ERROR_SILENT;
1198 	if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
1199 				".gitmodules", buf, size, &data, &config_opts))
1200 		data.ret |= report(options, oid, OBJ_BLOB,
1201 				   FSCK_MSG_GITMODULES_PARSE,
1202 				   "could not parse gitmodules blob");
1203 
1204 	return data.ret;
1205 }
1206 
fsck_object(struct object * obj,void * data,unsigned long size,struct fsck_options * options)1207 int fsck_object(struct object *obj, void *data, unsigned long size,
1208 	struct fsck_options *options)
1209 {
1210 	if (!obj)
1211 		return report(options, NULL, OBJ_NONE, FSCK_MSG_BAD_OBJECT_SHA1, "no valid object to fsck");
1212 
1213 	if (obj->type == OBJ_BLOB)
1214 		return fsck_blob(&obj->oid, data, size, options);
1215 	if (obj->type == OBJ_TREE)
1216 		return fsck_tree(&obj->oid, data, size, options);
1217 	if (obj->type == OBJ_COMMIT)
1218 		return fsck_commit(&obj->oid, data, size, options);
1219 	if (obj->type == OBJ_TAG)
1220 		return fsck_tag(&obj->oid, data, size, options);
1221 
1222 	return report(options, &obj->oid, obj->type,
1223 		      FSCK_MSG_UNKNOWN_TYPE,
1224 		      "unknown type '%d' (internal fsck error)",
1225 		      obj->type);
1226 }
1227 
fsck_error_function(struct fsck_options * o,const struct object_id * oid,enum object_type object_type,enum fsck_msg_type msg_type,enum fsck_msg_id msg_id,const char * message)1228 int fsck_error_function(struct fsck_options *o,
1229 			const struct object_id *oid,
1230 			enum object_type object_type,
1231 			enum fsck_msg_type msg_type,
1232 			enum fsck_msg_id msg_id,
1233 			const char *message)
1234 {
1235 	if (msg_type == FSCK_WARN) {
1236 		warning("object %s: %s", fsck_describe_object(o, oid), message);
1237 		return 0;
1238 	}
1239 	error("object %s: %s", fsck_describe_object(o, oid), message);
1240 	return 1;
1241 }
1242 
fsck_finish(struct fsck_options * options)1243 int fsck_finish(struct fsck_options *options)
1244 {
1245 	int ret = 0;
1246 	struct oidset_iter iter;
1247 	const struct object_id *oid;
1248 
1249 	oidset_iter_init(&options->gitmodules_found, &iter);
1250 	while ((oid = oidset_iter_next(&iter))) {
1251 		enum object_type type;
1252 		unsigned long size;
1253 		char *buf;
1254 
1255 		if (oidset_contains(&options->gitmodules_done, oid))
1256 			continue;
1257 
1258 		buf = read_object_file(oid, &type, &size);
1259 		if (!buf) {
1260 			if (is_promisor_object(oid))
1261 				continue;
1262 			ret |= report(options,
1263 				      oid, OBJ_BLOB,
1264 				      FSCK_MSG_GITMODULES_MISSING,
1265 				      "unable to read .gitmodules blob");
1266 			continue;
1267 		}
1268 
1269 		if (type == OBJ_BLOB)
1270 			ret |= fsck_blob(oid, buf, size, options);
1271 		else
1272 			ret |= report(options,
1273 				      oid, type,
1274 				      FSCK_MSG_GITMODULES_BLOB,
1275 				      "non-blob found at .gitmodules");
1276 		free(buf);
1277 	}
1278 
1279 
1280 	oidset_clear(&options->gitmodules_found);
1281 	oidset_clear(&options->gitmodules_done);
1282 	return ret;
1283 }
1284 
git_fsck_config(const char * var,const char * value,void * cb)1285 int git_fsck_config(const char *var, const char *value, void *cb)
1286 {
1287 	struct fsck_options *options = cb;
1288 	if (strcmp(var, "fsck.skiplist") == 0) {
1289 		const char *path;
1290 		struct strbuf sb = STRBUF_INIT;
1291 
1292 		if (git_config_pathname(&path, var, value))
1293 			return 1;
1294 		strbuf_addf(&sb, "skiplist=%s", path);
1295 		free((char *)path);
1296 		fsck_set_msg_types(options, sb.buf);
1297 		strbuf_release(&sb);
1298 		return 0;
1299 	}
1300 
1301 	if (skip_prefix(var, "fsck.", &var)) {
1302 		fsck_set_msg_type(options, var, value);
1303 		return 0;
1304 	}
1305 
1306 	return git_default_config(var, value, cb);
1307 }
1308 
1309 /*
1310  * Custom error callbacks that are used in more than one place.
1311  */
1312 
fsck_error_cb_print_missing_gitmodules(struct fsck_options * o,const struct object_id * oid,enum object_type object_type,enum fsck_msg_type msg_type,enum fsck_msg_id msg_id,const char * message)1313 int fsck_error_cb_print_missing_gitmodules(struct fsck_options *o,
1314 					   const struct object_id *oid,
1315 					   enum object_type object_type,
1316 					   enum fsck_msg_type msg_type,
1317 					   enum fsck_msg_id msg_id,
1318 					   const char *message)
1319 {
1320 	if (msg_id == FSCK_MSG_GITMODULES_MISSING) {
1321 		puts(oid_to_hex(oid));
1322 		return 0;
1323 	}
1324 	return fsck_error_function(o, oid, object_type, msg_type, msg_id, message);
1325 }
1326