summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2015-05-14 17:55:30 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2015-05-14 17:55:30 +0200
commit521a8da64c1e84c6a2999d71ad53ee24cdd4a1a1 (patch)
tree624458a9402198e754bec4bea40f56e2f592437b
parent542a7de0cdbed72f04a30db6f3ed1352b2169381 (diff)
downloadlibgit2-cmn/forbid-mutiurl.tar.gz
remote: refuse to load multi-url remotescmn/forbid-mutiurl
A remote can have more than a single entry in url or pushurl. Git uses this to perform multiple fetches or pushes, which can be useful for redundancy, but we currently cannot handle this. What we would do is fetch from or push to the last of the urls (as we consider them single-value fields), which would at best be confusing, but would also break the user's expectations. in order to avoid this, check whether the remote we're trying to lookup has mutliple urls and refuse to load it.
-rw-r--r--src/remote.c58
1 files changed, 47 insertions, 11 deletions
diff --git a/src/remote.c b/src/remote.c
index 44885bd17..1de5af4ab 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -408,14 +408,42 @@ static int get_optional_config(
return error;
}
+struct url_cb_data {
+ char *val;
+ int nurls;
+ bool fetch;
+};
+
+static int url_cb(const git_config_entry *entry, void *payload)
+{
+ struct url_cb_data *data = payload;
+
+ if (data->nurls > 0) {
+ giterr_set(GITERR_NET, "remotes with more than one url are not supported");
+ return -1;
+ }
+
+ if (!entry->value) {
+ giterr_set(GITERR_NET, "invalid value for %s", data->fetch ? "url" : "pushurl");
+ return -1;
+ }
+
+ data->val = git__strdup(entry->value);
+ GITERR_CHECK_ALLOC(data->val);
+ data->nurls++;
+
+ return 0;
+}
+
int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
{
git_remote *remote;
git_buf buf = GIT_BUF_INIT;
- const char *val;
+ char *val;
int error = 0;
git_config *config;
struct refspec_cb_data data = { NULL };
+ struct url_cb_data url_data;
bool optional_setting_found = false, found;
assert(out && repo && name);
@@ -443,26 +471,34 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
if ((error = git_buf_printf(&buf, "remote.%s.url", name)) < 0)
goto cleanup;
- if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
+ url_data.val = NULL;
+ url_data.nurls = 0;
+ url_data.fetch = true;
+ if ((error = get_optional_config(&found, config, &buf, url_cb, &url_data)) < 0)
goto cleanup;
+ val = url_data.val;
optional_setting_found |= found;
remote->repo = repo;
remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
- if (found && strlen(val) > 0) {
- remote->url = git__strdup(val);
- GITERR_CHECK_ALLOC(remote->url);
- }
+ if (found && strlen(val) > 0)
+ remote->url = val;
+ else
+ git__free(val);
val = NULL;
git_buf_clear(&buf);
git_buf_printf(&buf, "remote.%s.pushurl", name);
- if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
+ url_data.val = NULL;
+ url_data.nurls = 0;
+ url_data.fetch = true;
+ if ((error = get_optional_config(&found, config, &buf, url_cb, &url_data)) < 0)
goto cleanup;
+ val = url_data.val;
optional_setting_found |= found;
if (!optional_setting_found) {
@@ -471,10 +507,10 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
goto cleanup;
}
- if (found && strlen(val) > 0) {
- remote->pushurl = git__strdup(val);
- GITERR_CHECK_ALLOC(remote->pushurl);
- }
+ if (found && strlen(val) > 0)
+ remote->pushurl = val;
+ else
+ git__free(val);
data.remote = remote;
data.fetch = true;