{"thread":{"id":"18167","subject":"[PATCH 5/5] Support '*' in the middle of a refspec","startedAt":"2009-03-06T04:56:25Z","lastAt":"2009-03-07T06:11:39Z","messageCount":2,"participants":["Daniel Barkalow"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"107145","messageId":"alpine.LNX.1.00.0903052356010.19665@iabervon.org","threadId":"18167","inReplyTo":null,"subject":"[PATCH 5/5] Support '*' in the middle of a refspec","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2009-03-06T04:56:25Z","receivedAt":"2009-03-06T04:56:25Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"In order to keep the requirements strict, each * has to be a full path\ncomponent, and there may only be one * per side. This requirement is\nenforced entirely by check_ref_format(); the matching implementation\nwill substitute the whatever matches the * in the lhs for the * in the\nrhs.\n\nSigned-off-by: Daniel Barkalow <barkalow@iabervon.org>\n---\n refs.c             |   11 +++++++----\n remote.c           |   27 ++++++++++++++++++---------\n t/t5511-refspec.sh |   12 ++++++++++++\n 3 files changed, 37 insertions(+), 13 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex a50ba79..fef7c9f 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -694,6 +694,7 @@ static inline int bad_ref_char(int ch)\n int check_ref_format(const char *ref)\n {\n \tint ch, level, bad_type;\n+\tint ret = CHECK_REF_FORMAT_OK;\n \tconst char *cp = ref;\n \n \tlevel = 0;\n@@ -709,9 +710,11 @@ int check_ref_format(const char *ref)\n \t\t\treturn CHECK_REF_FORMAT_ERROR;\n \t\tbad_type = bad_ref_char(ch);\n \t\tif (bad_type) {\n-\t\t\treturn (bad_type == 2 && !*cp)\n-\t\t\t\t? CHECK_REF_FORMAT_WILDCARD\n-\t\t\t\t: CHECK_REF_FORMAT_ERROR;\n+\t\t\tif (bad_type == 2 && (!*cp || *cp == '/') &&\n+\t\t\t    ret == CHECK_REF_FORMAT_OK)\n+\t\t\t\tret = CHECK_REF_FORMAT_WILDCARD;\n+\t\t\telse\n+\t\t\t\treturn CHECK_REF_FORMAT_ERROR;\n \t\t}\n \n \t\t/* scan the rest of the path component */\n@@ -729,7 +732,7 @@ int check_ref_format(const char *ref)\n \t\tif (!ch) {\n \t\t\tif (level < 2)\n \t\t\t\treturn CHECK_REF_FORMAT_ONELEVEL;\n-\t\t\treturn CHECK_REF_FORMAT_OK;\n+\t\t\treturn ret;\n \t\t}\n \t}\n }\ndiff --git a/remote.c b/remote.c\nindex d0ce4c6..41005cf 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -511,12 +511,12 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp\n \n \t\tif (rhs) {\n \t\t\tsize_t rlen = strlen(++rhs);\n-\t\t\tis_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, \"/*\"));\n+\t\t\tis_glob = (1 <= rlen && strchr(rhs, '*'));\n \t\t\trs[i].dst = xstrndup(rhs, rlen);\n \t\t}\n \n \t\tllen = (rhs ? (rhs - lhs - 1) : strlen(lhs));\n-\t\tif (2 <= llen && !memcmp(lhs + llen - 2, \"/*\", 2)) {\n+\t\tif (1 <= llen && memchr(lhs, '*', llen)) {\n \t\t\tif ((rhs && !is_glob) || (!rhs && fetch))\n \t\t\t\tgoto invalid;\n \t\t\tis_glob = 1;\n@@ -716,15 +716,24 @@ int remote_has_url(struct remote *remote, const char *url)\n static int name_fits_pattern(const char *key, const char *name,\n \t\t\t     const char *value, char **result)\n {\n-\tsize_t klen = strchr(key, '*') - key;\n-\tint ret = !strncmp(name, key, klen);\n+\tconst char *keystar = strchr(key, '*');\n+\tsize_t klen = keystar - key;\n+\tsize_t ksuffixlen = strlen(keystar + 1);\n+\tsize_t namelen = strlen(name);\n+\tint ret = !strncmp(name, key, klen) && namelen >= klen + ksuffixlen &&\n+\t\t!memcmp(name + namelen - ksuffixlen, keystar + 1, ksuffixlen);\n \tif (ret && value) {\n-\t\tsize_t vlen = strchr(value, '*') - value;\n-\t\t*result = xmalloc(vlen +\n+\t\tconst char *valuestar = strchr(value, '*');\n+\t\tsize_t vlen = valuestar - value;\n+\t\tsize_t vsuffixlen = strlen(valuestar + 1);\n+\t\t*result = xmalloc(vlen + vsuffixlen +\n \t\t\t\t  strlen(name) -\n-\t\t\t\t  klen + 1);\n-\t\tstrcpy(*result, value);\n-\t\tstrcpy(*result + vlen, name + klen);\n+\t\t\t\t  klen - ksuffixlen + 1);\n+\t\tstrncpy(*result, value, vlen);\n+\t\tstrncpy(*result + vlen,\n+\t\t\tname + klen, namelen - klen - ksuffixlen);\n+\t\tstrcpy(*result + vlen + namelen - klen - ksuffixlen,\n+\t\t       valuestar + 1);\n \t}\n \treturn ret;\n }\ndiff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh\nindex 22ba380..c289322 100755\n--- a/t/t5511-refspec.sh\n+++ b/t/t5511-refspec.sh\n@@ -72,4 +72,16 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me'\n test_refspec push ':refs/remotes/frotz/delete me'\t\tinvalid\n test_refspec fetch ':refs/remotes/frotz/HEAD to me'\t\tinvalid\n \n+test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid\n+test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid\n+\n+test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid\n+test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid\n+\n+test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid\n+test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid\n+\n+test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*'\n+test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*'\n+\n test_done\n-- \n1.6.1.286.gd33a4.dirty\n"},{"id":"107273","messageId":"alpine.LNX.1.00.0903070109590.19665@iabervon.org","threadId":"18167","inReplyTo":"alpine.LNX.1.00.0903052356010.19665@iabervon.org","subject":"[PATCH v2 5/5] Support '*' in the middle of a refspec","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2009-03-07T06:11:39Z","receivedAt":"2009-03-07T06:11:39Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"In order to keep the requirements strict, each * has to be a full path\ncomponent, and there may only be one * per side. This requirement is\nenforced entirely by check_ref_format(); the matching implementation\nwill substitute the whatever matches the * in the lhs for the * in the\nrhs.\n\nSigned-off-by: Daniel Barkalow <barkalow@iabervon.org>\n---\nRebased on the new version of the earlier patches\n\n refs.c             |   11 +++++++----\n remote.c           |   24 +++++++++++++++++-------\n t/t5511-refspec.sh |   12 ++++++++++++\n 3 files changed, 36 insertions(+), 11 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex a50ba79..fef7c9f 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -694,6 +694,7 @@ static inline int bad_ref_char(int ch)\n int check_ref_format(const char *ref)\n {\n \tint ch, level, bad_type;\n+\tint ret = CHECK_REF_FORMAT_OK;\n \tconst char *cp = ref;\n \n \tlevel = 0;\n@@ -709,9 +710,11 @@ int check_ref_format(const char *ref)\n \t\t\treturn CHECK_REF_FORMAT_ERROR;\n \t\tbad_type = bad_ref_char(ch);\n \t\tif (bad_type) {\n-\t\t\treturn (bad_type == 2 && !*cp)\n-\t\t\t\t? CHECK_REF_FORMAT_WILDCARD\n-\t\t\t\t: CHECK_REF_FORMAT_ERROR;\n+\t\t\tif (bad_type == 2 && (!*cp || *cp == '/') &&\n+\t\t\t    ret == CHECK_REF_FORMAT_OK)\n+\t\t\t\tret = CHECK_REF_FORMAT_WILDCARD;\n+\t\t\telse\n+\t\t\t\treturn CHECK_REF_FORMAT_ERROR;\n \t\t}\n \n \t\t/* scan the rest of the path component */\n@@ -729,7 +732,7 @@ int check_ref_format(const char *ref)\n \t\tif (!ch) {\n \t\t\tif (level < 2)\n \t\t\t\treturn CHECK_REF_FORMAT_ONELEVEL;\n-\t\t\treturn CHECK_REF_FORMAT_OK;\n+\t\t\treturn ret;\n \t\t}\n \t}\n }\ndiff --git a/remote.c b/remote.c\nindex d596a48..90203e2 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -511,12 +511,12 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp\n \n \t\tif (rhs) {\n \t\t\tsize_t rlen = strlen(++rhs);\n-\t\t\tis_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, \"/*\"));\n+\t\t\tis_glob = (1 <= rlen && strchr(rhs, '*'));\n \t\t\trs[i].dst = xstrndup(rhs, rlen);\n \t\t}\n \n \t\tllen = (rhs ? (rhs - lhs - 1) : strlen(lhs));\n-\t\tif (2 <= llen && !memcmp(lhs + llen - 2, \"/*\", 2)) {\n+\t\tif (1 <= llen && memchr(lhs, '*', llen)) {\n \t\t\tif ((rhs && !is_glob) || (!rhs && fetch))\n \t\t\t\tgoto invalid;\n \t\t\tis_glob = 1;\n@@ -718,22 +718,32 @@ static int match_name_with_pattern(const char *key, const char *name,\n {\n \tconst char *kstar = strchr(key, '*');\n \tsize_t klen;\n+\tsize_t ksuffixlen;\n+\tsize_t namelen;\n \tint ret;\n \tif (!kstar)\n \t\tdie(\"Key '%s' of pattern had no '*'\", key);\n \tklen = kstar - key;\n-\tret = !strncmp(key, name, klen);\n+\tksuffixlen = strlen(kstar + 1);\n+\tnamelen = strlen(name);\n+\tret = !strncmp(name, key, klen) && namelen >= klen + ksuffixlen &&\n+\t\t!memcmp(name + namelen - ksuffixlen, kstar + 1, ksuffixlen);\n \tif (ret && value) {\n \t\tconst char *vstar = strchr(value, '*');\n \t\tsize_t vlen;\n+\t\tsize_t vsuffixlen;\n \t\tif (!vstar)\n \t\t\tdie(\"Value '%s' of pattern has no '*'\", value);\n \t\tvlen = vstar - value;\n-\t\t*result = xmalloc(vlen +\n+\t\tvsuffixlen = strlen(vstar + 1);\n+\t\t*result = xmalloc(vlen + vsuffixlen +\n \t\t\t\t  strlen(name) -\n-\t\t\t\t  klen + 1);\n-\t\tstrcpy(*result, value);\n-\t\tstrcpy(*result + vlen, name + klen);\n+\t\t\t\t  klen - ksuffixlen + 1);\n+\t\tstrncpy(*result, value, vlen);\n+\t\tstrncpy(*result + vlen,\n+\t\t\tname + klen, namelen - klen - ksuffixlen);\n+\t\tstrcpy(*result + vlen + namelen - klen - ksuffixlen,\n+\t\t       vstar + 1);\n \t}\n \treturn ret;\n }\ndiff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh\nindex 22ba380..c289322 100755\n--- a/t/t5511-refspec.sh\n+++ b/t/t5511-refspec.sh\n@@ -72,4 +72,16 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me'\n test_refspec push ':refs/remotes/frotz/delete me'\t\tinvalid\n test_refspec fetch ':refs/remotes/frotz/HEAD to me'\t\tinvalid\n \n+test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid\n+test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid\n+\n+test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid\n+test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid\n+\n+test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid\n+test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid\n+\n+test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*'\n+test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*'\n+\n test_done\n-- \n1.6.1.286.gd33a4.dirty\n"}]}