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)
int format_tracking_info(struct branch *branch, struct strbuf *sb)
{
int num_ours, num_theirs;
- const char *base, *remote_msg;
+ const char *base;
if (!stat_tracking_info(branch, &num_ours, &num_theirs))
return 0;
base = branch->merge[0]->dst;
if (!prefixcmp(base, "refs/remotes/")) {
- remote_msg = " remote";
base += strlen("refs/remotes/");
- } else {
- remote_msg = "";
}
if (!num_theirs)
- strbuf_addf(sb, "Your branch is ahead of the tracked%s branch '%s' "
+ strbuf_addf(sb, "Your branch is ahead of '%s' "
"by %d commit%s.\n",
- remote_msg, base,
- num_ours, (num_ours == 1) ? "" : "s");
+ base, num_ours, (num_ours == 1) ? "" : "s");
else if (!num_ours)
- strbuf_addf(sb, "Your branch is behind the tracked%s branch '%s' "
- "by %d commit%s,\n"
+ strbuf_addf(sb, "Your branch is behind '%s' "
+ "by %d commit%s, "
"and can be fast-forwarded.\n",
- remote_msg, base,
- num_theirs, (num_theirs == 1) ? "" : "s");
+ base, num_theirs, (num_theirs == 1) ? "" : "s");
else
- strbuf_addf(sb, "Your branch and the tracked%s branch '%s' "
- "have diverged,\nand respectively "
- "have %d and %d different commit(s) each.\n",
- remote_msg, base,
- num_ours, num_theirs);
+ strbuf_addf(sb, "Your branch and '%s' have diverged,\n"
+ "and have %d and %d different commit(s) each, "
+ "respectively.\n",
+ base, num_ours, num_theirs);
return 1;
}