static int process_ref(int len, struct ref ***list, unsigned int flags, struct oid_array *extra_have) { struct object_id old_oid; const char *name; if (parse_oid_hex(packet_buffer, &old_oid, &name)) return 0; if (*name != ' ') return 0; name++; if (extra_have && !strcmp(name, ".have")) { oid_array_append(extra_have, &old_oid); } else if (!strcmp(name, "capabilities^{}")) { die("protocol error: unexpected capabilities^{}"); } else if (check_ref(name, flags)) { struct ref *ref = alloc_ref(name); oidcpy(&ref->old_oid, &old_oid); **list = ref; *list = &ref->next; } check_no_capabilities(len); return 1; }
static void receive_wanted_refs(struct packet_reader *reader, struct ref **sought, int nr_sought) { process_section_header(reader, "wanted-refs", 0); while (packet_reader_read(reader) == PACKET_READ_NORMAL) { struct object_id oid; const char *end; int i; if (parse_oid_hex(reader->line, &oid, &end) || *end++ != ' ') die(_("expected wanted-ref, got '%s'"), reader->line); for (i = 0; i < nr_sought; i++) { if (!strcmp(end, sought[i]->name)) { oidcpy(&sought[i]->old_oid, &oid); break; } } if (i == nr_sought) die(_("unexpected wanted-ref: '%s'"), reader->line); } if (reader->status != PACKET_READ_DELIM) die(_("error processing wanted refs: %d"), reader->status); }
static void add_sought_entry(struct ref ***sought, int *nr, int *alloc, const char *name) { struct ref *ref; struct object_id oid; const char *p; if (!parse_oid_hex(name, &oid, &p)) { if (*p == ' ') { /* <oid> <ref>, find refname */ name = p + 1; } else if (*p == '\0') { ; /* <oid>, leave oid as name */ } else { /* <ref>, clear cruft from oid */ oidclr(&oid); } } else { /* <ref>, clear cruft from get_oid_hex */ oidclr(&oid); } ref = alloc_ref(name); oidcpy(&ref->old_oid, &oid); (*nr)++; ALLOC_GROW(*sought, *nr, *alloc); (*sought)[*nr - 1] = ref; }
static void read_alternate_refs(const char *path, alternate_ref_fn *cb, void *data) { struct child_process cmd = CHILD_PROCESS_INIT; struct strbuf line = STRBUF_INIT; FILE *fh; fill_alternate_refs_command(&cmd, path); if (start_command(&cmd)) return; fh = xfdopen(cmd.out, "r"); while (strbuf_getline_lf(&line, fh) != EOF) { struct object_id oid; const char *p; if (parse_oid_hex(line.buf, &oid, &p) || *p) { warning(_("invalid line while parsing alternate refs: %s"), line.buf); break; } cb(&oid, data); } fclose(fh); finish_command(&cmd); }
int parse_tag_buffer(struct tag *item, const void *data, unsigned long size) { struct object_id oid; char type[20]; const char *bufptr = data; const char *tail = bufptr + size; const char *nl; if (item->object.parsed) return 0; item->object.parsed = 1; if (size < GIT_SHA1_HEXSZ + 24) return -1; if (memcmp("object ", bufptr, 7) || parse_oid_hex(bufptr + 7, &oid, &bufptr) || *bufptr++ != '\n') return -1; if (!starts_with(bufptr, "type ")) return -1; bufptr += 5; nl = memchr(bufptr, '\n', tail - bufptr); if (!nl || sizeof(type) <= (nl - bufptr)) return -1; memcpy(type, bufptr, nl - bufptr); type[nl - bufptr] = '\0'; bufptr = nl + 1; if (!strcmp(type, blob_type)) { item->tagged = (struct object *)lookup_blob(&oid); } else if (!strcmp(type, tree_type)) { item->tagged = (struct object *)lookup_tree(&oid); } else if (!strcmp(type, commit_type)) { item->tagged = (struct object *)lookup_commit(&oid); } else if (!strcmp(type, tag_type)) { item->tagged = (struct object *)lookup_tag(&oid); } else { error("Unknown type %s", type); item->tagged = NULL; } if (bufptr + 4 < tail && starts_with(bufptr, "tag ")) ; /* good */ else return -1; bufptr += 4; nl = memchr(bufptr, '\n', tail - bufptr); if (!nl) return -1; item->tag = xmemdupz(bufptr, nl - bufptr); bufptr = nl + 1; if (bufptr + 7 < tail && starts_with(bufptr, "tagger ")) item->date = parse_tag_date(bufptr, tail); else item->date = 0; return 0; }
static int is_unmatched_ref(const struct ref *ref) { struct object_id oid; const char *p; return ref->match_status == REF_NOT_MATCHED && !parse_oid_hex(ref->name, &oid, &p) && *p == '\0' && oideq(&oid, &ref->old_oid); }
static int process_dummy_ref(void) { struct object_id oid; const char *name; if (parse_oid_hex(packet_buffer, &oid, &name)) return 0; if (*name != ' ') return 0; name++; return !oidcmp(&null_oid, &oid) && !strcmp(name, "capabilities^{}"); }
static int process_dummy_ref(const char *line) { struct object_id oid; const char *name; if (parse_oid_hex(line, &oid, &name)) return 0; if (*name != ' ') return 0; name++; return oideq(&null_oid, &oid) && !strcmp(name, "capabilities^{}"); }
int cmd__repository(int argc, const char **argv) { if (argc < 2) die("must have at least 2 arguments"); if (!strcmp(argv[1], "parse_commit_in_graph")) { struct object_id oid; if (argc < 5) die("not enough arguments"); if (parse_oid_hex(argv[4], &oid, &argv[4])) die("cannot parse oid '%s'", argv[4]); test_parse_commit_in_graph(argv[2], argv[3], &oid); } else if (!strcmp(argv[1], "get_commit_tree_in_graph")) { struct object_id oid; if (argc < 5) die("not enough arguments"); if (parse_oid_hex(argv[4], &oid, &argv[4])) die("cannot parse oid '%s'", argv[4]); test_get_commit_tree_in_graph(argv[2], argv[3], &oid); } else { die("unrecognized '%s'", argv[1]); } return 0; }
/* Diff two trees. */ static int stdin_diff_trees(struct tree *tree1, const char *p) { struct object_id oid; struct tree *tree2; if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p) return error("Need exactly two trees, separated by a space"); tree2 = lookup_tree(&oid); if (!tree2 || parse_tree(tree2)) return -1; printf("%s %s\n", oid_to_hex(&tree1->object.oid), oid_to_hex(&tree2->object.oid)); diff_tree_oid(&tree1->object.oid, &tree2->object.oid, "", &log_tree_opt.diffopt); log_tree_diff_flush(&log_tree_opt); return 0; }
/* Diff one or more commits. */ static int stdin_diff_commit(struct commit *commit, const char *p) { struct object_id oid; struct commit_list **pptr = NULL; /* Graft the fake parents locally to the commit */ while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) { struct commit *parent = lookup_commit(&oid); if (!pptr) { /* Free the real parent list */ free_commit_list(commit->parents); commit->parents = NULL; pptr = &(commit->parents); } if (parent) { pptr = &commit_list_insert(parent, pptr)->next; } } return log_tree_commit(&log_tree_opt, commit); }
static int get_reachable_list(struct object_array *src, struct object_array *reachable) { struct child_process cmd = CHILD_PROCESS_INIT; int i; struct object *o; char namebuf[GIT_MAX_HEXSZ + 2]; /* ^ + hash + LF */ const unsigned hexsz = the_hash_algo->hexsz; if (do_reachable_revlist(&cmd, src, reachable) < 0) return -1; while ((i = read_in_full(cmd.out, namebuf, hexsz + 1)) == hexsz + 1) { struct object_id sha1; const char *p; if (parse_oid_hex(namebuf, &sha1, &p) || *p != '\n') break; o = lookup_object(sha1.hash); if (o && o->type == OBJ_COMMIT) { o->flags &= ~TMP_MARK; } } for (i = get_max_object_index(); 0 < i; i--) { o = get_indexed_object(i - 1); if (o && o->type == OBJ_COMMIT && (o->flags & TMP_MARK)) { add_object_array(o, NULL, reachable); o->flags &= ~TMP_MARK; } } close(cmd.out); if (finish_command(&cmd)) return -1; return 0; }
static int diff_tree_stdin(char *line) { int len = strlen(line); struct object_id oid; struct object *obj; const char *p; if (!len || line[len-1] != '\n') return -1; line[len-1] = 0; if (parse_oid_hex(line, &oid, &p)) return -1; obj = parse_object(&oid); if (!obj) return -1; if (obj->type == OBJ_COMMIT) return stdin_diff_commit((struct commit *)obj, p); if (obj->type == OBJ_TREE) return stdin_diff_trees((struct tree *)obj, p); error("Object %s is a %s, not a commit or tree", oid_to_hex(&oid), typename(obj->type)); return -1; }
static int parse_new_style_cacheinfo(const char *arg, unsigned int *mode, struct object_id *oid, const char **path) { unsigned long ul; char *endp; const char *p; if (!arg) return -1; errno = 0; ul = strtoul(arg, &endp, 8); if (errno || endp == arg || *endp != ',' || (unsigned int) ul != ul) return -1; /* not a new-style cacheinfo */ *mode = ul; endp++; if (parse_oid_hex(endp, oid, &p) || *p != ',') return -1; *path = p + 1; return 0; }
static void init_skiplist(struct fsck_options *options, const char *path) { static struct oid_array skiplist = OID_ARRAY_INIT; int sorted, fd; char buffer[GIT_MAX_HEXSZ + 1]; struct object_id oid; if (options->skiplist) sorted = options->skiplist->sorted; else { sorted = 1; options->skiplist = &skiplist; } fd = open(path, O_RDONLY); if (fd < 0) die("Could not open skip list: %s", path); for (;;) { const char *p; int result = read_in_full(fd, buffer, sizeof(buffer)); if (result < 0) die_errno("Could not read '%s'", path); if (!result) break; if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') die("Invalid SHA-1: %s", buffer); oid_array_append(&skiplist, &oid); if (sorted && skiplist.nr > 1 && oidcmp(&skiplist.oid[skiplist.nr - 2], &oid) > 0) sorted = 0; } close(fd); if (sorted) skiplist.sorted = 1; }
static void filter_refs(struct fetch_pack_args *args, struct ref **refs, struct ref **sought, int nr_sought) { struct ref *newlist = NULL; struct ref **newtail = &newlist; struct ref *unmatched = NULL; struct ref *ref, *next; struct oidset tip_oids = OIDSET_INIT; int i; i = 0; for (ref = *refs; ref; ref = next) { int keep = 0; next = ref->next; if (starts_with(ref->name, "refs/") && check_refname_format(ref->name, 0)) ; /* trash */ else { while (i < nr_sought) { int cmp = strcmp(ref->name, sought[i]->name); if (cmp < 0) break; /* definitely do not have it */ else if (cmp == 0) { keep = 1; /* definitely have it */ sought[i]->match_status = REF_MATCHED; } i++; } } if (!keep && args->fetch_all && (!args->deepen || !starts_with(ref->name, "refs/tags/"))) keep = 1; if (keep) { *newtail = ref; ref->next = NULL; newtail = &ref->next; } else { ref->next = unmatched; unmatched = ref; } } /* Append unmatched requests to the list */ for (i = 0; i < nr_sought; i++) { struct object_id oid; const char *p; ref = sought[i]; if (ref->match_status != REF_NOT_MATCHED) continue; if (parse_oid_hex(ref->name, &oid, &p) || *p != '\0' || oidcmp(&oid, &ref->old_oid)) continue; if ((allow_unadvertised_object_request & (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1)) || tip_oids_contain(&tip_oids, unmatched, newlist, &ref->old_oid)) { ref->match_status = REF_MATCHED; *newtail = copy_ref(ref); newtail = &(*newtail)->next; } else { ref->match_status = REF_UNADVERTISED_NOT_ALLOWED; } } oidset_clear(&tip_oids); for (ref = unmatched; ref; ref = next) { next = ref->next; free(ref); } *refs = newlist; }
/* * Move the iterator to the next record in the snapshot, without * respect for whether the record is actually required by the current * iteration. Adjust the fields in `iter` and return `ITER_OK` or * `ITER_DONE`. This function does not free the iterator in the case * of `ITER_DONE`. */ static int next_record(struct packed_ref_iterator *iter) { const char *p = iter->pos, *eol; strbuf_reset(&iter->refname_buf); if (iter->pos == iter->eof) return ITER_DONE; iter->base.flags = REF_ISPACKED; if (iter->eof - p < GIT_SHA1_HEXSZ + 2 || parse_oid_hex(p, &iter->oid, &p) || !isspace(*p++)) die_invalid_line(iter->snapshot->refs->path, iter->pos, iter->eof - iter->pos); eol = memchr(p, '\n', iter->eof - p); if (!eol) die_unterminated_line(iter->snapshot->refs->path, iter->pos, iter->eof - iter->pos); strbuf_add(&iter->refname_buf, p, eol - p); iter->base.refname = iter->refname_buf.buf; if (check_refname_format(iter->base.refname, REFNAME_ALLOW_ONELEVEL)) { if (!refname_is_safe(iter->base.refname)) die("packed refname is dangerous: %s", iter->base.refname); oidclr(&iter->oid); iter->base.flags |= REF_BAD_NAME | REF_ISBROKEN; } if (iter->snapshot->peeled == PEELED_FULLY || (iter->snapshot->peeled == PEELED_TAGS && starts_with(iter->base.refname, "refs/tags/"))) iter->base.flags |= REF_KNOWS_PEELED; iter->pos = eol + 1; if (iter->pos < iter->eof && *iter->pos == '^') { p = iter->pos + 1; if (iter->eof - p < GIT_SHA1_HEXSZ + 1 || parse_oid_hex(p, &iter->peeled, &p) || *p++ != '\n') die_invalid_line(iter->snapshot->refs->path, iter->pos, iter->eof - iter->pos); iter->pos = p; /* * Regardless of what the file header said, we * definitely know the value of *this* reference. But * we suppress it if the reference is broken: */ if ((iter->base.flags & REF_ISBROKEN)) { oidclr(&iter->peeled); iter->base.flags &= ~REF_KNOWS_PEELED; } else { iter->base.flags |= REF_KNOWS_PEELED; } } else { oidclr(&iter->peeled); } return ITER_OK; }
/* Returns 1 when a valid ref has been added to `list`, 0 otherwise */ static int process_ref_v2(const char *line, struct ref ***list) { int ret = 1; int i = 0; struct object_id old_oid; struct ref *ref; struct string_list line_sections = STRING_LIST_INIT_DUP; const char *end; /* * Ref lines have a number of fields which are space deliminated. The * first field is the OID of the ref. The second field is the ref * name. Subsequent fields (symref-target and peeled) are optional and * don't have a particular order. */ if (string_list_split(&line_sections, line, ' ', -1) < 2) { ret = 0; goto out; } if (parse_oid_hex(line_sections.items[i++].string, &old_oid, &end) || *end) { ret = 0; goto out; } ref = alloc_ref(line_sections.items[i++].string); oidcpy(&ref->old_oid, &old_oid); **list = ref; *list = &ref->next; for (; i < line_sections.nr; i++) { const char *arg = line_sections.items[i].string; if (skip_prefix(arg, "symref-target:", &arg)) ref->symref = xstrdup(arg); if (skip_prefix(arg, "peeled:", &arg)) { struct object_id peeled_oid; char *peeled_name; struct ref *peeled; if (parse_oid_hex(arg, &peeled_oid, &end) || *end) { ret = 0; goto out; } peeled_name = xstrfmt("%s^{}", ref->name); peeled = alloc_ref(peeled_name); oidcpy(&peeled->old_oid, &peeled_oid); **list = peeled; *list = &peeled->next; free(peeled_name); } } out: string_list_clear(&line_sections, 0); return ret; }
static int verify_tag(char *buffer, unsigned long size) { int typelen; char type[20]; struct object_id oid; const char *object, *type_line, *tag_line, *tagger_line, *lb, *rb, *p; size_t len; if (size < 84) return error("wanna fool me ? you obviously got the size wrong !"); buffer[size] = 0; /* Verify object line */ object = buffer; if (memcmp(object, "object ", 7)) return error("char%d: does not start with \"object \"", 0); if (parse_oid_hex(object + 7, &oid, &p)) return error("char%d: could not get SHA1 hash", 7); /* Verify type line */ type_line = p + 1; if (memcmp(type_line - 1, "\ntype ", 6)) return error("char%d: could not find \"\\ntype \"", 47); /* Verify tag-line */ tag_line = strchr(type_line, '\n'); if (!tag_line) return error("char%"PRIuMAX": could not find next \"\\n\"", (uintmax_t) (type_line - buffer)); tag_line++; if (memcmp(tag_line, "tag ", 4) || tag_line[4] == '\n') return error("char%"PRIuMAX": no \"tag \" found", (uintmax_t) (tag_line - buffer)); /* Get the actual type */ typelen = tag_line - type_line - strlen("type \n"); if (typelen >= sizeof(type)) return error("char%"PRIuMAX": type too long", (uintmax_t) (type_line+5 - buffer)); memcpy(type, type_line+5, typelen); type[typelen] = 0; /* Verify that the object matches */ if (verify_object(&oid, type)) return error("char%d: could not verify object %s", 7, oid_to_hex(&oid)); /* Verify the tag-name: we don't allow control characters or spaces in it */ tag_line += 4; for (;;) { unsigned char c = *tag_line++; if (c == '\n') break; if (c > ' ') continue; return error("char%"PRIuMAX": could not verify tag name", (uintmax_t) (tag_line - buffer)); } /* Verify the tagger line */ tagger_line = tag_line; if (memcmp(tagger_line, "tagger ", 7)) return error("char%"PRIuMAX": could not find \"tagger \"", (uintmax_t) (tagger_line - buffer)); /* * Check for correct form for name and email * i.e. " <" followed by "> " on _this_ line * No angle brackets within the name or email address fields. * No spaces within the email address field. */ tagger_line += 7; if (!(lb = strstr(tagger_line, " <")) || !(rb = strstr(lb+2, "> ")) || strpbrk(tagger_line, "<>\n") != lb+1 || strpbrk(lb+2, "><\n ") != rb) return error("char%"PRIuMAX": malformed tagger field", (uintmax_t) (tagger_line - buffer)); /* Check for author name, at least one character, space is acceptable */ if (lb == tagger_line) return error("char%"PRIuMAX": missing tagger name", (uintmax_t) (tagger_line - buffer)); /* timestamp, 1 or more digits followed by space */ tagger_line = rb + 2; if (!(len = strspn(tagger_line, "0123456789"))) return error("char%"PRIuMAX": missing tag timestamp", (uintmax_t) (tagger_line - buffer)); tagger_line += len; if (*tagger_line != ' ') return error("char%"PRIuMAX": malformed tag timestamp", (uintmax_t) (tagger_line - buffer)); tagger_line++; /* timezone, 5 digits [+-]hhmm, max. 1400 */ if (!((tagger_line[0] == '+' || tagger_line[0] == '-') && strspn(tagger_line+1, "0123456789") == 4 && tagger_line[5] == '\n' && atoi(tagger_line+1) <= 1400)) return error("char%"PRIuMAX": malformed tag timezone", (uintmax_t) (tagger_line - buffer)); tagger_line += 6; /* Verify the blank line separating the header from the body */ if (*tagger_line != '\n') return error("char%"PRIuMAX": trailing garbage in tag header", (uintmax_t) (tagger_line - buffer)); /* The actual stuff afterwards we don't care about.. */ return 0; }
static void receive_needs(void) { struct object_array shallows = OBJECT_ARRAY_INIT; struct string_list deepen_not = STRING_LIST_INIT_DUP; int depth = 0; int has_non_tip = 0; timestamp_t deepen_since = 0; int deepen_rev_list = 0; shallow_nr = 0; for (;;) { struct object *o; const char *features; struct object_id oid_buf; char *line = packet_read_line(0, NULL); const char *arg; reset_timeout(); if (!line) break; if (process_shallow(line, &shallows)) continue; if (process_deepen(line, &depth)) continue; if (process_deepen_since(line, &deepen_since, &deepen_rev_list)) continue; if (process_deepen_not(line, &deepen_not, &deepen_rev_list)) continue; if (skip_prefix(line, "filter ", &arg)) { if (!filter_capability_requested) die("git upload-pack: filtering capability not negotiated"); parse_list_objects_filter(&filter_options, arg); continue; } if (!skip_prefix(line, "want ", &arg) || parse_oid_hex(arg, &oid_buf, &features)) die("git upload-pack: protocol error, " "expected to get object ID, not '%s'", line); if (parse_feature_request(features, "deepen-relative")) deepen_relative = 1; if (parse_feature_request(features, "multi_ack_detailed")) multi_ack = 2; else if (parse_feature_request(features, "multi_ack")) multi_ack = 1; if (parse_feature_request(features, "no-done")) no_done = 1; if (parse_feature_request(features, "thin-pack")) use_thin_pack = 1; if (parse_feature_request(features, "ofs-delta")) use_ofs_delta = 1; if (parse_feature_request(features, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (parse_feature_request(features, "side-band")) use_sideband = DEFAULT_PACKET_MAX; if (parse_feature_request(features, "no-progress")) no_progress = 1; if (parse_feature_request(features, "include-tag")) use_include_tag = 1; if (allow_filter && parse_feature_request(features, "filter")) filter_capability_requested = 1; o = parse_object(&oid_buf); if (!o) { packet_write_fmt(1, "ERR upload-pack: not our ref %s", oid_to_hex(&oid_buf)); die("git upload-pack: not our ref %s", oid_to_hex(&oid_buf)); } if (!(o->flags & WANTED)) { o->flags |= WANTED; if (!((allow_unadvertised_object_request & ALLOW_ANY_SHA1) == ALLOW_ANY_SHA1 || is_our_ref(o))) has_non_tip = 1; add_object_array(o, NULL, &want_obj); } } /* * We have sent all our refs already, and the other end * should have chosen out of them. When we are operating * in the stateless RPC mode, however, their choice may * have been based on the set of older refs advertised * by another process that handled the initial request. */ if (has_non_tip) check_non_tip(); if (!use_sideband && daemon_mode) no_progress = 1; if (depth == 0 && !deepen_rev_list && shallows.nr == 0) return; if (send_shallow_list(depth, deepen_rev_list, deepen_since, &deepen_not, &shallows)) packet_flush(1); object_array_clear(&shallows); }
static int fsck_tag_buffer(struct tag *tag, const char *data, unsigned long size, struct fsck_options *options) { struct object_id oid; int ret = 0; const char *buffer; char *to_free = NULL, *eol; struct strbuf sb = STRBUF_INIT; const char *p; if (data) buffer = data; else { enum object_type type; buffer = to_free = read_object_file(&tag->object.oid, &type, &size); if (!buffer) return report(options, &tag->object, FSCK_MSG_MISSING_TAG_OBJECT, "cannot read tag object"); if (type != OBJ_TAG) { ret = report(options, &tag->object, FSCK_MSG_TAG_OBJECT_NOT_TAG, "expected tag got %s", type_name(type)); goto done; } } ret = verify_headers(buffer, size, &tag->object, options); if (ret) goto done; if (!skip_prefix(buffer, "object ", &buffer)) { ret = report(options, &tag->object, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line"); goto done; } if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') { ret = report(options, &tag->object, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1"); if (ret) goto done; } buffer = p + 1; if (!skip_prefix(buffer, "type ", &buffer)) { ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line"); goto done; } eol = strchr(buffer, '\n'); if (!eol) { ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line"); goto done; } if (type_from_string_gently(buffer, eol - buffer, 1) < 0) ret = report(options, &tag->object, FSCK_MSG_BAD_TYPE, "invalid 'type' value"); if (ret) goto done; buffer = eol + 1; if (!skip_prefix(buffer, "tag ", &buffer)) { ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line"); goto done; } eol = strchr(buffer, '\n'); if (!eol) { ret = report(options, &tag->object, FSCK_MSG_MISSING_TAG, "invalid format - unexpected end after 'type' line"); goto done; } strbuf_addf(&sb, "refs/tags/%.*s", (int)(eol - buffer), buffer); if (check_refname_format(sb.buf, 0)) { ret = report(options, &tag->object, FSCK_MSG_BAD_TAG_NAME, "invalid 'tag' name: %.*s", (int)(eol - buffer), buffer); if (ret) goto done; } buffer = eol + 1; if (!skip_prefix(buffer, "tagger ", &buffer)) { /* early tags do not contain 'tagger' lines; warn only */ ret = report(options, &tag->object, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line"); if (ret) goto done; } else ret = fsck_ident(&buffer, &tag->object, options); done: strbuf_release(&sb); free(to_free); return ret; }
static int fsck_commit_buffer(struct commit *commit, const char *buffer, unsigned long size, struct fsck_options *options) { struct object_id tree_oid, oid; struct commit_graft *graft; unsigned parent_count, parent_line_count = 0, author_count; int err; const char *buffer_begin = buffer; const char *p; if (verify_headers(buffer, size, &commit->object, options)) return -1; if (!skip_prefix(buffer, "tree ", &buffer)) return report(options, &commit->object, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line"); if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') { err = report(options, &commit->object, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1"); if (err) return err; } buffer = p + 1; while (skip_prefix(buffer, "parent ", &buffer)) { if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') { err = report(options, &commit->object, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1"); if (err) return err; } buffer = p + 1; parent_line_count++; } graft = lookup_commit_graft(&commit->object.oid); parent_count = commit_list_count(commit->parents); if (graft) { if (graft->nr_parent == -1 && !parent_count) ; /* shallow commit */ else if (graft->nr_parent != parent_count) { err = report(options, &commit->object, FSCK_MSG_MISSING_GRAFT, "graft objects missing"); if (err) return err; } } else { if (parent_count != parent_line_count) { err = report(options, &commit->object, FSCK_MSG_MISSING_PARENT, "parent objects missing"); if (err) return err; } } author_count = 0; while (skip_prefix(buffer, "author ", &buffer)) { author_count++; err = fsck_ident(&buffer, &commit->object, options); if (err) return err; } if (author_count < 1) err = report(options, &commit->object, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line"); else if (author_count > 1) err = report(options, &commit->object, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines"); if (err) return err; if (!skip_prefix(buffer, "committer ", &buffer)) return report(options, &commit->object, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line"); err = fsck_ident(&buffer, &commit->object, options); if (err) return err; if (!get_commit_tree(commit)) { err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", oid_to_hex(&tree_oid)); if (err) return err; } if (memchr(buffer_begin, '\0', size)) { err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT, "NUL byte in the commit object body"); if (err) return err; } return 0; }