Commit Diff


commit - bd5895f3726fd0edc272b4c44727f60b5a5132c9
commit + cd95becd3d0ee4fb578daf570177c3550cb19e08
blob - e2e96e4065e6d735452b5a23c4eb1ad179abfa67
blob + d0df1255deadae95cebcf18a88340a0d87666d46
--- include/got_error.h
+++ include/got_error.h
@@ -127,6 +127,7 @@
 #define GOT_ERR_REBASE_REQUIRED	111
 #define GOT_ERR_REGEX		112
 #define GOT_ERR_REF_NAME_MINUS	113
+#define GOT_ERR_GITCONFIG_SYNTAX 114
 
 static const struct got_error {
 	int code;
@@ -260,6 +261,7 @@ static const struct got_error {
 	{ GOT_ERR_REBASE_REQUIRED,"specified branch must be rebased first" },
 	{ GOT_ERR_REGEX, "regular expression error" },
 	{ GOT_ERR_REF_NAME_MINUS, "reference name may not start with '-'" },
+	{ GOT_ERR_GITCONFIG_SYNTAX, "gitconfig syntax error" },
 };
 
 /*
blob - 7ed477b1d49d732af4362f4100cb33659065f814
blob + 6ef2a57e12d131c901a5bce6196837a91a3618ba
--- include/got_repository.h
+++ include/got_repository.h
@@ -44,6 +44,16 @@ const char *got_repo_get_global_gitconfig_author_name(
 /* Obtain global commit author email parsed ~/.gitconfig, else NULL. */
 const char *got_repo_get_global_gitconfig_author_email(struct got_repository *);
 
+/* Information about one remote repository. */
+struct got_remote_repo {
+	char *name;
+	char *url;
+};
+
+/* Obtain the list of remote repositories parsed from gitconfig. */ 
+void got_repo_get_gitconfig_remotes(int *, struct got_remote_repo **,
+    struct got_repository *);
+
 /*
  * Obtain paths to various directories within a repository.
  * The caller must dispose of a path with free(3).
blob - 1ddfb97d543989190d1cf894c45ed4ed1424f1aa
blob + 5188ecbf5c2419c20c0064c42212be9f91f390f0
--- lib/gitconfig.c
+++ lib/gitconfig.c
@@ -493,7 +493,52 @@ got_gitconfig_get_str(struct got_gitconfig *conf, char
 	    tag));
 	return 0;
 }
+
+const struct got_error *
+got_gitconfig_get_section_list(struct got_gitconfig_list **sections,
+    struct got_gitconfig *conf)
+{
+	const struct got_error *err = NULL;
+	struct got_gitconfig_list *list = NULL;
+	struct got_gitconfig_list_node *node = 0;
+	struct got_gitconfig_binding *cb;
+	int i;
+
+	*sections = NULL;
 
+	list = malloc(sizeof *list);
+	if (!list)
+		return got_error_from_errno("malloc");
+	TAILQ_INIT(&list->fields);
+	list->cnt = 0;
+	for (i = 0; i < nitems(conf->bindings); i++) {
+		for (cb = LIST_FIRST(&conf->bindings[i]); cb;
+		    cb = LIST_NEXT(cb, link)) {
+			list->cnt++;
+			node = calloc(1, sizeof *node);
+			if (!node) {
+				err = got_error_from_errno("calloc");
+				goto cleanup;
+			}
+			node->field = strdup(cb->section);
+			if (!node->field) {
+				err = got_error_from_errno("strdup");
+				goto cleanup;
+			}
+			TAILQ_INSERT_TAIL(&list->fields, node, link);
+		}
+	}
+
+	*sections = list;
+	return NULL;
+
+cleanup:
+	free(node);
+	if (list)
+		got_gitconfig_free_list(list);
+	return err;
+}
+
 /*
  * Build a list of string values out of the comma separated value denoted by
  * TAG in SECTION.
blob - 4d61ab3964722d849b94e3048f1cb6a15d2edc3f
blob + 615d2690ac39f3fceb3704b2624a85e8de2ba65c
--- lib/got_lib_gitconfig.h
+++ lib/got_lib_gitconfig.h
@@ -39,6 +39,8 @@ struct got_gitconfig_list {
 struct got_gitconfig;
 
 void     got_gitconfig_free_list(struct got_gitconfig_list *);
+const struct got_error *got_gitconfig_get_section_list(
+    struct got_gitconfig_list **, struct got_gitconfig *);
 struct got_gitconfig_list *got_gitconfig_get_list(struct got_gitconfig *,
     char *, char *);
 struct got_gitconfig_list *got_gitconfig_get_tag_list(struct got_gitconfig *, char *);
blob - a37a450e6e18733afec74aa1dc9cb427c9d27acb
blob + b27325da498aa72413f8377303ba76d4012c7813
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
@@ -111,8 +111,11 @@ enum got_imsg_type {
 	GOT_IMSG_GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST,
 	GOT_IMSG_GITCONFIG_AUTHOR_NAME_REQUEST,
 	GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST,
+	GOT_IMSG_GITCONFIG_REMOTES_REQUEST,
 	GOT_IMSG_GITCONFIG_INT_VAL,
 	GOT_IMSG_GITCONFIG_STR_VAL,
+	GOT_IMSG_GITCONFIG_REMOTES,
+	GOT_IMSG_GITCONFIG_REMOTE,
 };
 
 /* Structure for GOT_IMSG_ERROR. */
@@ -229,6 +232,24 @@ struct got_imsg_packed_object {
 	int idx;
 } __attribute__((__packed__));
 
+/*
+ * Structure for GOT_IMSG_GITCONFIG_REMOTE data.
+ */
+struct got_imsg_remote {
+	size_t name_len;
+	size_t url_len;
+
+	/* Followed by name_len + url_len data bytes. */
+};
+
+/*
+ * Structure for GOT_IMSG_GITCONFIG_REMOTES data.
+ */
+struct got_imsg_remotes {
+	int nremotes; /* This many GOT_IMSG_GITCONFIG_REMOTE messages follow. */
+};
+
+struct got_remote_repo;
 struct got_pack;
 struct got_packidx;
 struct got_pathlist_head;
@@ -285,11 +306,17 @@ const struct got_error *got_privsep_send_gitconfig_aut
     struct imsgbuf *);
 const struct got_error *got_privsep_send_gitconfig_author_email_req(
     struct imsgbuf *);
+const struct got_error *got_privsep_send_gitconfig_remotes_req(
+    struct imsgbuf *);
 const struct got_error *got_privsep_send_gitconfig_str(struct imsgbuf *,
     const char *);
 const struct got_error *got_privsep_recv_gitconfig_str(char **,
     struct imsgbuf *);
 const struct got_error *got_privsep_send_gitconfig_int(struct imsgbuf *, int);
 const struct got_error *got_privsep_recv_gitconfig_int(int *, struct imsgbuf *);
+const struct got_error *got_privsep_send_gitconfig_remotes(struct imsgbuf *,
+    struct got_remote_repo *, int);
+const struct got_error *got_privsep_recv_gitconfig_remotes(
+    struct got_remote_repo **, int *, struct imsgbuf *);
 
 void got_privsep_exec_child(int[2], const char *, const char *);
blob - c304faf993ada599d3d88ab1f3172d00c4ba1225
blob + 93f1734b814bde4b84f85106f95c3646947c45d8
--- lib/got_lib_repository.h
+++ lib/got_lib_repository.h
@@ -47,6 +47,8 @@ struct got_repository {
 	char *gitconfig_author_email;
 	char *global_gitconfig_author_name;
 	char *global_gitconfig_author_email;
+	int ngitconfig_remotes;
+	struct got_remote_repo *gitconfig_remotes;
 };
 
 const struct got_error*got_repo_cache_object(struct got_repository *,
blob - 58bdc0196125fd795f5e78ba1b0c888f248e9fa2
blob + f31cafb2ee6c5d18919265def86f6ddd6193c86d
--- lib/privsep.c
+++ lib/privsep.c
@@ -34,6 +34,7 @@
 #include "got_object.h"
 #include "got_error.h"
 #include "got_path.h"
+#include "got_repository.h"
 
 #include "got_lib_sha1.h"
 #include "got_lib_delta.h"
@@ -1274,6 +1275,17 @@ got_privsep_send_gitconfig_author_email_req(struct ims
 	    GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST, 0, 0, -1, NULL, 0) == -1)
 		return got_error_from_errno("imsg_compose "
 		    "GITCONFIG_AUTHOR_EMAIL_REQUEST");
+
+	return flush_imsg(ibuf);
+}
+
+const struct got_error *
+got_privsep_send_gitconfig_remotes_req(struct imsgbuf *ibuf)
+{
+	if (imsg_compose(ibuf,
+	    GOT_IMSG_GITCONFIG_REMOTES_REQUEST, 0, 0, -1, NULL, 0) == -1)
+		return got_error_from_errno("imsg_compose "
+		    "GITCONFIG_REMOTE_REQUEST");
 
 	return flush_imsg(ibuf);
 }
@@ -1359,6 +1371,108 @@ got_privsep_recv_gitconfig_int(int *val, struct imsgbu
 			break;
 		}
 		memcpy(val, imsg.data, sizeof(*val));
+		break;
+	default:
+		err = got_error(GOT_ERR_PRIVSEP_MSG);
+		break;
+	}
+
+	imsg_free(&imsg);
+	return err;
+}
+
+const struct got_error *
+got_privsep_send_gitconfig_remotes(struct imsgbuf *ibuf,
+    struct got_remote_repo *remotes, int nremotes)
+{
+	const struct got_error *err = NULL;
+	struct got_imsg_remotes iremotes;
+	int i;
+
+	iremotes.nremotes = nremotes;
+	if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_REMOTES, 0, 0, -1,
+	    &iremotes, sizeof(iremotes)) == -1)
+		return got_error_from_errno("imsg_compose GITCONFIG_REMOTES");
+
+	err = flush_imsg(ibuf);
+	imsg_clear(ibuf);
+	if (err)
+		return err;
+
+	for (i = 0; i < nremotes; i++) {
+		struct got_imsg_remote iremote;
+		size_t len = sizeof(iremote);
+		struct ibuf *wbuf;
+
+		iremote.name_len = strlen(remotes[i].name);
+		len += iremote.name_len;
+		iremote.url_len = strlen(remotes[i].url);
+		len += iremote.url_len;
+
+		wbuf = imsg_create(ibuf, GOT_IMSG_GITCONFIG_REMOTE, 0, 0, len);
+		if (wbuf == NULL)
+			return got_error_from_errno(
+			    "imsg_create GITCONFIG_REMOTE");
+
+		if (imsg_add(wbuf, &iremote, sizeof(iremote)) == -1) {
+			err = got_error_from_errno(
+			    "imsg_add GIITCONFIG_REMOTE");
+			ibuf_free(wbuf);
+			return err;
+		}
+
+		if (imsg_add(wbuf, remotes[i].name, iremote.name_len) == -1) {
+			err = got_error_from_errno(
+			    "imsg_add GIITCONFIG_REMOTE");
+			ibuf_free(wbuf);
+			return err;
+		}
+		if (imsg_add(wbuf, remotes[i].url, iremote.url_len) == -1) {
+			err = got_error_from_errno(
+			    "imsg_add GIITCONFIG_REMOTE");
+			ibuf_free(wbuf);
+			return err;
+		}
+
+		wbuf->fd = -1;
+		imsg_close(ibuf, wbuf);
+		err = flush_imsg(ibuf);
+		if (err)
+			return err;
+	}
+
+	return NULL;
+}
+
+const struct got_error *
+got_privsep_recv_gitconfig_remotes(struct got_remote_repo **remotes,
+    int *nremotes, struct imsgbuf *ibuf)
+{
+	const struct got_error *err = NULL;
+	struct imsg imsg;
+	size_t datalen;
+	struct got_imsg_remotes iremotes;
+	struct got_imsg_remote iremote;
+
+	*remotes = NULL;
+	*nremotes = 0;
+
+	err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremotes));
+	if (err)
+		return err;
+	datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+
+	switch (imsg.hdr.type) {
+	case GOT_IMSG_GITCONFIG_REMOTES:
+		if (datalen != sizeof(iremotes)) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			break;
+		}
+		memcpy(&iremotes, imsg.data, sizeof(iremotes));
+		if (iremotes.nremotes == 0) {
+			imsg_free(&imsg);
+			return NULL;
+		}
 		break;
 	default:
 		err = got_error(GOT_ERR_PRIVSEP_MSG);
@@ -1366,6 +1480,68 @@ got_privsep_recv_gitconfig_int(int *val, struct imsgbu
 	}
 
 	imsg_free(&imsg);
+
+	*remotes = recallocarray(NULL, 0, iremotes.nremotes, sizeof(iremote));
+	if (*remotes == NULL)
+		return got_error_from_errno("recallocarray");
+
+	while (*nremotes < iremotes.nremotes) {
+		struct got_remote_repo *remote;
+	
+		err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremote));
+		if (err)
+			break;
+		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+
+		switch (imsg.hdr.type) {
+		case GOT_IMSG_GITCONFIG_REMOTE:
+			remote = &(*remotes)[*nremotes];
+			if (datalen < sizeof(iremote)) {
+				err = got_error(GOT_ERR_PRIVSEP_LEN);
+				break;
+			}
+			memcpy(&iremote, imsg.data, sizeof(iremote));
+			if (iremote.name_len == 0 || iremote.url_len == 0 ||
+			    (sizeof(iremote) + iremote.name_len +
+			    iremote.url_len) > datalen) {
+				err = got_error(GOT_ERR_PRIVSEP_LEN);
+				break;
+			}
+			remote->name = strndup(imsg.data + sizeof(iremote),
+			    iremote.name_len);
+			if (remote->name == NULL) {
+				err = got_error_from_errno("strndup");
+				break;
+			}
+			remote->url = strndup(imsg.data + sizeof(iremote) +
+			    iremote.name_len, iremote.url_len);
+			if (remote->url == NULL) {
+				err = got_error_from_errno("strndup");
+				free(remote->name);
+				break;
+			}
+			(*nremotes)++;
+			break;
+		default:
+			err = got_error(GOT_ERR_PRIVSEP_MSG);
+			break;
+		}
+
+		imsg_free(&imsg);
+		if (err)
+			break;
+	}
+
+	if (err) {
+		int i;
+		for (i = 0; i < *nremotes; i++) {
+			free((*remotes)[i].name);
+			free((*remotes)[i].url);
+		}
+		free(*remotes);
+		*remotes = NULL;
+		*nremotes = 0;
+	}
 	return err;
 }
 
blob - a5b0f8fded6c31a6c08dace849ceda974c1ef3c8
blob + e7022555ae9106a6b519d797cb9e28bbdfe897b4
--- lib/repository.c
+++ lib/repository.c
@@ -168,6 +168,14 @@ get_path_gitconfig(char **p, struct got_repository *re
 	if (*p == NULL)
 		return got_error_from_errno("asprintf");
 	return NULL;
+}
+
+void
+got_repo_get_gitconfig_remotes(int *nremotes, struct got_remote_repo **remotes,
+    struct got_repository *repo)
+{
+	*nremotes = repo->ngitconfig_remotes;
+	*remotes = repo->gitconfig_remotes;
 }
 
 static int
@@ -365,6 +373,7 @@ done:
 static const struct got_error *
 parse_gitconfig_file(int *gitconfig_repository_format_version,
     char **gitconfig_author_name, char **gitconfig_author_email,
+    struct got_remote_repo **remotes, int *nremotes,
     const char *gitconfig_path)
 {
 	const struct got_error *err = NULL, *child_err = NULL;
@@ -441,6 +450,17 @@ parse_gitconfig_file(int *gitconfig_repository_format_
 	err = got_privsep_recv_gitconfig_str(gitconfig_author_email, ibuf);
 	if (err)
 		goto done;
+
+	if (remotes && nremotes) {
+		err = got_privsep_send_gitconfig_remotes_req(ibuf);
+		if (err)
+			goto done;
+
+		err = got_privsep_recv_gitconfig_remotes(remotes,
+		    nremotes, ibuf);
+		if (err)
+			goto done;
+	}
 
 	imsg_clear(ibuf);
 	err = got_privsep_send_stop(imsg_fds[0]);
@@ -470,7 +490,7 @@ read_gitconfig(struct got_repository *repo, const char
 		err = parse_gitconfig_file(&dummy_repo_version,
 		    &repo->global_gitconfig_author_name,
 		    &repo->global_gitconfig_author_email,
-		    global_gitconfig_path);
+		    NULL, NULL, global_gitconfig_path);
 		if (err)
 			return err;
 	}
@@ -482,6 +502,7 @@ read_gitconfig(struct got_repository *repo, const char
 
 	err = parse_gitconfig_file(&repo->gitconfig_repository_format_version,
 	    &repo->gitconfig_author_name, &repo->gitconfig_author_email,
+	    &repo->gitconfig_remotes, &repo->ngitconfig_remotes,
 	    repo_gitconfig_path);
 	if (err)
 		goto done;
@@ -620,6 +641,11 @@ got_repo_close(struct got_repository *repo)
 
 	free(repo->gitconfig_author_name);
 	free(repo->gitconfig_author_email);
+	for (i = 0; i < repo->ngitconfig_remotes; i++) {
+		free(repo->gitconfig_remotes[i].name);
+		free(repo->gitconfig_remotes[i].url);
+	}
+	free(repo->gitconfig_remotes);
 	free(repo);
 
 	return err;
blob - c14f37dd21a67e7027328b8a776e99a036726c7c
blob + 7c6439deb2b6bd6dd54a308e07d765495636ca39
--- libexec/got-read-gitconfig/got-read-gitconfig.c
+++ libexec/got-read-gitconfig/got-read-gitconfig.c
@@ -32,6 +32,7 @@
 
 #include "got_error.h"
 #include "got_object.h"
+#include "got_repository.h"
 
 #include "got_lib_delta.h"
 #include "got_lib_object.h"
@@ -72,6 +73,75 @@ gitconfig_str_request(struct imsgbuf *ibuf, struct got
 	return got_privsep_send_gitconfig_str(ibuf, value);
 }
 
+static const struct got_error *
+gitconfig_remotes_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig)
+{
+	const struct got_error *err = NULL;
+	struct got_gitconfig_list *sections;
+	struct got_gitconfig_list_node *node;
+	struct got_remote_repo *remotes = NULL;
+	int nremotes = 0, i;
+
+	if (gitconfig == NULL)
+		return got_error(GOT_ERR_PRIVSEP_MSG);
+
+	err = got_gitconfig_get_section_list(&sections, gitconfig);
+	if (err)
+		return err;
+
+	TAILQ_FOREACH(node, &sections->fields, link) {
+		if (strncasecmp("remote \"", node->field, 8) != 0)
+			continue;
+		nremotes++;
+	}
+
+	if (nremotes == 0) {
+		err = got_privsep_send_gitconfig_remotes(ibuf, NULL, 0);
+		goto done;
+	}
+
+	remotes = recallocarray(NULL, 0, nremotes, sizeof(*remotes));
+	if (remotes == NULL) {
+		err = got_error_from_errno("recallocarray");
+		goto done;
+	}
+
+	i = 0;
+	TAILQ_FOREACH(node, &sections->fields, link) {
+		char *name, *end;
+
+		if (strncasecmp("remote \"", node->field, 8) != 0)
+			continue;
+
+		name = strdup(node->field + 8);
+		if (name == NULL) {
+			err = got_error_from_errno("strdup");
+			goto done;
+		}
+		end = strrchr(name, '"');
+		if (end)
+			*end = '\0';
+		remotes[i].name = name;
+
+		remotes[i].url = got_gitconfig_get_str(gitconfig,
+		    node->field, "url");
+		if (remotes[i].url == NULL) {
+			err = got_error(GOT_ERR_GITCONFIG_SYNTAX);
+			goto done;
+		}
+
+		i++;
+	}
+
+	err = got_privsep_send_gitconfig_remotes(ibuf, remotes, nremotes);
+done:
+	for (i = 0; i < nremotes; i++)
+		free(remotes[i].name);
+	free(remotes);
+	got_gitconfig_free_list(sections);
+	return err;
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -147,6 +217,9 @@ main(int argc, char *argv[])
 			err = gitconfig_str_request(&ibuf, gitconfig, "user",
 			    "email");
 			break;
+		case GOT_IMSG_GITCONFIG_REMOTES_REQUEST:
+			err = gitconfig_remotes_request(&ibuf, gitconfig);
+			break;
 		default:
 			err = got_error(GOT_ERR_PRIVSEP_MSG);
 			break;