if (!longest)
return url;
- ret = malloc(rewrite[longest_i]->baselen +
+ ret = xmalloc(rewrite[longest_i]->baselen +
(strlen(url) - longest->len) + 1);
strcpy(ret, rewrite[longest_i]->base);
strcpy(ret + rewrite[longest_i]->baselen, url + longest->len);
ret->name = xstrndup(name, len);
else
ret->name = xstrdup(name);
- refname = malloc(strlen(name) + strlen("refs/heads/") + 1);
+ refname = xmalloc(strlen(name) + strlen("refs/heads/") + 1);
strcpy(refname, "refs/heads/");
strcpy(refname + strlen("refs/heads/"), ret->name);
ret->refname = refname;
{
const char *slash = strchr(remote->name, '/');
char *frag;
- struct strbuf branch;
+ struct strbuf branch = STRBUF_INIT;
int n = slash ? slash - remote->name : 1000;
FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r");
char *s, *p;
* #branch specified. The "master" (or specified) branch is
* fetched and stored in the local branch of the same name.
*/
- strbuf_init(&branch, 0);
frag = strchr(p, '#');
if (frag) {
*(frag++) = '\0';
if (prefixcmp(key, "remote."))
return 0;
name = key + 7;
+ if (*name == '/') {
+ warning("Config remote shorthand cannot begin with '/': %s",
+ name);
+ return 0;
+ }
subkey = strrchr(name, '.');
if (!subkey)
return error("Config with no key for remote %s", name);
- if (*subkey == '/') {
- warning("Config remote shorthand cannot begin with '/': %s", name);
- return 0;
- }
remote = make_remote(name, subkey - name);
if (!strcmp(subkey, ".mirror"))
remote->mirror = git_config_bool(key, value);
alias_all_urls();
}
+/*
+ * We need to make sure the tracking branches are well formed, but a
+ * wildcard refspec in "struct refspec" must have a trailing slash. We
+ * temporarily drop the trailing '/' while calling check_ref_format(),
+ * and put it back. The caller knows that a CHECK_REF_FORMAT_ONELEVEL
+ * error return is Ok for a wildcard refspec.
+ */
+static int verify_refname(char *name, int is_glob)
+{
+ int result, len = -1;
+
+ if (is_glob) {
+ len = strlen(name);
+ assert(name[len - 1] == '/');
+ name[len - 1] = '\0';
+ }
+ result = check_ref_format(name);
+ if (is_glob)
+ name[len - 1] = '/';
+ return result;
+}
+
+/*
+ * This function frees a refspec array.
+ * Warning: code paths should be checked to ensure that the src
+ * and dst pointers are always freeable pointers as well
+ * as the refspec pointer itself.
+ */
+static void free_refspecs(struct refspec *refspec, int nr_refspec)
+{
+ int i;
+
+ if (!refspec)
+ return;
+
+ for (i = 0; i < nr_refspec; i++) {
+ free(refspec[i].src);
+ free(refspec[i].dst);
+ }
+ free(refspec);
+}
+
static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
{
int i;
struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
for (i = 0; i < nr_refspec; i++) {
- size_t llen, rlen;
+ size_t llen;
int is_glob;
const char *lhs, *rhs;
- llen = rlen = is_glob = 0;
+ llen = is_glob = 0;
lhs = refspec[i];
if (*lhs == '+') {
}
if (rhs) {
- rhs++;
- rlen = strlen(rhs);
+ size_t rlen = strlen(++rhs);
is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*"));
- if (is_glob)
- rlen -= 2;
- rs[i].dst = xstrndup(rhs, rlen);
+ rs[i].dst = xstrndup(rhs, rlen - is_glob);
}
llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
if ((rhs && !is_glob) || (!rhs && fetch))
goto invalid;
is_glob = 1;
- llen -= 2;
+ llen--;
} else if (rhs && is_glob) {
goto invalid;
}
if (!*rs[i].src)
; /* empty is ok */
else {
- st = check_ref_format(rs[i].src);
+ st = verify_refname(rs[i].src, is_glob);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
goto invalid;
}
} else if (!*rs[i].dst) {
; /* ok */
} else {
- st = check_ref_format(rs[i].dst);
+ st = verify_refname(rs[i].dst, is_glob);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
goto invalid;
}
if (!*rs[i].src)
; /* empty is ok */
else if (is_glob) {
- st = check_ref_format(rs[i].src);
+ st = verify_refname(rs[i].src, is_glob);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
goto invalid;
}
* - otherwise it must be a valid looking ref.
*/
if (!rs[i].dst) {
- st = check_ref_format(rs[i].src);
+ st = verify_refname(rs[i].src, is_glob);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
goto invalid;
} else if (!*rs[i].dst) {
goto invalid;
} else {
- st = check_ref_format(rs[i].dst);
+ st = verify_refname(rs[i].dst, is_glob);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
goto invalid;
}
invalid:
if (verify) {
- free(rs);
+ /*
+ * nr_refspec must be greater than zero and i must be valid
+ * since it is only possible to reach this point from within
+ * the for loop above.
+ */
+ free_refspecs(rs, i+1);
return NULL;
}
die("Invalid refspec '%s'", refspec[i]);
struct refspec *refspec;
refspec = parse_refspec_internal(1, fetch_refspec, 1, 1);
- if (refspec)
- free(refspec);
+ free_refspecs(refspec, 1);
return !!refspec;
}
return parse_refspec_internal(nr_refspec, refspec, 1, 0);
}
-struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
+static struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
{
return parse_refspec_internal(nr_refspec, refspec, 0, 0);
}
if (!fetch->dst)
continue;
if (fetch->pattern) {
- if (!prefixcmp(needle, key) &&
- needle[strlen(key)] == '/') {
+ if (!prefixcmp(needle, key)) {
*result = xmalloc(strlen(value) +
strlen(needle) -
strlen(key) + 1);
struct ref *alloc_ref(unsigned namelen)
{
- struct ref *ret = xmalloc(sizeof(struct ref) + namelen);
- memset(ret, 0, sizeof(struct ref) + namelen);
+ struct ref *ret = xcalloc(1, sizeof(struct ref) + namelen);
return ret;
}
return ret;
}
-void free_ref(struct ref *ref)
+static void free_ref(struct ref *ref)
{
if (!ref)
return;
continue;
}
- if (rs[i].pattern &&
- !prefixcmp(src->name, rs[i].src) &&
- src->name[strlen(rs[i].src)] == '/')
+ if (rs[i].pattern && !prefixcmp(src->name, rs[i].src))
return rs + i;
}
if (matching_refs != -1)