X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=refs.c;h=5789152743ffbf0ac0f9a0270e2d689349cf7682;hb=39950fef8bb45e944655e48393ee04c0b33211f5;hp=b0e6ece6f43437bb7d59490d64802baa3b277090;hpb=1c4f47690074de3c27c1a2124779bfe2898f295d;p=thirdparty%2Fgit.git diff --git a/refs.c b/refs.c index b0e6ece6f4..5789152743 100644 --- a/refs.c +++ b/refs.c @@ -120,17 +120,19 @@ 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; - 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(strlen(rest)); + result = !normalize_path_copy(buf, rest); free(buf); return result; } @@ -1080,3 +1082,152 @@ int rename_ref_available(const char *oldname, const char *newname) strbuf_release(&err); return ret; } + +int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data) +{ + struct object_id oid; + int flag; + + if (submodule) { + if (resolve_gitlink_ref(submodule, "HEAD", oid.hash) == 0) + return fn("HEAD", &oid, 0, cb_data); + + return 0; + } + + if (!read_ref_full("HEAD", RESOLVE_REF_READING, oid.hash, &flag)) + return fn("HEAD", &oid, flag, cb_data); + + return 0; +} + +int head_ref(each_ref_fn fn, void *cb_data) +{ + return head_ref_submodule(NULL, 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); +} + +int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data) +{ + return do_for_each_ref(submodule, "", fn, 0, 0, cb_data); +} + +int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data) +{ + return do_for_each_ref(NULL, prefix, fn, strlen(prefix), 0, cb_data); +} + +int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken) +{ + unsigned int flag = 0; + + if (broken) + flag = DO_FOR_EACH_INCLUDE_BROKEN; + return do_for_each_ref(NULL, prefix, fn, 0, flag, cb_data); +} + +int for_each_ref_in_submodule(const char *submodule, const char *prefix, + each_ref_fn fn, void *cb_data) +{ + return do_for_each_ref(submodule, prefix, fn, strlen(prefix), 0, cb_data); +} + +int for_each_replace_ref(each_ref_fn fn, void *cb_data) +{ + return do_for_each_ref(NULL, git_replace_ref_base, fn, + strlen(git_replace_ref_base), 0, cb_data); +} + +int for_each_namespaced_ref(each_ref_fn fn, void *cb_data) +{ + struct strbuf buf = STRBUF_INIT; + int ret; + strbuf_addf(&buf, "%srefs/", get_git_namespace()); + ret = do_for_each_ref(NULL, buf.buf, fn, 0, 0, cb_data); + strbuf_release(&buf); + return ret; +} + +int for_each_rawref(each_ref_fn fn, void *cb_data) +{ + return do_for_each_ref(NULL, "", fn, 0, + DO_FOR_EACH_INCLUDE_BROKEN, cb_data); +} + +/* This function needs to return a meaningful errno on failure */ +const char *resolve_ref_unsafe(const char *refname, int resolve_flags, + unsigned char *sha1, int *flags) +{ + static struct strbuf sb_refname = STRBUF_INIT; + int unused_flags; + int symref_count; + + if (!flags) + flags = &unused_flags; + + *flags = 0; + + if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { + if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) || + !refname_is_safe(refname)) { + errno = EINVAL; + return NULL; + } + + /* + * dwim_ref() uses REF_ISBROKEN to distinguish between + * missing refs and refs that were present but invalid, + * to complain about the latter to stderr. + * + * We don't know whether the ref exists, so don't set + * REF_ISBROKEN yet. + */ + *flags |= REF_BAD_NAME; + } + + for (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) { + unsigned int read_flags = 0; + + if (read_raw_ref(refname, sha1, &sb_refname, &read_flags)) { + *flags |= read_flags; + if (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING)) + return NULL; + hashclr(sha1); + if (*flags & REF_BAD_NAME) + *flags |= REF_ISBROKEN; + return refname; + } + + *flags |= read_flags; + + if (!(read_flags & REF_ISSYMREF)) { + if (*flags & REF_BAD_NAME) { + hashclr(sha1); + *flags |= REF_ISBROKEN; + } + return refname; + } + + refname = sb_refname.buf; + if (resolve_flags & RESOLVE_REF_NO_RECURSE) { + hashclr(sha1); + return refname; + } + if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { + if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) || + !refname_is_safe(refname)) { + errno = EINVAL; + return NULL; + } + + *flags |= REF_ISBROKEN | REF_BAD_NAME; + } + } + + errno = ELOOP; + return NULL; +}