aboutsummaryrefslogtreecommitdiffstats
path: root/builtin/fast-import.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/fast-import.c')
-rw-r--r--builtin/fast-import.c243
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)