Coverage Report

Created: 2025-12-31 07:01

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