diff options
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 171 |
1 files changed, 142 insertions, 29 deletions
@@ -5,6 +5,7 @@ #include "cache.h" #include "hashmap.h" #include "lockfile.h" +#include "iterator.h" #include "refs.h" #include "refs/refs-internal.h" #include "object.h" @@ -405,11 +406,11 @@ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data) const char *prettify_refname(const char *name) { - return name + ( - starts_with(name, "refs/heads/") ? 11 : - starts_with(name, "refs/tags/") ? 10 : - starts_with(name, "refs/remotes/") ? 13 : - 0); + if (skip_prefix(name, "refs/heads/", &name) || + skip_prefix(name, "refs/tags/", &name) || + skip_prefix(name, "refs/remotes/", &name)) + ; /* nothing */ + return name; } static const char *ref_rev_parse_rules[] = { @@ -468,29 +469,31 @@ int expand_ref(const char *str, int len, unsigned char *sha1, char **ref) { const char **p, *r; int refs_found = 0; + struct strbuf fullref = STRBUF_INIT; *ref = NULL; for (p = ref_rev_parse_rules; *p; p++) { - char fullref[PATH_MAX]; unsigned char sha1_from_ref[20]; unsigned char *this_result; int flag; this_result = refs_found ? sha1_from_ref : sha1; - mksnpath(fullref, sizeof(fullref), *p, len, str); - r = resolve_ref_unsafe(fullref, RESOLVE_REF_READING, + strbuf_reset(&fullref); + strbuf_addf(&fullref, *p, len, str); + r = resolve_ref_unsafe(fullref.buf, RESOLVE_REF_READING, this_result, &flag); if (r) { if (!refs_found++) *ref = xstrdup(r); if (!warn_ambiguous_refs) break; - } else if ((flag & REF_ISSYMREF) && strcmp(fullref, "HEAD")) { - warning("ignoring dangling symref %s.", fullref); - } else if ((flag & REF_ISBROKEN) && strchr(fullref, '/')) { - warning("ignoring broken ref %s.", fullref); + } else if ((flag & REF_ISSYMREF) && strcmp(fullref.buf, "HEAD")) { + warning("ignoring dangling symref %s.", fullref.buf); + } else if ((flag & REF_ISBROKEN) && strchr(fullref.buf, '/')) { + warning("ignoring broken ref %s.", fullref.buf); } } + strbuf_release(&fullref); return refs_found; } @@ -499,21 +502,22 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) char *last_branch = substitute_branch_name(&str, &len); const char **p; int logs_found = 0; + struct strbuf path = STRBUF_INIT; *log = NULL; for (p = ref_rev_parse_rules; *p; p++) { unsigned char hash[20]; - char path[PATH_MAX]; const char *ref, *it; - mksnpath(path, sizeof(path), *p, len, str); - ref = resolve_ref_unsafe(path, RESOLVE_REF_READING, + strbuf_reset(&path); + strbuf_addf(&path, *p, len, str); + ref = resolve_ref_unsafe(path.buf, RESOLVE_REF_READING, hash, NULL); if (!ref) continue; - if (reflog_exists(path)) - it = path; - else if (strcmp(ref, path) && reflog_exists(ref)) + if (reflog_exists(path.buf)) + it = path.buf; + else if (strcmp(ref, path.buf) && reflog_exists(ref)) it = ref; else continue; @@ -524,6 +528,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) if (!warn_ambiguous_refs) break; } + strbuf_release(&path); free(last_branch); return logs_found; } @@ -1014,6 +1019,7 @@ char *shorten_unambiguous_ref(const char *refname, int strict) static char **scanf_fmts; static int nr_rules; char *short_name; + struct strbuf resolved_buf = STRBUF_INIT; if (!nr_rules) { /* @@ -1072,7 +1078,6 @@ char *shorten_unambiguous_ref(const char *refname, int strict) */ for (j = 0; j < rules_to_fail; j++) { const char *rule = ref_rev_parse_rules[j]; - char refname[PATH_MAX]; /* skip matched rule */ if (i == j) @@ -1083,9 +1088,10 @@ char *shorten_unambiguous_ref(const char *refname, int strict) * (with this previous rule) to a valid ref * read_ref() returns 0 on success */ - mksnpath(refname, sizeof(refname), - rule, short_name_len, short_name); - if (ref_exists(refname)) + strbuf_reset(&resolved_buf); + strbuf_addf(&resolved_buf, rule, + short_name_len, short_name); + if (ref_exists(resolved_buf.buf)) break; } @@ -1093,10 +1099,13 @@ char *shorten_unambiguous_ref(const char *refname, int strict) * short name is non-ambiguous if all previous rules * haven't resolved to a valid ref */ - if (j == rules_to_fail) + if (j == rules_to_fail) { + strbuf_release(&resolved_buf); return short_name; + } } + strbuf_release(&resolved_buf); free(short_name); return xstrdup(refname); } @@ -1231,6 +1240,18 @@ int head_ref(each_ref_fn fn, void *cb_data) return head_ref_submodule(NULL, fn, cb_data); } +struct ref_iterator *refs_ref_iterator_begin( + struct ref_store *refs, + const char *prefix, int trim, int flags) +{ + struct ref_iterator *iter; + + iter = refs->be->iterator_begin(refs, prefix, flags); + iter = prefix_ref_iterator_begin(iter, prefix, trim); + + return iter; +} + /* * Call fn for each reference in the specified submodule for which the * refname begins with prefix. If trim is non-zero, then trim that @@ -1248,8 +1269,7 @@ static int do_for_each_ref(struct ref_store *refs, const char *prefix, if (!refs) return 0; - iter = refs->be->iterator_begin(refs, prefix, flags); - iter = prefix_ref_iterator_begin(iter, prefix, trim); + iter = refs_ref_iterator_begin(refs, prefix, trim, flags); return do_for_each_ref_iterator(iter, fn, cb_data); } @@ -1327,6 +1347,13 @@ int for_each_rawref(each_ref_fn fn, void *cb_data) return refs_for_each_rawref(get_main_ref_store(), fn, cb_data); } +int refs_read_raw_ref(struct ref_store *ref_store, + const char *refname, unsigned char *sha1, + struct strbuf *referent, unsigned int *type) +{ + return ref_store->be->read_raw_ref(ref_store, refname, sha1, referent, type); +} + /* This function needs to return a meaningful errno on failure */ const char *refs_resolve_ref_unsafe(struct ref_store *refs, const char *refname, @@ -1363,8 +1390,8 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, for (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) { unsigned int read_flags = 0; - if (refs->be->read_raw_ref(refs, refname, - sha1, &sb_refname, &read_flags)) { + if (refs_read_raw_ref(refs, refname, + sha1, &sb_refname, &read_flags)) { *flags |= read_flags; if (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING)) return NULL; @@ -1661,16 +1688,102 @@ int ref_transaction_commit(struct ref_transaction *transaction, { struct ref_store *refs = transaction->ref_store; + if (getenv(GIT_QUARANTINE_ENVIRONMENT)) { + strbuf_addstr(err, + _("ref updates forbidden inside quarantine environment")); + return -1; + } + return refs->be->transaction_commit(refs, transaction, err); } int refs_verify_refname_available(struct ref_store *refs, const char *refname, - const struct string_list *extra, + const struct string_list *extras, const struct string_list *skip, struct strbuf *err) { - return refs->be->verify_refname_available(refs, refname, extra, skip, err); + const char *slash; + const char *extra_refname; + struct strbuf dirname = STRBUF_INIT; + struct strbuf referent = STRBUF_INIT; + struct object_id oid; + unsigned int type; + struct ref_iterator *iter; + int ok; + int ret = -1; + + /* + * For the sake of comments in this function, suppose that + * refname is "refs/foo/bar". + */ + + assert(err); + + strbuf_grow(&dirname, strlen(refname) + 1); + for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) { + /* Expand dirname to the new prefix, not including the trailing slash: */ + strbuf_add(&dirname, refname + dirname.len, slash - refname - dirname.len); + + /* + * We are still at a leading dir of the refname (e.g., + * "refs/foo"; if there is a reference with that name, + * it is a conflict, *unless* it is in skip. + */ + if (skip && string_list_has_string(skip, dirname.buf)) + continue; + + if (!refs_read_raw_ref(refs, dirname.buf, oid.hash, &referent, &type)) { + strbuf_addf(err, "'%s' exists; cannot create '%s'", + dirname.buf, refname); + goto cleanup; + } + + if (extras && string_list_has_string(extras, dirname.buf)) { + strbuf_addf(err, "cannot process '%s' and '%s' at the same time", + refname, dirname.buf); + goto cleanup; + } + } + + /* + * We are at the leaf of our refname (e.g., "refs/foo/bar"). + * There is no point in searching for a reference with that + * name, because a refname isn't considered to conflict with + * itself. But we still need to check for references whose + * names are in the "refs/foo/bar/" namespace, because they + * *do* conflict. + */ + strbuf_addstr(&dirname, refname + dirname.len); + strbuf_addch(&dirname, '/'); + + iter = refs_ref_iterator_begin(refs, dirname.buf, 0, + DO_FOR_EACH_INCLUDE_BROKEN); + while ((ok = ref_iterator_advance(iter)) == ITER_OK) { + if (skip && + string_list_has_string(skip, iter->refname)) + continue; + + strbuf_addf(err, "'%s' exists; cannot create '%s'", + iter->refname, refname); + ref_iterator_abort(iter); + goto cleanup; + } + + if (ok != ITER_DONE) + die("BUG: error while iterating over references"); + + extra_refname = find_descendant_ref(dirname.buf, extras, skip); + if (extra_refname) + strbuf_addf(err, "cannot process '%s' and '%s' at the same time", + refname, extra_refname); + else + ret = 0; + +cleanup: + strbuf_release(&referent); + strbuf_release(&dirname); + return ret; } int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data) |