On Tue, Jul 15, 2014 at 12:34 PM, Ronnie Sahlberg <sahlberg@xxxxxxxxxx> wrote: > On Tue, Jul 15, 2014 at 11:04 AM, Jonathan Nieder <jrnieder@xxxxxxxxx> wrote: >> Michael Haggerty wrote: >> >>> So...I like the idea of enforcing refname checks at the lowest level >>> possible, but I think that the change you propose is too abrupt. I >>> think it needs either more careful analysis showing that it won't hurt >>> anybody, or some kind of tooling or non-strict mode that people can use >>> to fix their repositories. >> >> The recovery code has been broken for a while, so I don't see harm >> in this change. >> >> How to take care of the recovery use case is another question. FWIW I >> also would prefer if "git update-ref -d" or "git branch -D" could be >> used to delete corrupt refs instead of having to use fsck (since a >> fsck run can take a while), but that's a question for a later series. >> >> In an ideal world, the low-level functions would allow *reading* and >> *deleting* poorly named refs (even without any special flag) but not >> creating them. Is that doable? > > That should be doable. Ill add these repairs as 3-4 new patches at the > end of the current patch series. > >> The main complication I can see is >> iteration: would iteration skip poorly named refs and warn, or would >> something more complicated be needed? > > Right now, "git branch" will error and abort right away when it > finds the first bad ref. I haven't checked the exact spot it does this > yet but I suspect it is when building the ref-cache. > I will solve the cases for create and delete for now. > > > What/how to handle iterables will require more thought. > Right now, since these refs will be filtered out and never end up in > ref-cache, either from loose refs or from packed refs > it does mean that anyone that uses an iterator is guaranteed to only > get refs with valid names passed back to them. > We would need to audit all code that uses iterators and make sure it > can handle the case where the callback is suddenly > invoked with a bad refname. > >> >> Thanks, >> Jonathan The following seems to do the trick to allow deleting a bad ref. We would need something for the iterator too. Since this touches the same areas that my ~100 other ref transaction patches that are queued up do, I would like to wait applying this patch until once the next few series are finished and merged. (to avoid having to do a lot of rebases and fix legio of merge conflicts that this would introduce in my branches). Treat this as an approximation on what the fix to repair git branch -D will look like once the time comes. regards ronnie sahlberg === commit a2514213999a192c9995a3a5e1479d7d09e2c083 Author: Ronnie Sahlberg <sahlberg@xxxxxxxxxx> Date: Tue Jul 15 12:59:36 2014 -0700 refs.c: fix handling of badly named refs We currently do not handle badly named refs well : $ cp .git/refs/heads/master .git/refs/heads/master.....@\*@\\. $ git branch fatal: Reference has invalid format: 'refs/heads/master.....@*@\.' $ git branch -D master.....@\*@\\. error: branch 'master.....@*@\.' not found. But we can not really recover from a badly named ref with less than manually deleting the .git/refs/heads/<refname> file. Change resolve_ref_unsafe to take a flags field instead of a 'reading' boolean and update all callers that used a non-zero value for reading to pass the flag RESOLVE_REF_READING instead. Add another flag RESOLVE_REF_ALLOW_BAD_NAME that will make resolve_ref_unsafe skip checking the refname for sanity and use this from branch.c so that we will be able to call resolve_ref_unsafe on such refs when trying to delete it. Add checks for refname sanity when updating (not deleting) a ref in ref_transaction_update and in ref_transaction_create to make the transaction fail if an attempt is made to create/update a badly named ref. Since all ref changes will later go through the transaction layer this means we no longer need to check for and fail for bad refnames in lock_ref_sha1_basic. Change lock_ref_sha1_basic to not fail for bad refnames. Just check the refname, and print an error, and remember that the refname is bad so that we can skip calling verify_lock(). Signed-off-by: Ronnie Sahlberg <sahlberg@xxxxxxxxxx> diff --git a/builtin/blame.c b/builtin/blame.c index 662e3fe..76340e2 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -2278,7 +2278,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, commit->object.type = OBJ_COMMIT; parent_tail = &commit->parents; - if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL)) + if (!resolve_ref_unsafe("HEAD", head_sha1, RESOLVE_REF_READING, NULL)) die("no such ref: HEAD"); parent_tail = append_parent(parent_tail, head_sha1); diff --git a/builtin/branch.c b/builtin/branch.c index 652b1d2..5c95656 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -129,7 +129,8 @@ static int branch_merged(int kind, const char *name, branch->merge[0] && branch->merge[0]->dst && (reference_name = reference_name_to_free = - resolve_refdup(branch->merge[0]->dst, sha1, 1, NULL)) != NULL) + resolve_refdup(branch->merge[0]->dst, sha1, + RESOLVE_REF_READING, NULL)) != NULL) reference_rev = lookup_commit_reference(sha1); } if (!reference_rev) @@ -233,7 +234,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, free(name); name = mkpathdup(fmt, bname.buf); - target = resolve_ref_unsafe(name, sha1, 0, &flags); + target = resolve_ref_unsafe(name, sha1, + RESOLVE_REF_ALLOW_BAD_NAME, &flags); if (!target || (!(flags & REF_ISSYMREF) && is_null_sha1(sha1))) { error(remote_branch diff --git a/builtin/clone.c b/builtin/clone.c index b12989d..f7307e6 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -622,7 +622,7 @@ static int checkout(void) if (option_no_checkout) return 0; - head = resolve_refdup("HEAD", sha1, 1, NULL); + head = resolve_refdup("HEAD", sha1, RESOLVE_REF_READING, NULL); if (!head) { warning(_("remote HEAD refers to nonexistent ref, " "unable to checkout.\n")); diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 3906eda..d8ab177 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -602,7 +602,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out, /* get current branch */ current_branch = current_branch_to_free = - resolve_refdup("HEAD", head_sha1, 1, NULL); + resolve_refdup("HEAD", head_sha1, RESOLVE_REF_READING, NULL); if (!current_branch) die("No current branch"); if (starts_with(current_branch, "refs/heads/")) diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 4135980..a5833fd 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -649,7 +649,8 @@ static void populate_value(struct refinfo *ref) if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) { unsigned char unused1[20]; - ref->symref = resolve_refdup(ref->refname, unused1, 1, NULL); + ref->symref = resolve_refdup(ref->refname, unused1, + RESOLVE_REF_READING, NULL); if (!ref->symref) ref->symref = ""; } @@ -707,7 +708,8 @@ static void populate_value(struct refinfo *ref) const char *head; unsigned char sha1[20]; - head = resolve_ref_unsafe("HEAD", sha1, 1, NULL); + head = resolve_ref_unsafe("HEAD", sha1, + RESOLVE_REF_READING, NULL); if (!strcmp(ref->refname, head)) v->s = "*"; else diff --git a/builtin/log.c b/builtin/log.c index a7ba211..92db809 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1395,7 +1395,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (check_head) { unsigned char sha1[20]; const char *ref; - ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL); + ref = resolve_ref_unsafe("HEAD", sha1, + RESOLVE_REF_READING, NULL); if (ref && starts_with(ref, "refs/heads/")) branch_name = xstrdup(ref + strlen("refs/heads/")); else diff --git a/builtin/remote.c b/builtin/remote.c index 401feb3..be8ebac 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -568,7 +568,8 @@ static int read_remote_branches(const char *refname, strbuf_addf(&buf, "refs/remotes/%s/", rename->old); if (starts_with(refname, buf.buf)) { item = string_list_append(rename->remote_branches, xstrdup(refname)); - symref = resolve_ref_unsafe(refname, orig_sha1, 1, &flag); + symref = resolve_ref_unsafe(refname, orig_sha1, + RESOLVE_REF_READING, &flag); if (flag & REF_ISSYMREF) item->util = xstrdup(symref); else @@ -704,7 +705,7 @@ static int mv(int argc, const char **argv) int flag = 0; unsigned char sha1[20]; - read_ref_full(item->string, sha1, 1, &flag); + read_ref_full(item->string, sha1, RESOLVE_REF_READING, &flag); if (!(flag & REF_ISSYMREF)) continue; if (delete_ref(item->string, NULL, REF_NODEREF)) diff --git a/builtin/show-branch.c b/builtin/show-branch.c index d873172..a9a5eb3 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -727,7 +727,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) if (ac == 0) { static const char *fake_av[2]; - fake_av[0] = resolve_refdup("HEAD", sha1, 1, NULL); + fake_av[0] = resolve_refdup("HEAD", sha1, + RESOLVE_REF_READING, NULL); fake_av[1] = NULL; av = fake_av; ac = 1; @@ -789,7 +790,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) } } - head_p = resolve_ref_unsafe("HEAD", head_sha1, 1, NULL); + head_p = resolve_ref_unsafe("HEAD", head_sha1, + RESOLVE_REF_READING, NULL); if (head_p) { head_len = strlen(head_p); memcpy(head, head_p, head_len + 1); diff --git a/bundle.c b/bundle.c index 1222952..8aaf5f8 100644 --- a/bundle.c +++ b/bundle.c @@ -311,7 +311,7 @@ int create_bundle(struct bundle_header *header, const char *path, continue; if (dwim_ref(e->name, strlen(e->name), sha1, &ref) != 1) continue; - if (read_ref_full(e->name, sha1, 1, &flag)) + if (read_ref_full(e->name, sha1, RESOLVE_REF_READING, &flag)) flag = 0; display_ref = (flag & REF_ISSYMREF) ? e->name : ref; diff --git a/cache.h b/cache.h index 4ca4583..aab246d 100644 --- a/cache.h +++ b/cache.h @@ -948,7 +948,7 @@ extern int get_sha1_hex(const char *hex, unsigned char *sha1); extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */ extern int read_ref_full(const char *refname, unsigned char *sha1, - int reading, int *flags); + int flags, int *ref_flag); extern int read_ref(const char *refname, unsigned char *sha1); /* @@ -960,17 +960,17 @@ extern int read_ref(const char *refname, unsigned char *sha1); * or the input ref. * * If the reference cannot be resolved to an object, the behavior - * depends on the "reading" argument: + * depends on the RESOLVE_REF_READING flag: * - * - If reading is set, return NULL. + * - If RESOLVE_REF_READING is set, return NULL. * - * - If reading is not set, clear sha1 and return the name of the last - * reference name in the chain, which will either be a non-symbolic + * - If RESOLVE_REF_READING is not set, clear sha1 and return the name of + * the last reference name in the chain, which will either be a non-symbolic * reference or an undefined reference. If this is a prelude to * "writing" to the ref, the return value is the name of the ref * that will actually be created or changed. * - * If flag is non-NULL, set the value that it points to the + * If ref_flag is non-NULL, set the value that it points to the * combination of REF_ISPACKED (if the reference was found among the * packed references) and REF_ISSYMREF (if the initial reference was a * symbolic reference). @@ -981,8 +981,10 @@ extern int read_ref(const char *refname, unsigned char *sha1); * * errno is set to something meaningful on error. */ -extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, int reading, int *flag); -extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag); +#define RESOLVE_REF_READING 0x01 +#define RESOLVE_REF_ALLOW_BAD_NAME 0x02 +extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, int flags, int *ref_flag); +extern char *resolve_refdup(const char *ref, unsigned char *sha1, int flags, int *ref_flag); extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref); extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref); diff --git a/http-backend.c b/http-backend.c index d2c0a62..059f790 100644 --- a/http-backend.c +++ b/http-backend.c @@ -417,7 +417,8 @@ static int show_head_ref(const char *refname, const unsigned char *sha1, if (flag & REF_ISSYMREF) { unsigned char unused[20]; - const char *target = resolve_ref_unsafe(refname, unused, 1, NULL); + const char *target = resolve_ref_unsafe(refname, unused, + RESOLVE_REF_READING, NULL); const char *target_nons = strip_namespace(target); strbuf_addf(buf, "ref: %s\n", target_nons); diff --git a/reflog-walk.c b/reflog-walk.c index 9ce8b53..d80a42a 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -48,7 +48,8 @@ static struct complete_reflogs *read_complete_reflog(const char *ref) unsigned char sha1[20]; const char *name; void *name_to_free; - name = name_to_free = resolve_refdup(ref, sha1, 1, NULL); + name = name_to_free = resolve_refdup(ref, sha1, + RESOLVE_REF_READING, NULL); if (name) { for_each_reflog_ent(name, read_one_reflog, reflogs); free(name_to_free); diff --git a/refs.c b/refs.c index 221d8a7..dd9d61d 100644 --- a/refs.c +++ b/refs.c @@ -1194,7 +1194,8 @@ static void read_loose_refs(const char *dirname, struct ref_dir *dir) hashclr(sha1); flag |= REF_ISBROKEN; } - } else if (read_ref_full(refname.buf, sha1, 1, &flag)) { + } else if (read_ref_full(refname.buf, sha1, + RESOLVE_REF_READING, &flag)) { hashclr(sha1); flag |= REF_ISBROKEN; } @@ -1346,21 +1347,21 @@ static const char *handle_missing_loose_ref(const char *refname, } /* This function needs to return a meaningful errno on failure */ -const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int reading, int *flag) +const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int flags, int *ref_flag) { int depth = MAXDEPTH; ssize_t len; char buffer[256]; static char refname_buffer[256]; - if (flag) - *flag = 0; + if (ref_flag) + *ref_flag = 0; - if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { + if (!(flags & RESOLVE_REF_ALLOW_BAD_NAME) && + check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { errno = EINVAL; return NULL; } - for (;;) { char path[PATH_MAX]; struct stat st; @@ -1387,7 +1388,8 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea if (lstat(path, &st) < 0) { if (errno == ENOENT) return handle_missing_loose_ref(refname, sha1, - reading, flag); + flags & RESOLVE_REF_READING, + ref_flag); else return NULL; } @@ -1407,8 +1409,8 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea !check_refname_format(buffer, 0)) { strcpy(refname_buffer, buffer); refname = refname_buffer; - if (flag) - *flag |= REF_ISSYMREF; + if (ref_flag) + *ref_flag |= REF_ISSYMREF; continue; } } @@ -1453,21 +1455,21 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea */ if (get_sha1_hex(buffer, sha1) || (buffer[40] != '\0' && !isspace(buffer[40]))) { - if (flag) - *flag |= REF_ISBROKEN; + if (ref_flag) + *ref_flag |= REF_ISBROKEN; errno = EINVAL; return NULL; } return refname; } - if (flag) - *flag |= REF_ISSYMREF; + if (ref_flag) + *ref_flag |= REF_ISSYMREF; buf = buffer + 4; while (isspace(*buf)) buf++; if (check_refname_format(buf, REFNAME_ALLOW_ONELEVEL)) { - if (flag) - *flag |= REF_ISBROKEN; + if (ref_flag) + *ref_flag |= REF_ISBROKEN; errno = EINVAL; return NULL; } @@ -1475,9 +1477,9 @@ const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int rea } } -char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag) +char *resolve_refdup(const char *ref, unsigned char *sha1, int flags, int *ref_flag) { - const char *ret = resolve_ref_unsafe(ref, sha1, reading, flag); + const char *ret = resolve_ref_unsafe(ref, sha1, flags, ref_flag); return ret ? xstrdup(ret) : NULL; } @@ -1488,22 +1490,22 @@ struct ref_filter { void *cb_data; }; -int read_ref_full(const char *refname, unsigned char *sha1, int reading, int *flags) +int read_ref_full(const char *refname, unsigned char *sha1, int flags, int *ref_flag) { - if (resolve_ref_unsafe(refname, sha1, reading, flags)) + if (resolve_ref_unsafe(refname, sha1, flags, ref_flag)) return 0; return -1; } int read_ref(const char *refname, unsigned char *sha1) { - return read_ref_full(refname, sha1, 1, NULL); + return read_ref_full(refname, sha1, RESOLVE_REF_READING, NULL); } int ref_exists(const char *refname) { unsigned char sha1[20]; - return !!resolve_ref_unsafe(refname, sha1, 1, NULL); + return !!resolve_ref_unsafe(refname, sha1, RESOLVE_REF_READING, NULL); } static int filter_refs(const char *refname, const unsigned char *sha1, int flags, @@ -1617,7 +1619,7 @@ int peel_ref(const char *refname, unsigned char *sha1) return 0; } - if (read_ref_full(refname, base, 1, &flag)) + if (read_ref_full(refname, base, RESOLVE_REF_READING, &flag)) return -1; /* @@ -1783,7 +1785,7 @@ static int do_head_ref(const char *submodule, each_ref_fn fn, void *cb_data) return 0; } - if (!read_ref_full("HEAD", sha1, 1, &flag)) + if (!read_ref_full("HEAD", sha1, RESOLVE_REF_READING, &flag)) return fn("HEAD", sha1, flag, cb_data); return 0; @@ -1863,7 +1865,7 @@ int head_ref_namespaced(each_ref_fn fn, void *cb_data) int flag; strbuf_addf(&buf, "%sHEAD", get_git_namespace()); - if (!read_ref_full(buf.buf, sha1, 1, &flag)) + if (!read_ref_full(buf.buf, sha1, RESOLVE_REF_READING, &flag)) ret = fn(buf.buf, sha1, flag, cb_data); strbuf_release(&buf); @@ -1958,7 +1960,8 @@ int refname_match(const char *abbrev_name, const char *full_name) static struct ref_lock *verify_lock(struct ref_lock *lock, const unsigned char *old_sha1, int mustexist) { - if (read_ref_full(lock->ref_name, lock->old_sha1, mustexist, NULL)) { + if (read_ref_full(lock->ref_name, lock->old_sha1, + mustexist ? RESOLVE_REF_READING : 0, NULL)) { int save_errno = errno; error("Can't verify ref %s", lock->ref_name); unlock_ref(lock); @@ -2031,7 +2034,8 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref) this_result = refs_found ? sha1_from_ref : sha1; mksnpath(fullref, sizeof(fullref), *p, len, str); - r = resolve_ref_unsafe(fullref, this_result, 1, &flag); + r = resolve_ref_unsafe(fullref, this_result, + RESOLVE_REF_READING, &flag); if (r) { if (!refs_found++) *ref = xstrdup(r); @@ -2060,7 +2064,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) const char *ref, *it; mksnpath(path, sizeof(path), *p, len, str); - ref = resolve_ref_unsafe(path, hash, 1, NULL); + ref = resolve_ref_unsafe(path, hash, RESOLVE_REF_READING, NULL); if (!ref) continue; if (reflog_exists(path)) @@ -2092,18 +2096,22 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, int last_errno = 0; int type, lflags; int mustexist = (old_sha1 && !is_null_sha1(old_sha1)); + int resolve_flags; int missing = 0; int attempts_remaining = 3; - - if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { - errno = EINVAL; - return NULL; - } + int bad_refname; lock = xcalloc(1, sizeof(struct ref_lock)); lock->lock_fd = -1; - refname = resolve_ref_unsafe(refname, lock->old_sha1, mustexist, &type); + bad_refname = check_refname_format(refname, REFNAME_ALLOW_ONELEVEL); + + resolve_flags = RESOLVE_REF_ALLOW_BAD_NAME; + if (mustexist) + resolve_flags |= RESOLVE_REF_READING; + + refname = resolve_ref_unsafe(refname, lock->old_sha1, resolve_flags, + &type); if (!refname && errno == EISDIR) { /* we are trying to lock foo but we used to * have foo/bar which now does not exist; @@ -2116,7 +2124,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, error("there are still refs under '%s'", orig_refname); goto error_return; } - refname = resolve_ref_unsafe(orig_refname, lock->old_sha1, mustexist, &type); + refname = resolve_ref_unsafe(orig_refname, lock->old_sha1, + resolve_flags, &type); } if (type_p) *type_p = type; @@ -2180,6 +2189,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, else unable_to_lock_index_die(ref_file, errno); } + if (bad_refname) + return lock; return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock; error_return: @@ -2680,7 +2691,8 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms if (log && S_ISLNK(loginfo.st_mode)) return error("reflog for %s is a symlink", oldrefname); - symref = resolve_ref_unsafe(oldrefname, orig_sha1, 1, &flag); + symref = resolve_ref_unsafe(oldrefname, orig_sha1, + RESOLVE_REF_READING, &flag); if (flag & REF_ISSYMREF) return error("refname %s is a symbolic ref, renaming it is not supported", oldrefname); @@ -2704,7 +2716,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms goto rollback; } - if (!read_ref_full(newrefname, sha1, 1, NULL) && + if (!read_ref_full(newrefname, sha1, RESOLVE_REF_READING, NULL) && delete_ref(newrefname, sha1, REF_NODEREF)) { if (errno==EISDIR) { if (remove_empty_directories(git_path("%s", newrefname))) { @@ -2982,7 +2994,8 @@ static int write_ref_sha1(struct ref_lock *lock, unsigned char head_sha1[20]; int head_flag; const char *head_ref; - head_ref = resolve_ref_unsafe("HEAD", head_sha1, 1, &head_flag); + head_ref = resolve_ref_unsafe("HEAD", head_sha1, + RESOLVE_REF_READING, &head_flag); if (head_ref && (head_flag & REF_ISSYMREF) && !strcmp(head_ref, lock->ref_name)) log_ref_write("HEAD", lock->old_sha1, sha1, logmsg); @@ -3468,6 +3481,12 @@ int ref_transaction_update(struct ref_transaction *transaction, if (have_old && !old_sha1) die("BUG: have_old is true but old_sha1 is NULL"); + if (!is_null_sha1(new_sha1) && + check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { + strbuf_addf(err, "Bad refname: %s", refname); + return -1; + } + update = add_update(transaction, refname); hashcpy(update->new_sha1, new_sha1); update->flags = flags; @@ -3493,6 +3512,11 @@ int ref_transaction_create(struct ref_transaction *transaction, if (!new_sha1 || is_null_sha1(new_sha1)) die("BUG: create ref with null new_sha1"); + if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { + strbuf_addf(err, "Bad refname: %s", refname); + return -1; + } + update = add_update(transaction, refname); hashcpy(update->new_sha1, new_sha1); diff --git a/remote.c b/remote.c index ae04043..de84ac3 100644 --- a/remote.c +++ b/remote.c @@ -1121,7 +1121,8 @@ static char *guess_ref(const char *name, struct ref *peer) struct strbuf buf = STRBUF_INIT; unsigned char sha1[20]; - const char *r = resolve_ref_unsafe(peer->name, sha1, 1, NULL); + const char *r = resolve_ref_unsafe(peer->name, sha1, + RESOLVE_REF_READING, NULL); if (!r) return NULL; @@ -1182,7 +1183,8 @@ static int match_explicit(struct ref *src, struct ref *dst, unsigned char sha1[20]; int flag; - dst_value = resolve_ref_unsafe(matched_src->name, sha1, 1, &flag); + dst_value = resolve_ref_unsafe(matched_src->name, sha1, + RESOLVE_REF_READING, &flag); if (!dst_value || ((flag & REF_ISSYMREF) && !starts_with(dst_value, "refs/heads/"))) diff --git a/sequencer.c b/sequencer.c index 284059b..e1419bf 100644 --- a/sequencer.c +++ b/sequencer.c @@ -365,7 +365,7 @@ static int is_index_unchanged(void) unsigned char head_sha1[20]; struct commit *head_commit; - if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL)) + if (!resolve_ref_unsafe("HEAD", head_sha1, RESOLVE_REF_READING, NULL)) return error(_("Could not resolve HEAD commit\n")); head_commit = lookup_commit(head_sha1); diff --git a/transport-helper.c b/transport-helper.c index 84c616f..270ae28 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -889,7 +889,7 @@ static int push_refs_with_export(struct transport *transport, int flag; /* Follow symbolic refs (mainly for HEAD). */ - name = resolve_ref_unsafe(ref->peer_ref->name, sha1, 1, &flag); + name = resolve_ref_unsafe(ref->peer_ref->name, sha1, RESOLVE_REF_READING, &flag); if (!name || !(flag & REF_ISSYMREF)) name = ref->peer_ref->name; diff --git a/transport.c b/transport.c index 325f03e..f40e950 100644 --- a/transport.c +++ b/transport.c @@ -168,7 +168,8 @@ static void set_upstreams(struct transport *transport, struct ref *refs, /* Follow symbolic refs (mainly for HEAD). */ localname = ref->peer_ref->name; remotename = ref->name; - tmp = resolve_ref_unsafe(localname, sha, 1, &flag); + tmp = resolve_ref_unsafe(localname, sha, + RESOLVE_REF_READING, &flag); if (tmp && flag & REF_ISSYMREF && starts_with(tmp, "refs/heads/")) localname = tmp; @@ -753,7 +754,7 @@ void transport_print_push_status(const char *dest, struct ref *refs, unsigned char head_sha1[20]; char *head; - head = resolve_refdup("HEAD", head_sha1, 1, NULL); + head = resolve_refdup("HEAD", head_sha1, RESOLVE_REF_READING, NULL); if (verbose) { for (ref = refs; ref; ref = ref->next) -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html