diff options
author | Daniel Barkalow <barkalow@iabervon.org> | 2008-03-17 22:05:23 -0400 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2008-03-26 00:10:55 -0700 |
commit | c091b3d415f95d3e4e62acddb084e211af46acbf (patch) | |
tree | d7370870e12f5dc2b4bf2a35858723c0d0c9c030 /remote.c | |
parent | 71a5099b647267d509e43f2c41483ca79af49d9f (diff) | |
download | git-c091b3d415f95d3e4e62acddb084e211af46acbf.tar.gz |
Tighten refspec processing
This changes the pattern matching code to not store the required final
/ before the *, and then to require each side to be a valid ref (or
empty). In particular, any refspec that looks like it should be a
pattern but doesn't quite meet the requirements will be found to be
invalid as a fallback non-pattern.
This was cherry picked from commit ef00d15 (Tighten refspec processing,
2008-03-17), and two fix-up commits 46220ca (remote.c: Fix overtight
refspec validation, 2008-03-20) and 7d19da4 (refspec: allow colon-less
wildcard "refs/category/*", 2008-03-25) squashed in.
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'remote.c')
-rw-r--r-- | remote.c | 176 |
1 files changed, 137 insertions, 39 deletions
@@ -305,42 +305,127 @@ static void read_config(void) git_config(handle_config); } -struct refspec *parse_ref_spec(int nr_refspec, const char **refspec) +static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch) { int i; + int st; struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec); + for (i = 0; i < nr_refspec; i++) { - const char *sp, *ep, *gp; - sp = refspec[i]; - if (*sp == '+') { + size_t llen, rlen; + int is_glob; + const char *lhs, *rhs; + + llen = rlen = is_glob = 0; + + lhs = refspec[i]; + if (*lhs == '+') { rs[i].force = 1; - sp++; + lhs++; + } + + rhs = strrchr(lhs, ':'); + if (rhs) { + rhs++; + rlen = strlen(rhs); + is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*")); + if (is_glob) + rlen -= 2; + rs[i].dst = xstrndup(rhs, rlen); } - gp = strchr(sp, '*'); - ep = strchr(sp, ':'); - if (gp && ep && gp > ep) - gp = NULL; - if (ep) { - if (ep[1]) { - const char *glob = strchr(ep + 1, '*'); - if (!glob) - gp = NULL; - if (gp) - rs[i].dst = xstrndup(ep + 1, - glob - ep - 1); - else - rs[i].dst = xstrdup(ep + 1); + + llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); + if (2 <= llen && !memcmp(lhs + llen - 2, "/*", 2)) { + if ((rhs && !is_glob) || (!rhs && fetch)) + goto invalid; + is_glob = 1; + llen -= 2; + } else if (rhs && is_glob) { + goto invalid; + } + + rs[i].pattern = is_glob; + rs[i].src = xstrndup(lhs, llen); + + if (fetch) { + /* + * LHS + * - empty is allowed; it means HEAD. + * - otherwise it must be a valid looking ref. + */ + if (!*rs[i].src) + ; /* empty is ok */ + else { + st = check_ref_format(rs[i].src); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + goto invalid; + } + /* + * RHS + * - missing is ok, and is same as empty. + * - empty is ok; it means not to store. + * - otherwise it must be a valid looking ref. + */ + if (!rs[i].dst) { + ; /* ok */ + } else if (!*rs[i].dst) { + ; /* ok */ + } else { + st = check_ref_format(rs[i].dst); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + goto invalid; } } else { - ep = sp + strlen(sp); - } - if (gp) { - rs[i].pattern = 1; - ep = gp; + /* + * LHS + * - empty is allowed; it means delete. + * - when wildcarded, it must be a valid looking ref. + * - otherwise, it must be an extended SHA-1, but + * there is no existing way to validate this. + */ + if (!*rs[i].src) + ; /* empty is ok */ + else if (is_glob) { + st = check_ref_format(rs[i].src); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + goto invalid; + } + else + ; /* anything goes, for now */ + /* + * RHS + * - missing is allowed, but LHS then must be a + * valid looking ref. + * - empty is not allowed. + * - otherwise it must be a valid looking ref. + */ + if (!rs[i].dst) { + st = check_ref_format(rs[i].src); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + goto invalid; + } else if (!*rs[i].dst) { + goto invalid; + } else { + st = check_ref_format(rs[i].dst); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + goto invalid; + } } - rs[i].src = xstrndup(sp, ep - sp); } return rs; + + invalid: + die("Invalid refspec '%s'", refspec[i]); +} + +struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec) +{ + return parse_refspec_internal(nr_refspec, refspec, 1); +} + +struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) +{ + return parse_refspec_internal(nr_refspec, refspec, 0); } static int valid_remote_nick(const char *name) @@ -371,8 +456,8 @@ struct remote *remote_get(const char *name) add_url(ret, name); if (!ret->url) return NULL; - ret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec); - ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec); + ret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec); + ret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec); return ret; } @@ -385,11 +470,11 @@ int for_each_remote(each_remote_fn fn, void *priv) if (!r) continue; if (!r->fetch) - r->fetch = parse_ref_spec(r->fetch_refspec_nr, - r->fetch_refspec); + r->fetch = parse_fetch_refspec(r->fetch_refspec_nr, + r->fetch_refspec); if (!r->push) - r->push = parse_ref_spec(r->push_refspec_nr, - r->push_refspec); + r->push = parse_push_refspec(r->push_refspec_nr, + r->push_refspec); result = fn(r, priv); } return result; @@ -455,7 +540,8 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec) if (!fetch->dst) continue; if (fetch->pattern) { - if (!prefixcmp(needle, key)) { + if (!prefixcmp(needle, key) && + needle[strlen(key)] == '/') { *result = xmalloc(strlen(value) + strlen(needle) - strlen(key) + 1); @@ -695,7 +781,9 @@ static const struct refspec *check_pattern_match(const struct refspec *rs, { int i; for (i = 0; i < rs_nr; i++) { - if (rs[i].pattern && !prefixcmp(src->name, rs[i].src)) + if (rs[i].pattern && + !prefixcmp(src->name, rs[i].src) && + src->name[strlen(rs[i].src)] == '/') return rs + i; } return NULL; @@ -710,7 +798,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, int nr_refspec, const char **refspec, int flags) { struct refspec *rs = - parse_ref_spec(nr_refspec, (const char **) refspec); + parse_push_refspec(nr_refspec, (const char **) refspec); int send_all = flags & MATCH_REFS_ALL; int send_mirror = flags & MATCH_REFS_MIRROR; @@ -894,7 +982,7 @@ int get_fetch_map(const struct ref *remote_refs, struct ref ***tail, int missing_ok) { - struct ref *ref_map, *rm; + struct ref *ref_map, **rmp; if (refspec->pattern) { ref_map = get_expanded_map(remote_refs, refspec); @@ -911,10 +999,20 @@ int get_fetch_map(const struct ref *remote_refs, } } - for (rm = ref_map; rm; rm = rm->next) { - if (rm->peer_ref && check_ref_format(rm->peer_ref->name + 5)) - die("* refusing to create funny ref '%s' locally", - rm->peer_ref->name); + for (rmp = &ref_map; *rmp; ) { + if ((*rmp)->peer_ref) { + int st = check_ref_format((*rmp)->peer_ref->name + 5); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) { + struct ref *ignore = *rmp; + error("* Ignoring funny ref '%s' locally", + (*rmp)->peer_ref->name); + *rmp = (*rmp)->next; + free(ignore->peer_ref); + free(ignore); + continue; + } + } + rmp = &((*rmp)->next); } if (ref_map) |