Browse Source

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.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Daniel Barkalow 17 years ago committed by Junio C Hamano
parent
commit
ef00d150e4
  1. 47
      remote.c

47
remote.c

@ -396,6 +396,7 @@ static void read_config(void)
struct refspec *parse_ref_spec(int nr_refspec, const char **refspec) struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
{ {
int i; int i;
int st;
struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec); struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
for (i = 0; i < nr_refspec; i++) { for (i = 0; i < nr_refspec; i++) {
const char *sp, *ep, *gp; const char *sp, *ep, *gp;
@ -404,13 +405,15 @@ struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
rs[i].force = 1; rs[i].force = 1;
sp++; sp++;
} }
gp = strchr(sp, '*'); gp = strstr(sp, "/*");
ep = strchr(sp, ':'); ep = strchr(sp, ':');
if (gp && ep && gp > ep) if (gp && ep && gp > ep)
gp = NULL; gp = NULL;
if (ep) { if (ep) {
if (ep[1]) { if (ep[1]) {
const char *glob = strchr(ep + 1, '*'); const char *glob = strstr(ep + 1, "/*");
if (glob && glob[2])
glob = NULL;
if (!glob) if (!glob)
gp = NULL; gp = NULL;
if (gp) if (gp)
@ -422,11 +425,24 @@ struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
} else { } else {
ep = sp + strlen(sp); ep = sp + strlen(sp);
} }
if (gp && gp + 2 != ep)
gp = NULL;
if (gp) { if (gp) {
rs[i].pattern = 1; rs[i].pattern = 1;
ep = gp; ep = gp;
} }
rs[i].src = xstrndup(sp, ep - sp); rs[i].src = xstrndup(sp, ep - sp);

if (*rs[i].src) {
st = check_ref_format(rs[i].src);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
die("Invalid refspec '%s'", refspec[i]);
}
if (rs[i].dst && *rs[i].dst) {
st = check_ref_format(rs[i].dst);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
die("Invalid refspec '%s'", refspec[i]);
}
} }
return rs; return rs;
} }
@ -543,7 +559,8 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
if (!fetch->dst) if (!fetch->dst)
continue; continue;
if (fetch->pattern) { if (fetch->pattern) {
if (!prefixcmp(needle, key)) { if (!prefixcmp(needle, key) &&
needle[strlen(key)] == '/') {
*result = xmalloc(strlen(value) + *result = xmalloc(strlen(value) +
strlen(needle) - strlen(needle) -
strlen(key) + 1); strlen(key) + 1);
@ -790,7 +807,9 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
{ {
int i; int i;
for (i = 0; i < rs_nr; 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 rs + i;
} }
return NULL; return NULL;
@ -989,7 +1008,7 @@ int get_fetch_map(const struct ref *remote_refs,
struct ref ***tail, struct ref ***tail,
int missing_ok) int missing_ok)
{ {
struct ref *ref_map, *rm; struct ref *ref_map, **rmp;


if (refspec->pattern) { if (refspec->pattern) {
ref_map = get_expanded_map(remote_refs, refspec); ref_map = get_expanded_map(remote_refs, refspec);
@ -1006,10 +1025,20 @@ int get_fetch_map(const struct ref *remote_refs,
} }
} }


for (rm = ref_map; rm; rm = rm->next) { for (rmp = &ref_map; *rmp; ) {
if (rm->peer_ref && check_ref_format(rm->peer_ref->name + 5)) if ((*rmp)->peer_ref) {
die("* refusing to create funny ref '%s' locally", int st = check_ref_format((*rmp)->peer_ref->name + 5);
rm->peer_ref->name); 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) if (ref_map)

Loading…
Cancel
Save