fsck.con commit cache: convert get_graft_file to handle arbitrary repositories (0437a2e)
   1#include "cache.h"
   2#include "object-store.h"
   3#include "object.h"
   4#include "blob.h"
   5#include "tree.h"
   6#include "tree-walk.h"
   7#include "commit.h"
   8#include "tag.h"
   9#include "fsck.h"
  10#include "refs.h"
  11#include "utf8.h"
  12#include "sha1-array.h"
  13#include "decorate.h"
  14
  15#define FSCK_FATAL -1
  16#define FSCK_INFO -2
  17
  18#define FOREACH_MSG_ID(FUNC) \
  19        /* fatal errors */ \
  20        FUNC(NUL_IN_HEADER, FATAL) \
  21        FUNC(UNTERMINATED_HEADER, FATAL) \
  22        /* errors */ \
  23        FUNC(BAD_DATE, ERROR) \
  24        FUNC(BAD_DATE_OVERFLOW, ERROR) \
  25        FUNC(BAD_EMAIL, ERROR) \
  26        FUNC(BAD_NAME, ERROR) \
  27        FUNC(BAD_OBJECT_SHA1, ERROR) \
  28        FUNC(BAD_PARENT_SHA1, ERROR) \
  29        FUNC(BAD_TAG_OBJECT, ERROR) \
  30        FUNC(BAD_TIMEZONE, ERROR) \
  31        FUNC(BAD_TREE, ERROR) \
  32        FUNC(BAD_TREE_SHA1, ERROR) \
  33        FUNC(BAD_TYPE, ERROR) \
  34        FUNC(DUPLICATE_ENTRIES, ERROR) \
  35        FUNC(MISSING_AUTHOR, ERROR) \
  36        FUNC(MISSING_COMMITTER, ERROR) \
  37        FUNC(MISSING_EMAIL, ERROR) \
  38        FUNC(MISSING_GRAFT, ERROR) \
  39        FUNC(MISSING_NAME_BEFORE_EMAIL, ERROR) \
  40        FUNC(MISSING_OBJECT, ERROR) \
  41        FUNC(MISSING_PARENT, ERROR) \
  42        FUNC(MISSING_SPACE_BEFORE_DATE, ERROR) \
  43        FUNC(MISSING_SPACE_BEFORE_EMAIL, ERROR) \
  44        FUNC(MISSING_TAG, ERROR) \
  45        FUNC(MISSING_TAG_ENTRY, ERROR) \
  46        FUNC(MISSING_TAG_OBJECT, ERROR) \
  47        FUNC(MISSING_TREE, ERROR) \
  48        FUNC(MISSING_TYPE, ERROR) \
  49        FUNC(MISSING_TYPE_ENTRY, ERROR) \
  50        FUNC(MULTIPLE_AUTHORS, ERROR) \
  51        FUNC(TAG_OBJECT_NOT_TAG, ERROR) \
  52        FUNC(TREE_NOT_SORTED, ERROR) \
  53        FUNC(UNKNOWN_TYPE, ERROR) \
  54        FUNC(ZERO_PADDED_DATE, ERROR) \
  55        /* warnings */ \
  56        FUNC(BAD_FILEMODE, WARN) \
  57        FUNC(EMPTY_NAME, WARN) \
  58        FUNC(FULL_PATHNAME, WARN) \
  59        FUNC(HAS_DOT, WARN) \
  60        FUNC(HAS_DOTDOT, WARN) \
  61        FUNC(HAS_DOTGIT, WARN) \
  62        FUNC(NULL_SHA1, WARN) \
  63        FUNC(ZERO_PADDED_FILEMODE, WARN) \
  64        FUNC(NUL_IN_COMMIT, WARN) \
  65        /* infos (reported as warnings, but ignored by default) */ \
  66        FUNC(BAD_TAG_NAME, INFO) \
  67        FUNC(MISSING_TAGGER_ENTRY, INFO)
  68
  69#define MSG_ID(id, msg_type) FSCK_MSG_##id,
  70enum fsck_msg_id {
  71        FOREACH_MSG_ID(MSG_ID)
  72        FSCK_MSG_MAX
  73};
  74#undef MSG_ID
  75
  76#define STR(x) #x
  77#define MSG_ID(id, msg_type) { STR(id), NULL, FSCK_##msg_type },
  78static struct {
  79        const char *id_string;
  80        const char *downcased;
  81        int msg_type;
  82} msg_id_info[FSCK_MSG_MAX + 1] = {
  83        FOREACH_MSG_ID(MSG_ID)
  84        { NULL, NULL, -1 }
  85};
  86#undef MSG_ID
  87
  88static int parse_msg_id(const char *text)
  89{
  90        int i;
  91
  92        if (!msg_id_info[0].downcased) {
  93                /* convert id_string to lower case, without underscores. */
  94                for (i = 0; i < FSCK_MSG_MAX; i++) {
  95                        const char *p = msg_id_info[i].id_string;
  96                        int len = strlen(p);
  97                        char *q = xmalloc(len);
  98
  99                        msg_id_info[i].downcased = q;
 100                        while (*p)
 101                                if (*p == '_')
 102                                        p++;
 103                                else
 104                                        *(q)++ = tolower(*(p)++);
 105                        *q = '\0';
 106                }
 107        }
 108
 109        for (i = 0; i < FSCK_MSG_MAX; i++)
 110                if (!strcmp(text, msg_id_info[i].downcased))
 111                        return i;
 112
 113        return -1;
 114}
 115
 116static int fsck_msg_type(enum fsck_msg_id msg_id,
 117        struct fsck_options *options)
 118{
 119        int msg_type;
 120
 121        assert(msg_id >= 0 && msg_id < FSCK_MSG_MAX);
 122
 123        if (options->msg_type)
 124                msg_type = options->msg_type[msg_id];
 125        else {
 126                msg_type = msg_id_info[msg_id].msg_type;
 127                if (options->strict && msg_type == FSCK_WARN)
 128                        msg_type = FSCK_ERROR;
 129        }
 130
 131        return msg_type;
 132}
 133
 134static void init_skiplist(struct fsck_options *options, const char *path)
 135{
 136        static struct oid_array skiplist = OID_ARRAY_INIT;
 137        int sorted, fd;
 138        char buffer[GIT_MAX_HEXSZ + 1];
 139        struct object_id oid;
 140
 141        if (options->skiplist)
 142                sorted = options->skiplist->sorted;
 143        else {
 144                sorted = 1;
 145                options->skiplist = &skiplist;
 146        }
 147
 148        fd = open(path, O_RDONLY);
 149        if (fd < 0)
 150                die("Could not open skip list: %s", path);
 151        for (;;) {
 152                const char *p;
 153                int result = read_in_full(fd, buffer, sizeof(buffer));
 154                if (result < 0)
 155                        die_errno("Could not read '%s'", path);
 156                if (!result)
 157                        break;
 158                if (parse_oid_hex(buffer, &oid, &p) || *p != '\n')
 159                        die("Invalid SHA-1: %s", buffer);
 160                oid_array_append(&skiplist, &oid);
 161                if (sorted && skiplist.nr > 1 &&
 162                                oidcmp(&skiplist.oid[skiplist.nr - 2],
 163                                       &oid) > 0)
 164                        sorted = 0;
 165        }
 166        close(fd);
 167
 168        if (sorted)
 169                skiplist.sorted = 1;
 170}
 171
 172static int parse_msg_type(const char *str)
 173{
 174        if (!strcmp(str, "error"))
 175                return FSCK_ERROR;
 176        else if (!strcmp(str, "warn"))
 177                return FSCK_WARN;
 178        else if (!strcmp(str, "ignore"))
 179                return FSCK_IGNORE;
 180        else
 181                die("Unknown fsck message type: '%s'", str);
 182}
 183
 184int is_valid_msg_type(const char *msg_id, const char *msg_type)
 185{
 186        if (parse_msg_id(msg_id) < 0)
 187                return 0;
 188        parse_msg_type(msg_type);
 189        return 1;
 190}
 191
 192void fsck_set_msg_type(struct fsck_options *options,
 193                const char *msg_id, const char *msg_type)
 194{
 195        int id = parse_msg_id(msg_id), type;
 196
 197        if (id < 0)
 198                die("Unhandled message id: %s", msg_id);
 199        type = parse_msg_type(msg_type);
 200
 201        if (type != FSCK_ERROR && msg_id_info[id].msg_type == FSCK_FATAL)
 202                die("Cannot demote %s to %s", msg_id, msg_type);
 203
 204        if (!options->msg_type) {
 205                int i;
 206                int *msg_type;
 207                ALLOC_ARRAY(msg_type, FSCK_MSG_MAX);
 208                for (i = 0; i < FSCK_MSG_MAX; i++)
 209                        msg_type[i] = fsck_msg_type(i, options);
 210                options->msg_type = msg_type;
 211        }
 212
 213        options->msg_type[id] = type;
 214}
 215
 216void fsck_set_msg_types(struct fsck_options *options, const char *values)
 217{
 218        char *buf = xstrdup(values), *to_free = buf;
 219        int done = 0;
 220
 221        while (!done) {
 222                int len = strcspn(buf, " ,|"), equal;
 223
 224                done = !buf[len];
 225                if (!len) {
 226                        buf++;
 227                        continue;
 228                }
 229                buf[len] = '\0';
 230
 231                for (equal = 0;
 232                     equal < len && buf[equal] != '=' && buf[equal] != ':';
 233                     equal++)
 234                        buf[equal] = tolower(buf[equal]);
 235                buf[equal] = '\0';
 236
 237                if (!strcmp(buf, "skiplist")) {
 238                        if (equal == len)
 239                                die("skiplist requires a path");
 240                        init_skiplist(options, buf + equal + 1);
 241                        buf += len + 1;
 242                        continue;
 243                }
 244
 245                if (equal == len)
 246                        die("Missing '=': '%s'", buf);
 247
 248                fsck_set_msg_type(options, buf, buf + equal + 1);
 249                buf += len + 1;
 250        }
 251        free(to_free);
 252}
 253
 254static void append_msg_id(struct strbuf *sb, const char *msg_id)
 255{
 256        for (;;) {
 257                char c = *(msg_id)++;
 258
 259                if (!c)
 260                        break;
 261                if (c != '_')
 262                        strbuf_addch(sb, tolower(c));
 263                else {
 264                        assert(*msg_id);
 265                        strbuf_addch(sb, *(msg_id)++);
 266                }
 267        }
 268
 269        strbuf_addstr(sb, ": ");
 270}
 271
 272__attribute__((format (printf, 4, 5)))
 273static int report(struct fsck_options *options, struct object *object,
 274        enum fsck_msg_id id, const char *fmt, ...)
 275{
 276        va_list ap;
 277        struct strbuf sb = STRBUF_INIT;
 278        int msg_type = fsck_msg_type(id, options), result;
 279
 280        if (msg_type == FSCK_IGNORE)
 281                return 0;
 282
 283        if (options->skiplist && object &&
 284                        oid_array_lookup(options->skiplist, &object->oid) >= 0)
 285                return 0;
 286
 287        if (msg_type == FSCK_FATAL)
 288                msg_type = FSCK_ERROR;
 289        else if (msg_type == FSCK_INFO)
 290                msg_type = FSCK_WARN;
 291
 292        append_msg_id(&sb, msg_id_info[id].id_string);
 293
 294        va_start(ap, fmt);
 295        strbuf_vaddf(&sb, fmt, ap);
 296        result = options->error_func(options, object, msg_type, sb.buf);
 297        strbuf_release(&sb);
 298        va_end(ap);
 299
 300        return result;
 301}
 302
 303static char *get_object_name(struct fsck_options *options, struct object *obj)
 304{
 305        if (!options->object_names)
 306                return NULL;
 307        return lookup_decoration(options->object_names, obj);
 308}
 309
 310static void put_object_name(struct fsck_options *options, struct object *obj,
 311        const char *fmt, ...)
 312{
 313        va_list ap;
 314        struct strbuf buf = STRBUF_INIT;
 315        char *existing;
 316
 317        if (!options->object_names)
 318                return;
 319        existing = lookup_decoration(options->object_names, obj);
 320        if (existing)
 321                return;
 322        va_start(ap, fmt);
 323        strbuf_vaddf(&buf, fmt, ap);
 324        add_decoration(options->object_names, obj, strbuf_detach(&buf, NULL));
 325        va_end(ap);
 326}
 327
 328static const char *describe_object(struct fsck_options *o, struct object *obj)
 329{
 330        static struct strbuf buf = STRBUF_INIT;
 331        char *name;
 332
 333        strbuf_reset(&buf);
 334        strbuf_addstr(&buf, oid_to_hex(&obj->oid));
 335        if (o->object_names && (name = lookup_decoration(o->object_names, obj)))
 336                strbuf_addf(&buf, " (%s)", name);
 337
 338        return buf.buf;
 339}
 340
 341static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *options)
 342{
 343        struct tree_desc desc;
 344        struct name_entry entry;
 345        int res = 0;
 346        const char *name;
 347
 348        if (parse_tree(tree))
 349                return -1;
 350
 351        name = get_object_name(options, &tree->object);
 352        if (init_tree_desc_gently(&desc, tree->buffer, tree->size))
 353                return -1;
 354        while (tree_entry_gently(&desc, &entry)) {
 355                struct object *obj;
 356                int result;
 357
 358                if (S_ISGITLINK(entry.mode))
 359                        continue;
 360
 361                if (S_ISDIR(entry.mode)) {
 362                        obj = (struct object *)lookup_tree(entry.oid);
 363                        if (name && obj)
 364                                put_object_name(options, obj, "%s%s/", name,
 365                                        entry.path);
 366                        result = options->walk(obj, OBJ_TREE, data, options);
 367                }
 368                else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
 369                        obj = (struct object *)lookup_blob(entry.oid);
 370                        if (name && obj)
 371                                put_object_name(options, obj, "%s%s", name,
 372                                        entry.path);
 373                        result = options->walk(obj, OBJ_BLOB, data, options);
 374                }
 375                else {
 376                        result = error("in tree %s: entry %s has bad mode %.6o",
 377                                        describe_object(options, &tree->object), entry.path, entry.mode);
 378                }
 379                if (result < 0)
 380                        return result;
 381                if (!res)
 382                        res = result;
 383        }
 384        return res;
 385}
 386
 387static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_options *options)
 388{
 389        int counter = 0, generation = 0, name_prefix_len = 0;
 390        struct commit_list *parents;
 391        int res;
 392        int result;
 393        const char *name;
 394
 395        if (parse_commit(commit))
 396                return -1;
 397
 398        name = get_object_name(options, &commit->object);
 399        if (name)
 400                put_object_name(options, &commit->tree->object, "%s:", name);
 401
 402        result = options->walk((struct object *)commit->tree, OBJ_TREE, data, options);
 403        if (result < 0)
 404                return result;
 405        res = result;
 406
 407        parents = commit->parents;
 408        if (name && parents) {
 409                int len = strlen(name), power;
 410
 411                if (len && name[len - 1] == '^') {
 412                        generation = 1;
 413                        name_prefix_len = len - 1;
 414                }
 415                else { /* parse ~<generation> suffix */
 416                        for (generation = 0, power = 1;
 417                             len && isdigit(name[len - 1]);
 418                             power *= 10)
 419                                generation += power * (name[--len] - '0');
 420                        if (power > 1 && len && name[len - 1] == '~')
 421                                name_prefix_len = len - 1;
 422                }
 423        }
 424
 425        while (parents) {
 426                if (name) {
 427                        struct object *obj = &parents->item->object;
 428
 429                        if (++counter > 1)
 430                                put_object_name(options, obj, "%s^%d",
 431                                        name, counter);
 432                        else if (generation > 0)
 433                                put_object_name(options, obj, "%.*s~%d",
 434                                        name_prefix_len, name, generation + 1);
 435                        else
 436                                put_object_name(options, obj, "%s^", name);
 437                }
 438                result = options->walk((struct object *)parents->item, OBJ_COMMIT, data, options);
 439                if (result < 0)
 440                        return result;
 441                if (!res)
 442                        res = result;
 443                parents = parents->next;
 444        }
 445        return res;
 446}
 447
 448static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *options)
 449{
 450        char *name = get_object_name(options, &tag->object);
 451
 452        if (parse_tag(tag))
 453                return -1;
 454        if (name)
 455                put_object_name(options, tag->tagged, "%s", name);
 456        return options->walk(tag->tagged, OBJ_ANY, data, options);
 457}
 458
 459int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
 460{
 461        if (!obj)
 462                return -1;
 463
 464        if (obj->type == OBJ_NONE)
 465                parse_object(&obj->oid);
 466
 467        switch (obj->type) {
 468        case OBJ_BLOB:
 469                return 0;
 470        case OBJ_TREE:
 471                return fsck_walk_tree((struct tree *)obj, data, options);
 472        case OBJ_COMMIT:
 473                return fsck_walk_commit((struct commit *)obj, data, options);
 474        case OBJ_TAG:
 475                return fsck_walk_tag((struct tag *)obj, data, options);
 476        default:
 477                error("Unknown object type for %s", describe_object(options, obj));
 478                return -1;
 479        }
 480}
 481
 482/*
 483 * The entries in a tree are ordered in the _path_ order,
 484 * which means that a directory entry is ordered by adding
 485 * a slash to the end of it.
 486 *
 487 * So a directory called "a" is ordered _after_ a file
 488 * called "a.c", because "a/" sorts after "a.c".
 489 */
 490#define TREE_UNORDERED (-1)
 491#define TREE_HAS_DUPS  (-2)
 492
 493static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
 494{
 495        int len1 = strlen(name1);
 496        int len2 = strlen(name2);
 497        int len = len1 < len2 ? len1 : len2;
 498        unsigned char c1, c2;
 499        int cmp;
 500
 501        cmp = memcmp(name1, name2, len);
 502        if (cmp < 0)
 503                return 0;
 504        if (cmp > 0)
 505                return TREE_UNORDERED;
 506
 507        /*
 508         * Ok, the first <len> characters are the same.
 509         * Now we need to order the next one, but turn
 510         * a '\0' into a '/' for a directory entry.
 511         */
 512        c1 = name1[len];
 513        c2 = name2[len];
 514        if (!c1 && !c2)
 515                /*
 516                 * git-write-tree used to write out a nonsense tree that has
 517                 * entries with the same name, one blob and one tree.  Make
 518                 * sure we do not have duplicate entries.
 519                 */
 520                return TREE_HAS_DUPS;
 521        if (!c1 && S_ISDIR(mode1))
 522                c1 = '/';
 523        if (!c2 && S_ISDIR(mode2))
 524                c2 = '/';
 525        return c1 < c2 ? 0 : TREE_UNORDERED;
 526}
 527
 528static int fsck_tree(struct tree *item, struct fsck_options *options)
 529{
 530        int retval = 0;
 531        int has_null_sha1 = 0;
 532        int has_full_path = 0;
 533        int has_empty_name = 0;
 534        int has_dot = 0;
 535        int has_dotdot = 0;
 536        int has_dotgit = 0;
 537        int has_zero_pad = 0;
 538        int has_bad_modes = 0;
 539        int has_dup_entries = 0;
 540        int not_properly_sorted = 0;
 541        struct tree_desc desc;
 542        unsigned o_mode;
 543        const char *o_name;
 544
 545        if (init_tree_desc_gently(&desc, item->buffer, item->size)) {
 546                retval += report(options, &item->object, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
 547                return retval;
 548        }
 549
 550        o_mode = 0;
 551        o_name = NULL;
 552
 553        while (desc.size) {
 554                unsigned mode;
 555                const char *name;
 556                const struct object_id *oid;
 557
 558                oid = tree_entry_extract(&desc, &name, &mode);
 559
 560                has_null_sha1 |= is_null_oid(oid);
 561                has_full_path |= !!strchr(name, '/');
 562                has_empty_name |= !*name;
 563                has_dot |= !strcmp(name, ".");
 564                has_dotdot |= !strcmp(name, "..");
 565                has_dotgit |= (!strcmp(name, ".git") ||
 566                               is_hfs_dotgit(name) ||
 567                               is_ntfs_dotgit(name));
 568                has_zero_pad |= *(char *)desc.buffer == '0';
 569                if (update_tree_entry_gently(&desc)) {
 570                        retval += report(options, &item->object, FSCK_MSG_BAD_TREE, "cannot be parsed as a tree");
 571                        break;
 572                }
 573
 574                switch (mode) {
 575                /*
 576                 * Standard modes..
 577                 */
 578                case S_IFREG | 0755:
 579                case S_IFREG | 0644:
 580                case S_IFLNK:
 581                case S_IFDIR:
 582                case S_IFGITLINK:
 583                        break;
 584                /*
 585                 * This is nonstandard, but we had a few of these
 586                 * early on when we honored the full set of mode
 587                 * bits..
 588                 */
 589                case S_IFREG | 0664:
 590                        if (!options->strict)
 591                                break;
 592                        /* fallthrough */
 593                default:
 594                        has_bad_modes = 1;
 595                }
 596
 597                if (o_name) {
 598                        switch (verify_ordered(o_mode, o_name, mode, name)) {
 599                        case TREE_UNORDERED:
 600                                not_properly_sorted = 1;
 601                                break;
 602                        case TREE_HAS_DUPS:
 603                                has_dup_entries = 1;
 604                                break;
 605                        default:
 606                                break;
 607                        }
 608                }
 609
 610                o_mode = mode;
 611                o_name = name;
 612        }
 613
 614        if (has_null_sha1)
 615                retval += report(options, &item->object, FSCK_MSG_NULL_SHA1, "contains entries pointing to null sha1");
 616        if (has_full_path)
 617                retval += report(options, &item->object, FSCK_MSG_FULL_PATHNAME, "contains full pathnames");
 618        if (has_empty_name)
 619                retval += report(options, &item->object, FSCK_MSG_EMPTY_NAME, "contains empty pathname");
 620        if (has_dot)
 621                retval += report(options, &item->object, FSCK_MSG_HAS_DOT, "contains '.'");
 622        if (has_dotdot)
 623                retval += report(options, &item->object, FSCK_MSG_HAS_DOTDOT, "contains '..'");
 624        if (has_dotgit)
 625                retval += report(options, &item->object, FSCK_MSG_HAS_DOTGIT, "contains '.git'");
 626        if (has_zero_pad)
 627                retval += report(options, &item->object, FSCK_MSG_ZERO_PADDED_FILEMODE, "contains zero-padded file modes");
 628        if (has_bad_modes)
 629                retval += report(options, &item->object, FSCK_MSG_BAD_FILEMODE, "contains bad file modes");
 630        if (has_dup_entries)
 631                retval += report(options, &item->object, FSCK_MSG_DUPLICATE_ENTRIES, "contains duplicate file entries");
 632        if (not_properly_sorted)
 633                retval += report(options, &item->object, FSCK_MSG_TREE_NOT_SORTED, "not properly sorted");
 634        return retval;
 635}
 636
 637static int verify_headers(const void *data, unsigned long size,
 638                          struct object *obj, struct fsck_options *options)
 639{
 640        const char *buffer = (const char *)data;
 641        unsigned long i;
 642
 643        for (i = 0; i < size; i++) {
 644                switch (buffer[i]) {
 645                case '\0':
 646                        return report(options, obj,
 647                                FSCK_MSG_NUL_IN_HEADER,
 648                                "unterminated header: NUL at offset %ld", i);
 649                case '\n':
 650                        if (i + 1 < size && buffer[i + 1] == '\n')
 651                                return 0;
 652                }
 653        }
 654
 655        /*
 656         * We did not find double-LF that separates the header
 657         * and the body.  Not having a body is not a crime but
 658         * we do want to see the terminating LF for the last header
 659         * line.
 660         */
 661        if (size && buffer[size - 1] == '\n')
 662                return 0;
 663
 664        return report(options, obj,
 665                FSCK_MSG_UNTERMINATED_HEADER, "unterminated header");
 666}
 667
 668static int fsck_ident(const char **ident, struct object *obj, struct fsck_options *options)
 669{
 670        const char *p = *ident;
 671        char *end;
 672
 673        *ident = strchrnul(*ident, '\n');
 674        if (**ident == '\n')
 675                (*ident)++;
 676
 677        if (*p == '<')
 678                return report(options, obj, FSCK_MSG_MISSING_NAME_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
 679        p += strcspn(p, "<>\n");
 680        if (*p == '>')
 681                return report(options, obj, FSCK_MSG_BAD_NAME, "invalid author/committer line - bad name");
 682        if (*p != '<')
 683                return report(options, obj, FSCK_MSG_MISSING_EMAIL, "invalid author/committer line - missing email");
 684        if (p[-1] != ' ')
 685                return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_EMAIL, "invalid author/committer line - missing space before email");
 686        p++;
 687        p += strcspn(p, "<>\n");
 688        if (*p != '>')
 689                return report(options, obj, FSCK_MSG_BAD_EMAIL, "invalid author/committer line - bad email");
 690        p++;
 691        if (*p != ' ')
 692                return report(options, obj, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
 693        p++;
 694        if (*p == '0' && p[1] != ' ')
 695                return report(options, obj, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
 696        if (date_overflows(parse_timestamp(p, &end, 10)))
 697                return report(options, obj, FSCK_MSG_BAD_DATE_OVERFLOW, "invalid author/committer line - date causes integer overflow");
 698        if ((end == p || *end != ' '))
 699                return report(options, obj, FSCK_MSG_BAD_DATE, "invalid author/committer line - bad date");
 700        p = end + 1;
 701        if ((*p != '+' && *p != '-') ||
 702            !isdigit(p[1]) ||
 703            !isdigit(p[2]) ||
 704            !isdigit(p[3]) ||
 705            !isdigit(p[4]) ||
 706            (p[5] != '\n'))
 707                return report(options, obj, FSCK_MSG_BAD_TIMEZONE, "invalid author/committer line - bad time zone");
 708        p += 6;
 709        return 0;
 710}
 711
 712static int fsck_commit_buffer(struct commit *commit, const char *buffer,
 713        unsigned long size, struct fsck_options *options)
 714{
 715        unsigned char tree_sha1[20], sha1[20];
 716        struct commit_graft *graft;
 717        unsigned parent_count, parent_line_count = 0, author_count;
 718        int err;
 719        const char *buffer_begin = buffer;
 720
 721        if (verify_headers(buffer, size, &commit->object, options))
 722                return -1;
 723
 724        if (!skip_prefix(buffer, "tree ", &buffer))
 725                return report(options, &commit->object, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
 726        if (get_sha1_hex(buffer, tree_sha1) || buffer[40] != '\n') {
 727                err = report(options, &commit->object, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
 728                if (err)
 729                        return err;
 730        }
 731        buffer += 41;
 732        while (skip_prefix(buffer, "parent ", &buffer)) {
 733                if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') {
 734                        err = report(options, &commit->object, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
 735                        if (err)
 736                                return err;
 737                }
 738                buffer += 41;
 739                parent_line_count++;
 740        }
 741        graft = lookup_commit_graft(the_repository, &commit->object.oid);
 742        parent_count = commit_list_count(commit->parents);
 743        if (graft) {
 744                if (graft->nr_parent == -1 && !parent_count)
 745                        ; /* shallow commit */
 746                else if (graft->nr_parent != parent_count) {
 747                        err = report(options, &commit->object, FSCK_MSG_MISSING_GRAFT, "graft objects missing");
 748                        if (err)
 749                                return err;
 750                }
 751        } else {
 752                if (parent_count != parent_line_count) {
 753                        err = report(options, &commit->object, FSCK_MSG_MISSING_PARENT, "parent objects missing");
 754                        if (err)
 755                                return err;
 756                }
 757        }
 758        author_count = 0;
 759        while (skip_prefix(buffer, "author ", &buffer)) {
 760                author_count++;
 761                err = fsck_ident(&buffer, &commit->object, options);
 762                if (err)
 763                        return err;
 764        }
 765        if (author_count < 1)
 766                err = report(options, &commit->object, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line");
 767        else if (author_count > 1)
 768                err = report(options, &commit->object, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines");
 769        if (err)
 770                return err;
 771        if (!skip_prefix(buffer, "committer ", &buffer))
 772                return report(options, &commit->object, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
 773        err = fsck_ident(&buffer, &commit->object, options);
 774        if (err)
 775                return err;
 776        if (!commit->tree) {
 777                err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
 778                if (err)
 779                        return err;
 780        }
 781        if (memchr(buffer_begin, '\0', size)) {
 782                err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT,
 783                             "NUL byte in the commit object body");
 784                if (err)
 785                        return err;
 786        }
 787        return 0;
 788}
 789
 790static int fsck_commit(struct commit *commit, const char *data,
 791        unsigned long size, struct fsck_options *options)
 792{
 793        const char *buffer = data ?  data : get_commit_buffer(commit, &size);
 794        int ret = fsck_commit_buffer(commit, buffer, size, options);
 795        if (!data)
 796                unuse_commit_buffer(commit, buffer);
 797        return ret;
 798}
 799
 800static int fsck_tag_buffer(struct tag *tag, const char *data,
 801        unsigned long size, struct fsck_options *options)
 802{
 803        unsigned char sha1[20];
 804        int ret = 0;
 805        const char *buffer;
 806        char *to_free = NULL, *eol;
 807        struct strbuf sb = STRBUF_INIT;
 808
 809        if (data)
 810                buffer = data;
 811        else {
 812                enum object_type type;
 813
 814                buffer = to_free =
 815                        read_object_file(&tag->object.oid, &type, &size);
 816                if (!buffer)
 817                        return report(options, &tag->object,
 818                                FSCK_MSG_MISSING_TAG_OBJECT,
 819                                "cannot read tag object");
 820
 821                if (type != OBJ_TAG) {
 822                        ret = report(options, &tag->object,
 823                                FSCK_MSG_TAG_OBJECT_NOT_TAG,
 824                                "expected tag got %s",
 825                            type_name(type));
 826                        goto done;
 827                }
 828        }
 829
 830        ret = verify_headers(buffer, size, &tag->object, options);
 831        if (ret)
 832                goto done;
 833
 834        if (!skip_prefix(buffer, "object ", &buffer)) {
 835                ret = report(options, &tag->object, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
 836                goto done;
 837        }
 838        if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') {
 839                ret = report(options, &tag->object, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
 840                if (ret)
 841                        goto done;
 842        }
 843        buffer += 41;
 844
 845        if (!skip_prefix(buffer, "type ", &buffer)) {
 846                ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
 847                goto done;
 848        }
 849        eol = strchr(buffer, '\n');
 850        if (!eol) {
 851                ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
 852                goto done;
 853        }
 854        if (type_from_string_gently(buffer, eol - buffer, 1) < 0)
 855                ret = report(options, &tag->object, FSCK_MSG_BAD_TYPE, "invalid 'type' value");
 856        if (ret)
 857                goto done;
 858        buffer = eol + 1;
 859
 860        if (!skip_prefix(buffer, "tag ", &buffer)) {
 861                ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line");
 862                goto done;
 863        }
 864        eol = strchr(buffer, '\n');
 865        if (!eol) {
 866                ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG, "invalid format - unexpected end after 'type' line");
 867                goto done;
 868        }
 869        strbuf_addf(&sb, "refs/tags/%.*s", (int)(eol - buffer), buffer);
 870        if (check_refname_format(sb.buf, 0)) {
 871                ret = report(options, &tag->object, FSCK_MSG_BAD_TAG_NAME,
 872                           "invalid 'tag' name: %.*s",
 873                           (int)(eol - buffer), buffer);
 874                if (ret)
 875                        goto done;
 876        }
 877        buffer = eol + 1;
 878
 879        if (!skip_prefix(buffer, "tagger ", &buffer)) {
 880                /* early tags do not contain 'tagger' lines; warn only */
 881                ret = report(options, &tag->object, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line");
 882                if (ret)
 883                        goto done;
 884        }
 885        else
 886                ret = fsck_ident(&buffer, &tag->object, options);
 887
 888done:
 889        strbuf_release(&sb);
 890        free(to_free);
 891        return ret;
 892}
 893
 894static int fsck_tag(struct tag *tag, const char *data,
 895        unsigned long size, struct fsck_options *options)
 896{
 897        struct object *tagged = tag->tagged;
 898
 899        if (!tagged)
 900                return report(options, &tag->object, FSCK_MSG_BAD_TAG_OBJECT, "could not load tagged object");
 901
 902        return fsck_tag_buffer(tag, data, size, options);
 903}
 904
 905int fsck_object(struct object *obj, void *data, unsigned long size,
 906        struct fsck_options *options)
 907{
 908        if (!obj)
 909                return report(options, obj, FSCK_MSG_BAD_OBJECT_SHA1, "no valid object to fsck");
 910
 911        if (obj->type == OBJ_BLOB)
 912                return 0;
 913        if (obj->type == OBJ_TREE)
 914                return fsck_tree((struct tree *) obj, options);
 915        if (obj->type == OBJ_COMMIT)
 916                return fsck_commit((struct commit *) obj, (const char *) data,
 917                        size, options);
 918        if (obj->type == OBJ_TAG)
 919                return fsck_tag((struct tag *) obj, (const char *) data,
 920                        size, options);
 921
 922        return report(options, obj, FSCK_MSG_UNKNOWN_TYPE, "unknown type '%d' (internal fsck error)",
 923                          obj->type);
 924}
 925
 926int fsck_error_function(struct fsck_options *o,
 927        struct object *obj, int msg_type, const char *message)
 928{
 929        if (msg_type == FSCK_WARN) {
 930                warning("object %s: %s", describe_object(o, obj), message);
 931                return 0;
 932        }
 933        error("object %s: %s", describe_object(o, obj), message);
 934        return 1;
 935}