diff options
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 97 |
1 files changed, 66 insertions, 31 deletions
@@ -120,25 +120,33 @@ int check_refname_format(const char *refname, int flags) int refname_is_safe(const char *refname) { - if (starts_with(refname, "refs/")) { + const char *rest; + + if (skip_prefix(refname, "refs/", &rest)) { char *buf; int result; + size_t restlen = strlen(rest); + + /* rest must not be empty, or start or end with "/" */ + if (!restlen || *rest == '/' || rest[restlen - 1] == '/') + return 0; - buf = xmallocz(strlen(refname)); /* * Does the refname try to escape refs/? * For example: refs/foo/../bar is safe but refs/foo/../../bar * is not. */ - result = !normalize_path_copy(buf, refname + strlen("refs/")); + buf = xmallocz(restlen); + result = !normalize_path_copy(buf, rest) && !strcmp(buf, rest); free(buf); return result; } - while (*refname) { + + do { if (!isupper(*refname) && *refname != '_') return 0; refname++; - } + } while (*refname); return 1; } @@ -496,7 +504,7 @@ static int write_pseudoref(const char *pseudoref, const unsigned char *sha1, filename = git_path("%s", pseudoref); fd = hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR); if (fd < 0) { - strbuf_addf(err, "Could not open '%s' for writing: %s", + strbuf_addf(err, "could not open '%s' for writing: %s", filename, strerror(errno)); return -1; } @@ -507,14 +515,14 @@ static int write_pseudoref(const char *pseudoref, const unsigned char *sha1, if (read_ref(pseudoref, actual_old_sha1)) die("could not read ref '%s'", pseudoref); if (hashcmp(actual_old_sha1, old_sha1)) { - strbuf_addf(err, "Unexpected sha1 when writing %s", pseudoref); + strbuf_addf(err, "unexpected sha1 when writing '%s'", pseudoref); rollback_lock_file(&lock); goto done; } } if (write_in_full(fd, buf.buf, buf.len) != buf.len) { - strbuf_addf(err, "Could not write to '%s'", filename); + strbuf_addf(err, "could not write to '%s'", filename); rollback_lock_file(&lock); goto done; } @@ -758,13 +766,32 @@ void ref_transaction_free(struct ref_transaction *transaction) free(transaction); } -static struct ref_update *add_update(struct ref_transaction *transaction, - const char *refname) +struct ref_update *ref_transaction_add_update( + struct ref_transaction *transaction, + const char *refname, unsigned int flags, + const unsigned char *new_sha1, + const unsigned char *old_sha1, + const char *msg) { struct ref_update *update; + + if (transaction->state != REF_TRANSACTION_OPEN) + die("BUG: update called for transaction that is not open"); + + if ((flags & REF_ISPRUNING) && !(flags & REF_NODEREF)) + die("BUG: REF_ISPRUNING set without REF_NODEREF"); + FLEX_ALLOC_STR(update, refname, refname); ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc); transaction->updates[transaction->nr++] = update; + + update->flags = flags; + + if (flags & REF_HAVE_NEW) + hashcpy(update->new_sha1, new_sha1); + if (flags & REF_HAVE_OLD) + hashcpy(update->old_sha1, old_sha1); + update->msg = xstrdup_or_null(msg); return update; } @@ -775,32 +802,20 @@ int ref_transaction_update(struct ref_transaction *transaction, unsigned int flags, const char *msg, struct strbuf *err) { - struct ref_update *update; - assert(err); - if (transaction->state != REF_TRANSACTION_OPEN) - die("BUG: update called for transaction that is not open"); - - if (new_sha1 && !is_null_sha1(new_sha1) && - check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { - strbuf_addf(err, "refusing to update ref with bad name %s", + if ((new_sha1 && !is_null_sha1(new_sha1)) ? + check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) : + !refname_is_safe(refname)) { + strbuf_addf(err, "refusing to update ref with bad name '%s'", refname); return -1; } - update = add_update(transaction, refname); - if (new_sha1) { - hashcpy(update->new_sha1, new_sha1); - flags |= REF_HAVE_NEW; - } - if (old_sha1) { - hashcpy(update->old_sha1, old_sha1); - flags |= REF_HAVE_OLD; - } - update->flags = flags; - if (msg) - update->msg = xstrdup(msg); + flags |= (new_sha1 ? REF_HAVE_NEW : 0) | (old_sha1 ? REF_HAVE_OLD : 0); + + ref_transaction_add_update(transaction, refname, flags, + new_sha1, old_sha1, msg); return 0; } @@ -906,7 +921,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict) /* -2 for strlen("%.*s") - strlen("%s"); +1 for NUL */ total_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1; - scanf_fmts = xmalloc(st_add(st_mult(nr_rules, sizeof(char *)), total_len)); + scanf_fmts = xmalloc(st_add(st_mult(sizeof(char *), nr_rules), total_len)); offset = 0; for (i = 0; i < nr_rules; i++) { @@ -1104,6 +1119,26 @@ int head_ref(each_ref_fn fn, void *cb_data) return head_ref_submodule(NULL, fn, cb_data); } +/* + * Call fn for each reference in the specified submodule for which the + * refname begins with prefix. If trim is non-zero, then trim that + * many characters off the beginning of each refname before passing + * the refname to fn. flags can be DO_FOR_EACH_INCLUDE_BROKEN to + * include broken references in the iteration. If fn ever returns a + * non-zero value, stop the iteration and return that value; + * otherwise, return 0. + */ +static int do_for_each_ref(const char *submodule, const char *prefix, + each_ref_fn fn, int trim, int flags, void *cb_data) +{ + struct ref_iterator *iter; + + iter = files_ref_iterator_begin(submodule, prefix, flags); + iter = prefix_ref_iterator_begin(iter, prefix, trim); + + return do_for_each_ref_iterator(iter, fn, cb_data); +} + int for_each_ref(each_ref_fn fn, void *cb_data) { return do_for_each_ref(NULL, "", fn, 0, 0, cb_data); |