diff options
Diffstat (limited to 'builtin/fast-import.c')
| -rw-r--r-- | builtin/fast-import.c | 243 |
1 files changed, 124 insertions, 119 deletions
diff --git a/builtin/fast-import.c b/builtin/fast-import.c index 92eda20683..d21c4053a7 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -1236,20 +1236,6 @@ static void *gfi_unpack_entry( return unpack_entry(the_repository, p, oe->idx.offset, &type, sizep); } -static const char *get_mode(const char *str, uint16_t *modep) -{ - unsigned char c; - uint16_t mode = 0; - - while ((c = *str++) != ' ') { - if (c < '0' || c > '7') - return NULL; - mode = (mode << 3) + (c - '0'); - } - *modep = mode; - return str; -} - static void load_tree(struct tree_entry *root) { struct object_id *oid = &root->versions[1].oid; @@ -1287,14 +1273,16 @@ static void load_tree(struct tree_entry *root) t->entries[t->entry_count++] = e; e->tree = NULL; - c = get_mode(c, &e->versions[1].mode); + c = parse_mode(c, &e->versions[1].mode); if (!c) die("Corrupt mode in %s", oid_to_hex(oid)); e->versions[0].mode = e->versions[1].mode; e->name = to_atom(c, strlen(c)); c += e->name->str_len + 1; - oidread(&e->versions[0].oid, (unsigned char *)c); - oidread(&e->versions[1].oid, (unsigned char *)c); + oidread(&e->versions[0].oid, (unsigned char *)c, + the_repository->hash_algo); + oidread(&e->versions[1].oid, (unsigned char *)c, + the_repository->hash_algo); c += the_hash_algo->rawsz; } free(buf); @@ -1400,7 +1388,7 @@ static void tree_content_replace( { if (!S_ISDIR(mode)) die("Root cannot be a non-directory"); - oidclr(&root->versions[0].oid); + oidclr(&root->versions[0].oid, the_repository->hash_algo); oidcpy(&root->versions[1].oid, oid); if (root->tree) release_tree_content_recursive(root->tree); @@ -1459,7 +1447,7 @@ static int tree_content_set( if (S_ISDIR(e->versions[0].mode)) e->versions[0].mode |= NO_DELTA; - oidclr(&root->versions[1].oid); + oidclr(&root->versions[1].oid, the_repository->hash_algo); return 1; } if (!S_ISDIR(e->versions[1].mode)) { @@ -1469,7 +1457,7 @@ static int tree_content_set( if (!e->tree) load_tree(e); if (tree_content_set(e, slash1 + 1, oid, mode, subtree)) { - oidclr(&root->versions[1].oid); + oidclr(&root->versions[1].oid, the_repository->hash_algo); return 1; } return 0; @@ -1481,7 +1469,7 @@ static int tree_content_set( e = new_tree_entry(); e->name = to_atom(p, n); e->versions[0].mode = 0; - oidclr(&e->versions[0].oid); + oidclr(&e->versions[0].oid, the_repository->hash_algo); t->entries[t->entry_count++] = e; if (*slash1) { e->tree = new_tree_content(8); @@ -1492,7 +1480,7 @@ static int tree_content_set( e->versions[1].mode = mode; oidcpy(&e->versions[1].oid, oid); } - oidclr(&root->versions[1].oid); + oidclr(&root->versions[1].oid, the_repository->hash_algo); return 1; } @@ -1537,7 +1525,8 @@ static int tree_content_remove( if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) { for (n = 0; n < e->tree->entry_count; n++) { if (e->tree->entries[n]->versions[1].mode) { - oidclr(&root->versions[1].oid); + oidclr(&root->versions[1].oid, + the_repository->hash_algo); return 1; } } @@ -1556,8 +1545,8 @@ del_entry: release_tree_content_recursive(e->tree); e->tree = NULL; e->versions[1].mode = 0; - oidclr(&e->versions[1].oid); - oidclr(&root->versions[1].oid); + oidclr(&e->versions[1].oid, the_repository->hash_algo); + oidclr(&root->versions[1].oid, the_repository->hash_algo); return 1; } @@ -1618,13 +1607,15 @@ static int update_branch(struct branch *b) if (is_null_oid(&b->oid)) { if (b->delete) - delete_ref(NULL, b->name, NULL, 0); + refs_delete_ref(get_main_ref_store(the_repository), + NULL, b->name, NULL, 0); return 0; } - if (read_ref(b->name, &old_oid)) - oidclr(&old_oid); + if (refs_read_ref(get_main_ref_store(the_repository), b->name, &old_oid)) + oidclr(&old_oid, the_repository->hash_algo); if (!force_update && !is_null_oid(&old_oid)) { struct commit *old_cmit, *new_cmit; + int ret; old_cmit = lookup_commit_reference_gently(the_repository, &old_oid, 0); @@ -1633,7 +1624,10 @@ static int update_branch(struct branch *b) if (!old_cmit || !new_cmit) return error("Branch %s is missing commits.", b->name); - if (!repo_in_merge_bases(the_repository, old_cmit, new_cmit)) { + ret = repo_in_merge_bases(the_repository, old_cmit, new_cmit); + if (ret < 0) + exit(128); + if (!ret) { warning("Not updating %s" " (new tip %s does not contain %s)", b->name, oid_to_hex(&b->oid), @@ -1641,10 +1635,11 @@ static int update_branch(struct branch *b) return -1; } } - transaction = ref_transaction_begin(&err); + transaction = ref_store_transaction_begin(get_main_ref_store(the_repository), + &err); if (!transaction || ref_transaction_update(transaction, b->name, &b->oid, &old_oid, - 0, msg, &err) || + NULL, NULL, 0, msg, &err) || ref_transaction_commit(transaction, &err)) { ref_transaction_free(transaction); error("%s", err.buf); @@ -1675,7 +1670,8 @@ static void dump_tags(void) struct strbuf err = STRBUF_INIT; struct ref_transaction *transaction; - transaction = ref_transaction_begin(&err); + transaction = ref_store_transaction_begin(get_main_ref_store(the_repository), + &err); if (!transaction) { failure |= error("%s", err.buf); goto cleanup; @@ -1685,7 +1681,8 @@ static void dump_tags(void) strbuf_addf(&ref_name, "refs/tags/%s", t->name); if (ref_transaction_update(transaction, ref_name.buf, - &t->oid, NULL, 0, msg, &err)) { + &t->oid, NULL, NULL, NULL, + 0, msg, &err)) { failure |= error("%s", err.buf); goto cleanup; } @@ -2220,7 +2217,7 @@ static int parse_mapped_oid_hex(const char *hex, struct object_id *oid, const ch * * idnum ::= ':' bigint; * - * Return the first character after the value in *endptr. + * Update *endptr to point to the first character after the value. * * Complain if the following character is not what is expected, * either a space or end of the string. @@ -2253,8 +2250,8 @@ static uintmax_t parse_mark_ref_eol(const char *p) } /* - * Parse the mark reference, demanding a trailing space. Return a - * pointer to the space. + * Parse the mark reference, demanding a trailing space. Update *p to + * point to the first character after the space. */ static uintmax_t parse_mark_ref_space(const char **p) { @@ -2268,15 +2265,67 @@ static uintmax_t parse_mark_ref_space(const char **p) return mark; } +/* + * Parse the path string into the strbuf. The path can either be quoted with + * escape sequences or unquoted without escape sequences. Unquoted strings may + * contain spaces only if `is_last_field` is nonzero; otherwise, it stops + * parsing at the first space. + */ +static void parse_path(struct strbuf *sb, const char *p, const char **endp, + int is_last_field, const char *field) +{ + if (*p == '"') { + if (unquote_c_style(sb, p, endp)) + die("Invalid %s: %s", field, command_buf.buf); + if (strlen(sb->buf) != sb->len) + die("NUL in %s: %s", field, command_buf.buf); + } else { + /* + * Unless we are parsing the last field of a line, + * SP is the end of this field. + */ + *endp = is_last_field + ? p + strlen(p) + : strchrnul(p, ' '); + strbuf_add(sb, p, *endp - p); + } +} + +/* + * Parse the path string into the strbuf, and complain if this is not the end of + * the string. Unquoted strings may contain spaces. + */ +static void parse_path_eol(struct strbuf *sb, const char *p, const char *field) +{ + const char *end; + + parse_path(sb, p, &end, 1, field); + if (*end) + die("Garbage after %s: %s", field, command_buf.buf); +} + +/* + * Parse the path string into the strbuf, and ensure it is followed by a space. + * Unquoted strings may not contain spaces. Update *endp to point to the first + * character after the space. + */ +static void parse_path_space(struct strbuf *sb, const char *p, + const char **endp, const char *field) +{ + parse_path(sb, p, endp, 0, field); + if (**endp != ' ') + die("Missing space after %s: %s", field, command_buf.buf); + (*endp)++; +} + static void file_change_m(const char *p, struct branch *b) { - static struct strbuf uq = STRBUF_INIT; - const char *endp; + static struct strbuf path = STRBUF_INIT; struct object_entry *oe; struct object_id oid; uint16_t mode, inline_data = 0; - p = get_mode(p, &mode); + p = parse_mode(p, &mode); if (!p) die("Corrupt mode: %s", command_buf.buf); switch (mode) { @@ -2308,16 +2357,14 @@ static void file_change_m(const char *p, struct branch *b) die("Missing space after SHA1: %s", command_buf.buf); } - strbuf_reset(&uq); - if (!unquote_c_style(&uq, p, &endp)) { - if (*endp) - die("Garbage after path in: %s", command_buf.buf); - p = uq.buf; - } + strbuf_reset(&path); + parse_path_eol(&path, p, "path"); /* Git does not track empty, non-toplevel directories. */ - if (S_ISDIR(mode) && is_empty_tree_oid(&oid) && *p) { - tree_content_remove(&b->branch_tree, p, NULL, 0); + if (S_ISDIR(mode) && + is_empty_tree_oid(&oid, the_repository->hash_algo) && + *path.buf) { + tree_content_remove(&b->branch_tree, path.buf, NULL, 0); return; } @@ -2338,10 +2385,6 @@ static void file_change_m(const char *p, struct branch *b) if (S_ISDIR(mode)) die("Directories cannot be specified 'inline': %s", command_buf.buf); - if (p != uq.buf) { - strbuf_addstr(&uq, p); - p = uq.buf; - } while (read_next_command() != EOF) { const char *v; if (skip_prefix(command_buf.buf, "cat-blob ", &v)) @@ -2367,74 +2410,48 @@ static void file_change_m(const char *p, struct branch *b) command_buf.buf); } - if (!*p) { + if (!*path.buf) { tree_content_replace(&b->branch_tree, &oid, mode, NULL); return; } - tree_content_set(&b->branch_tree, p, &oid, mode, NULL); + tree_content_set(&b->branch_tree, path.buf, &oid, mode, NULL); } static void file_change_d(const char *p, struct branch *b) { - static struct strbuf uq = STRBUF_INIT; - const char *endp; + static struct strbuf path = STRBUF_INIT; - strbuf_reset(&uq); - if (!unquote_c_style(&uq, p, &endp)) { - if (*endp) - die("Garbage after path in: %s", command_buf.buf); - p = uq.buf; - } - tree_content_remove(&b->branch_tree, p, NULL, 1); + strbuf_reset(&path); + parse_path_eol(&path, p, "path"); + tree_content_remove(&b->branch_tree, path.buf, NULL, 1); } -static void file_change_cr(const char *s, struct branch *b, int rename) +static void file_change_cr(const char *p, struct branch *b, int rename) { - const char *d; - static struct strbuf s_uq = STRBUF_INIT; - static struct strbuf d_uq = STRBUF_INIT; - const char *endp; + static struct strbuf source = STRBUF_INIT; + static struct strbuf dest = STRBUF_INIT; struct tree_entry leaf; - strbuf_reset(&s_uq); - if (!unquote_c_style(&s_uq, s, &endp)) { - if (*endp != ' ') - die("Missing space after source: %s", command_buf.buf); - } else { - endp = strchr(s, ' '); - if (!endp) - die("Missing space after source: %s", command_buf.buf); - strbuf_add(&s_uq, s, endp - s); - } - s = s_uq.buf; - - endp++; - if (!*endp) - die("Missing dest: %s", command_buf.buf); - - d = endp; - strbuf_reset(&d_uq); - if (!unquote_c_style(&d_uq, d, &endp)) { - if (*endp) - die("Garbage after dest in: %s", command_buf.buf); - d = d_uq.buf; - } + strbuf_reset(&source); + parse_path_space(&source, p, &p, "source"); + strbuf_reset(&dest); + parse_path_eol(&dest, p, "dest"); memset(&leaf, 0, sizeof(leaf)); if (rename) - tree_content_remove(&b->branch_tree, s, &leaf, 1); + tree_content_remove(&b->branch_tree, source.buf, &leaf, 1); else - tree_content_get(&b->branch_tree, s, &leaf, 1); + tree_content_get(&b->branch_tree, source.buf, &leaf, 1); if (!leaf.versions[1].mode) - die("Path %s not in branch", s); - if (!*d) { /* C "path/to/subdir" "" */ + die("Path %s not in branch", source.buf); + if (!*dest.buf) { /* C "path/to/subdir" "" */ tree_content_replace(&b->branch_tree, &leaf.versions[1].oid, leaf.versions[1].mode, leaf.tree); return; } - tree_content_set(&b->branch_tree, d, + tree_content_set(&b->branch_tree, dest.buf, &leaf.versions[1].oid, leaf.versions[1].mode, leaf.tree); @@ -2442,7 +2459,6 @@ static void file_change_cr(const char *s, struct branch *b, int rename) static void note_change_n(const char *p, struct branch *b, unsigned char *old_fanout) { - static struct strbuf uq = STRBUF_INIT; struct object_entry *oe; struct branch *s; struct object_id oid, commit_oid; @@ -2507,10 +2523,6 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa die("Invalid ref name or SHA1 expression: %s", p); if (inline_data) { - if (p != uq.buf) { - strbuf_addstr(&uq, p); - p = uq.buf; - } read_next_command(); parse_and_store_blob(&last_blob, &oid, 0); } else if (oe) { @@ -2543,8 +2555,8 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa static void file_change_deleteall(struct branch *b) { release_tree_content_recursive(b->branch_tree.tree); - oidclr(&b->branch_tree.versions[0].oid); - oidclr(&b->branch_tree.versions[1].oid); + oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo); + oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo); load_tree(&b->branch_tree); b->num_notes = 0; } @@ -2563,8 +2575,8 @@ static void parse_from_commit(struct branch *b, char *buf, unsigned long size) static void parse_from_existing(struct branch *b) { if (is_null_oid(&b->oid)) { - oidclr(&b->branch_tree.versions[0].oid); - oidclr(&b->branch_tree.versions[1].oid); + oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo); + oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo); } else { unsigned long size; char *buf; @@ -2887,9 +2899,9 @@ static void parse_reset_branch(const char *arg) b = lookup_branch(arg); if (b) { - oidclr(&b->oid); - oidclr(&b->branch_tree.versions[0].oid); - oidclr(&b->branch_tree.versions[1].oid); + oidclr(&b->oid, the_repository->hash_algo); + oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo); + oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo); if (b->branch_tree.tree) { release_tree_content_recursive(b->branch_tree.tree); b->branch_tree.tree = NULL; @@ -3162,6 +3174,7 @@ static void print_ls(int mode, const unsigned char *hash, const char *path) static void parse_ls(const char *p, struct branch *b) { + static struct strbuf path = STRBUF_INIT; struct tree_entry *root = NULL; struct tree_entry leaf = {NULL}; @@ -3178,17 +3191,9 @@ static void parse_ls(const char *p, struct branch *b) root->versions[1].mode = S_IFDIR; load_tree(root); } - if (*p == '"') { - static struct strbuf uq = STRBUF_INIT; - const char *endp; - strbuf_reset(&uq); - if (unquote_c_style(&uq, p, &endp)) - die("Invalid path: %s", command_buf.buf); - if (*endp) - die("Garbage after path in: %s", command_buf.buf); - p = uq.buf; - } - tree_content_get(root, p, &leaf, 1); + strbuf_reset(&path); + parse_path_eol(&path, p, "path"); + tree_content_get(root, path.buf, &leaf, 1); /* * A directory in preparation would have a sha1 of zero * until it is saved. Save, for simplicity. @@ -3196,7 +3201,7 @@ static void parse_ls(const char *p, struct branch *b) if (S_ISDIR(leaf.versions[1].mode)) store_tree(&leaf); - print_ls(leaf.versions[1].mode, leaf.versions[1].oid.hash, p); + print_ls(leaf.versions[1].mode, leaf.versions[1].oid.hash, path.buf); if (leaf.tree) release_tree_content_recursive(leaf.tree); if (!b || root != &b->branch_tree) |
