diff options
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 225 |
1 files changed, 117 insertions, 108 deletions
@@ -10,6 +10,7 @@ #include "refs.h" #include "refs/refs-internal.h" #include "run-command.h" +#include "hook.h" #include "object-store.h" #include "object.h" #include "tag.h" @@ -33,11 +34,6 @@ static struct ref_storage_be *find_ref_storage_backend(const char *name) return NULL; } -int ref_storage_backend_exists(const char *name) -{ - return find_ref_storage_backend(name) != NULL; -} - /* * How to handle various characters in refnames: * 0: An acceptable character for refs @@ -255,12 +251,13 @@ int refname_is_safe(const char *refname) * does not exist, emit a warning and return false. */ int ref_resolves_to_object(const char *refname, + struct repository *repo, const struct object_id *oid, unsigned int flags) { if (flags & REF_ISBROKEN) return 0; - if (!has_object_file(oid)) { + if (!repo_has_object_file(repo, oid)) { error(_("%s does not point to a valid object!"), refname); return 0; } @@ -294,20 +291,16 @@ struct ref_filter { void *cb_data; }; -int refs_read_ref_full(struct ref_store *refs, const char *refname, - int resolve_flags, struct object_id *oid, int *flags) +int read_ref_full(const char *refname, int resolve_flags, struct object_id *oid, int *flags) { - if (refs_resolve_ref_unsafe(refs, refname, resolve_flags, oid, flags)) + struct ref_store *refs = get_main_ref_store(the_repository); + + if (refs_resolve_ref_unsafe(refs, refname, resolve_flags, + oid, flags)) return 0; return -1; } -int read_ref_full(const char *refname, int resolve_flags, struct object_id *oid, int *flags) -{ - return refs_read_ref_full(get_main_ref_store(the_repository), refname, - resolve_flags, oid, flags); -} - int read_ref(const char *refname, struct object_id *oid) { return read_ref_full(refname, RESOLVE_REF_READING, oid, NULL); @@ -315,7 +308,8 @@ int read_ref(const char *refname, struct object_id *oid) int refs_ref_exists(struct ref_store *refs, const char *refname) { - return !!refs_resolve_ref_unsafe(refs, refname, RESOLVE_REF_READING, NULL, NULL); + return !!refs_resolve_ref_unsafe(refs, refname, RESOLVE_REF_READING, + NULL, NULL); } int ref_exists(const char *refname) @@ -658,12 +652,13 @@ int expand_ref(struct repository *repo, const char *str, int len, struct object_id oid_from_ref; struct object_id *this_result; int flag; + struct ref_store *refs = get_main_ref_store(repo); this_result = refs_found ? &oid_from_ref : oid; strbuf_reset(&fullref); strbuf_addf(&fullref, *p, len, str); - r = refs_resolve_ref_unsafe(get_main_ref_store(repo), - fullref.buf, RESOLVE_REF_READING, + r = refs_resolve_ref_unsafe(refs, fullref.buf, + RESOLVE_REF_READING, this_result, &flag); if (r) { if (!refs_found++) @@ -698,7 +693,7 @@ int repo_dwim_log(struct repository *r, const char *str, int len, strbuf_addf(&path, *p, len, str); ref = refs_resolve_ref_unsafe(refs, path.buf, RESOLVE_REF_READING, - &hash, NULL); + oid ? &hash : NULL, NULL); if (!ref) continue; if (refs_reflog_exists(refs, path.buf)) @@ -710,7 +705,8 @@ int repo_dwim_log(struct repository *r, const char *str, int len, continue; if (!logs_found++) { *log = xstrdup(it); - oidcpy(oid, &hash); + if (oid) + oidcpy(oid, &hash); } if (!warn_ambiguous_refs) break; @@ -1080,9 +1076,10 @@ int ref_transaction_update(struct ref_transaction *transaction, { assert(err); - if ((new_oid && !is_null_oid(new_oid)) ? - check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) : - !refname_is_safe(refname)) { + if (!(flags & REF_SKIP_REFNAME_VERIFICATION) && + ((new_oid && !is_null_oid(new_oid)) ? + 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; @@ -1091,6 +1088,13 @@ int ref_transaction_update(struct ref_transaction *transaction, if (flags & ~REF_TRANSACTION_UPDATE_ALLOWED_FLAGS) BUG("illegal flags 0x%x passed to ref_transaction_update()", flags); + /* + * Clear flags outside the allowed set; this should be a noop because + * of the BUG() check above, but it works around a -Wnonnull warning + * with some versions of "gcc -O3". + */ + flags &= REF_TRANSACTION_UPDATE_ALLOWED_FLAGS; + flags |= (new_oid ? REF_HAVE_NEW : 0) | (old_oid ? REF_HAVE_OLD : 0); ref_transaction_add_update(transaction, refname, flags, @@ -1375,32 +1379,13 @@ const char *find_descendant_ref(const char *dirname, return NULL; } -int refs_rename_ref_available(struct ref_store *refs, - const char *old_refname, - const char *new_refname) -{ - struct string_list skip = STRING_LIST_INIT_NODUP; - struct strbuf err = STRBUF_INIT; - int ok; - - string_list_insert(&skip, old_refname); - ok = !refs_verify_refname_available(refs, new_refname, - NULL, &skip, &err); - if (!ok) - error("%s", err.buf); - - string_list_clear(&skip, 0); - strbuf_release(&err); - return ok; -} - int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data) { struct object_id oid; int flag; - if (!refs_read_ref_full(refs, "HEAD", RESOLVE_REF_READING, - &oid, &flag)) + if (refs_resolve_ref_unsafe(refs, "HEAD", RESOLVE_REF_READING, + &oid, &flag)) return fn("HEAD", &oid, flag, cb_data); return 0; @@ -1413,14 +1398,21 @@ int head_ref(each_ref_fn fn, void *cb_data) struct ref_iterator *refs_ref_iterator_begin( struct ref_store *refs, - const char *prefix, int trim, int flags) + const char *prefix, int trim, + enum do_for_each_ref_flags flags) { struct ref_iterator *iter; - if (ref_paranoia < 0) - ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0); - if (ref_paranoia) - flags |= DO_FOR_EACH_INCLUDE_BROKEN; + if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) { + static int ref_paranoia = -1; + + if (ref_paranoia < 0) + ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 1); + if (ref_paranoia) { + flags |= DO_FOR_EACH_INCLUDE_BROKEN; + flags |= DO_FOR_EACH_OMIT_DANGLING_SYMREFS; + } + } iter = refs->be->iterator_begin(refs, prefix, flags); @@ -1479,7 +1471,8 @@ static int do_for_each_ref_helper(struct repository *r, } static int do_for_each_ref(struct ref_store *refs, const char *prefix, - each_ref_fn fn, int trim, int flags, void *cb_data) + each_ref_fn fn, int trim, + enum do_for_each_ref_flags flags, void *cb_data) { struct ref_iterator *iter; struct do_for_each_ref_help hp = { fn, cb_data }; @@ -1514,25 +1507,16 @@ int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data) return refs_for_each_ref_in(get_main_ref_store(the_repository), prefix, fn, cb_data); } -int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken) +int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data) { - unsigned int flag = 0; - - if (broken) - flag = DO_FOR_EACH_INCLUDE_BROKEN; return do_for_each_ref(get_main_ref_store(the_repository), - prefix, fn, 0, flag, cb_data); + prefix, fn, 0, 0, cb_data); } int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix, - each_ref_fn fn, void *cb_data, - unsigned int broken) + each_ref_fn fn, void *cb_data) { - unsigned int flag = 0; - - if (broken) - flag = DO_FOR_EACH_INCLUDE_BROKEN; - return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data); + return do_for_each_ref(refs, prefix, fn, 0, 0, cb_data); } int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data) @@ -1624,8 +1608,7 @@ static void find_longest_prefixes(struct string_list *out, int for_each_fullref_in_prefixes(const char *namespace, const char **patterns, - each_ref_fn fn, void *cb_data, - unsigned int broken) + each_ref_fn fn, void *cb_data) { struct string_list prefixes = STRING_LIST_INIT_DUP; struct string_list_item *prefix; @@ -1640,7 +1623,7 @@ int for_each_fullref_in_prefixes(const char *namespace, for_each_string_list_item(prefix, &prefixes) { strbuf_addstr(&buf, prefix->string); - ret = for_each_fullref_in(buf.buf, fn, cb_data, broken); + ret = for_each_fullref_in(buf.buf, fn, cb_data); if (ret) break; strbuf_setlen(&buf, namespace_len); @@ -1653,7 +1636,8 @@ int for_each_fullref_in_prefixes(const char *namespace, static int refs_read_special_head(struct ref_store *ref_store, const char *refname, struct object_id *oid, - struct strbuf *referent, unsigned int *type) + struct strbuf *referent, unsigned int *type, + int *failure_errno) { struct strbuf full_path = STRBUF_INIT; struct strbuf content = STRBUF_INIT; @@ -1663,7 +1647,8 @@ static int refs_read_special_head(struct ref_store *ref_store, if (strbuf_read_file(&content, full_path.buf, 0) < 0) goto done; - result = parse_loose_ref_contents(content.buf, oid, referent, type); + result = parse_loose_ref_contents(content.buf, oid, referent, type, + failure_errno); done: strbuf_release(&full_path); @@ -1671,24 +1656,25 @@ done: return result; } -int refs_read_raw_ref(struct ref_store *ref_store, - const char *refname, struct object_id *oid, - struct strbuf *referent, unsigned int *type) +int refs_read_raw_ref(struct ref_store *ref_store, const char *refname, + struct object_id *oid, struct strbuf *referent, + unsigned int *type, int *failure_errno) { + assert(failure_errno); if (!strcmp(refname, "FETCH_HEAD") || !strcmp(refname, "MERGE_HEAD")) { return refs_read_special_head(ref_store, refname, oid, referent, - type); + type, failure_errno); } return ref_store->be->read_raw_ref(ref_store, refname, oid, referent, - type); + type, failure_errno); } -/* This function needs to return a meaningful errno on failure */ const char *refs_resolve_ref_unsafe(struct ref_store *refs, const char *refname, int resolve_flags, - struct object_id *oid, int *flags) + struct object_id *oid, + int *flags) { static struct strbuf sb_refname = STRBUF_INIT; struct object_id unused_oid; @@ -1704,10 +1690,8 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) || - !refname_is_safe(refname)) { - errno = EINVAL; + !refname_is_safe(refname)) return NULL; - } /* * dwim_ref() uses REF_ISBROKEN to distinguish between @@ -1722,9 +1706,10 @@ 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; + int failure_errno; - if (refs_read_raw_ref(refs, refname, - oid, &sb_refname, &read_flags)) { + if (refs_read_raw_ref(refs, refname, oid, &sb_refname, + &read_flags, &failure_errno)) { *flags |= read_flags; /* In reading mode, refs must eventually resolve */ @@ -1736,9 +1721,9 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, * may show errors besides ENOENT if there are * similarly-named refs. */ - if (errno != ENOENT && - errno != EISDIR && - errno != ENOTDIR) + if (failure_errno != ENOENT && + failure_errno != EISDIR && + failure_errno != ENOTDIR) return NULL; oidclr(oid); @@ -1764,16 +1749,13 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, } if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) || - !refname_is_safe(refname)) { - errno = EINVAL; + !refname_is_safe(refname)) return NULL; - } *flags |= REF_ISBROKEN | REF_BAD_NAME; } } - errno = ELOOP; return NULL; } @@ -1875,7 +1857,8 @@ static struct ref_store *lookup_ref_store_map(struct hashmap *map, * Create, record, and return a ref_store instance for the specified * gitdir. */ -static struct ref_store *ref_store_init(const char *gitdir, +static struct ref_store *ref_store_init(struct repository *repo, + const char *gitdir, unsigned int flags) { const char *be_name = "files"; @@ -1885,7 +1868,7 @@ static struct ref_store *ref_store_init(const char *gitdir, if (!be) BUG("reference backend %s is unknown", be_name); - refs = be->init(gitdir, flags); + refs = be->init(repo, gitdir, flags); return refs; } @@ -1897,7 +1880,7 @@ struct ref_store *get_main_ref_store(struct repository *r) if (!r->gitdir) BUG("attempting to get main_ref_store outside of repository"); - r->refs_private = ref_store_init(r->gitdir, REF_STORE_ALL_CAPS); + r->refs_private = ref_store_init(r, r->gitdir, REF_STORE_ALL_CAPS); r->refs_private = maybe_debug_wrap_ref_store(r->gitdir, r->refs_private); return r->refs_private; } @@ -1927,6 +1910,7 @@ struct ref_store *get_submodule_ref_store(const char *submodule) struct ref_store *refs; char *to_free = NULL; size_t len; + struct repository *subrepo; if (!submodule) return NULL; @@ -1952,8 +1936,19 @@ struct ref_store *get_submodule_ref_store(const char *submodule) if (submodule_to_gitdir(&submodule_sb, submodule)) goto done; - /* assume that add_submodule_odb() has been called */ - refs = ref_store_init(submodule_sb.buf, + subrepo = xmalloc(sizeof(*subrepo)); + /* + * NEEDSWORK: Make get_submodule_ref_store() work with arbitrary + * superprojects other than the_repository. This probably should be + * done by making it take a struct repository * parameter instead of a + * submodule path. + */ + if (repo_submodule_init(subrepo, the_repository, submodule, + null_oid())) { + free(subrepo); + goto done; + } + refs = ref_store_init(subrepo, submodule_sb.buf, REF_STORE_READ | REF_STORE_ODB); register_ref_store_map(&submodule_ref_stores, "submodule", refs, submodule); @@ -1979,10 +1974,12 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt) return refs; if (wt->id) - refs = ref_store_init(git_common_path("worktrees/%s", wt->id), + refs = ref_store_init(the_repository, + git_common_path("worktrees/%s", wt->id), REF_STORE_ALL_CAPS); else - refs = ref_store_init(get_git_common_dir(), + refs = ref_store_init(the_repository, + get_git_common_dir(), REF_STORE_ALL_CAPS); if (refs) @@ -1991,10 +1988,12 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt) return refs; } -void base_ref_store_init(struct ref_store *refs, - const struct ref_storage_be *be) +void base_ref_store_init(struct ref_store *refs, struct repository *repo, + const char *path, const struct ref_storage_be *be) { refs->be = be; + refs->repo = repo; + refs->gitdir = xstrdup(path); } /* backend functions */ @@ -2091,8 +2090,11 @@ static int run_transaction_hook(struct ref_transaction *transaction, update->refname); if (write_in_full(proc.in, buf.buf, buf.len) < 0) { - if (errno != EPIPE) + if (errno != EPIPE) { + /* Don't leak errno outside this API */ + errno = 0; ret = -1; + } break; } } @@ -2126,7 +2128,7 @@ int ref_transaction_prepare(struct ref_transaction *transaction, break; } - if (getenv(GIT_QUARANTINE_ENVIRONMENT)) { + if (refs->repo->objects->odb->disable_ref_updates) { strbuf_addstr(err, _("ref updates forbidden inside quarantine environment")); return -1; @@ -2227,6 +2229,13 @@ int refs_verify_refname_available(struct ref_store *refs, strbuf_grow(&dirname, strlen(refname) + 1); for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) { + /* + * Just saying "Is a directory" when we e.g. can't + * lock some multi-level ref isn't very informative, + * the user won't be told *what* is a directory, so + * let's not use strerror() below. + */ + int ignore_errno; /* Expand dirname to the new prefix, not including the trailing slash: */ strbuf_add(&dirname, refname + dirname.len, slash - refname - dirname.len); @@ -2238,7 +2247,8 @@ int refs_verify_refname_available(struct ref_store *refs, if (skip && string_list_has_string(skip, dirname.buf)) continue; - if (!refs_read_raw_ref(refs, dirname.buf, &oid, &referent, &type)) { + if (!refs_read_raw_ref(refs, dirname.buf, &oid, &referent, + &type, &ignore_errno)) { strbuf_addf(err, _("'%s' exists; cannot create '%s'"), dirname.buf, refname); goto cleanup; @@ -2347,16 +2357,15 @@ int reflog_exists(const char *refname) } int refs_create_reflog(struct ref_store *refs, const char *refname, - int force_create, struct strbuf *err) + struct strbuf *err) { - return refs->be->create_reflog(refs, refname, force_create, err); + return refs->be->create_reflog(refs, refname, err); } -int safe_create_reflog(const char *refname, int force_create, - struct strbuf *err) +int safe_create_reflog(const char *refname, struct strbuf *err) { return refs_create_reflog(get_main_ref_store(the_repository), refname, - force_create, err); + err); } int refs_delete_reflog(struct ref_store *refs, const char *refname) @@ -2370,19 +2379,19 @@ int delete_reflog(const char *refname) } int refs_reflog_expire(struct ref_store *refs, - const char *refname, const struct object_id *oid, + const char *refname, unsigned int flags, reflog_expiry_prepare_fn prepare_fn, reflog_expiry_should_prune_fn should_prune_fn, reflog_expiry_cleanup_fn cleanup_fn, void *policy_cb_data) { - return refs->be->reflog_expire(refs, refname, oid, flags, + return refs->be->reflog_expire(refs, refname, flags, prepare_fn, should_prune_fn, cleanup_fn, policy_cb_data); } -int reflog_expire(const char *refname, const struct object_id *oid, +int reflog_expire(const char *refname, unsigned int flags, reflog_expiry_prepare_fn prepare_fn, reflog_expiry_should_prune_fn should_prune_fn, @@ -2390,7 +2399,7 @@ int reflog_expire(const char *refname, const struct object_id *oid, void *policy_cb_data) { return refs_reflog_expire(get_main_ref_store(the_repository), - refname, oid, flags, + refname, flags, prepare_fn, should_prune_fn, cleanup_fn, policy_cb_data); } |