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