Commit 3350156242bb705818218fc29cebbf2798228b94

Stefan Sperling 2020-03-18T16:11:30

prepare for providing refs we already have in fetch request imsg currently we always send and expect an empty list

diff --git a/lib/fetch.c b/lib/fetch.c
index 910dea7..4016f64 100644
--- a/lib/fetch.c
+++ b/lib/fetch.c
@@ -310,11 +310,14 @@ got_fetch_pack(struct got_object_id **pack_hash, struct got_pathlist_head *refs,
 	char *tmppackpath = NULL, *tmpidxpath = NULL;
 	char *packpath = NULL, *idxpath = NULL, *id_str = NULL;
 	const char *repo_path = got_repo_get_path(repo);
+	struct got_pathlist_head have_refs;
 	struct got_pathlist_entry *pe;
 	char *path;
 
 	*pack_hash = NULL;
 
+	TAILQ_INIT(&have_refs);
+
 	if (asprintf(&path, "%s/%s/fetching.pack",
 	    repo_path, GOT_OBJECTS_PACK_DIR) == -1) {
 		err = got_error_from_errno("asprintf");
@@ -368,7 +371,7 @@ got_fetch_pack(struct got_object_id **pack_hash, struct got_pathlist_head *refs,
 		err = got_error_from_errno("dup");
 		goto done;
 	}
-	err = got_privsep_send_fetch_req(&ibuf, nfetchfd);
+	err = got_privsep_send_fetch_req(&ibuf, nfetchfd, &have_refs);
 	if (err != NULL)
 		goto done;
 	nfetchfd = -1;
diff --git a/lib/got_lib_privsep.h b/lib/got_lib_privsep.h
index 2e254be..05435e3 100644
--- a/lib/got_lib_privsep.h
+++ b/lib/got_lib_privsep.h
@@ -234,6 +234,17 @@ struct got_imsg_tag_object {
 	 */
 } __attribute__((__packed__));
 
+/* Structures for GOT_IMSG_FETCH_REQUEST data. */
+struct got_imsg_fetch_have_ref {
+	uint8_t id[SHA1_DIGEST_LENGTH];
+	size_t name_len;
+	/* Followed by name_len data bytes. */
+};
+struct got_imsg_fetch_have_refs {
+	size_t n_have_refs;
+	/* Followed by n_have_refs times of got_imsg_fetch_have_ref data. */
+};
+
 /* Structures for GOT_IMSG_FETCH_SYMREFS data. */
 struct got_imsg_fetch_symref {
 	size_t name_len;
@@ -339,7 +350,8 @@ const struct got_error *got_privsep_send_index_pack_req(struct imsgbuf *, int,
     struct got_object_id *);
 const struct got_error *got_privsep_send_index_pack_done(struct imsgbuf *);
 const struct got_error *got_privsep_wait_index_pack_done(struct imsgbuf *);
-const struct got_error *got_privsep_send_fetch_req(struct imsgbuf *, int);
+const struct got_error *got_privsep_send_fetch_req(struct imsgbuf *, int,
+    struct got_pathlist_head *);
 const struct got_error *got_privsep_send_fetch_symrefs(struct imsgbuf *,
     struct got_pathlist_head *);
 const struct got_error *got_privsep_send_fetch_progress(struct imsgbuf *,
diff --git a/lib/privsep.c b/lib/privsep.c
index 23b8318..6bd3dc9 100644
--- a/lib/privsep.c
+++ b/lib/privsep.c
@@ -405,16 +405,68 @@ got_privsep_send_obj(struct imsgbuf *ibuf, struct got_object *obj)
 }
 
 const struct got_error *
-got_privsep_send_fetch_req(struct imsgbuf *ibuf, int fd)
+got_privsep_send_fetch_req(struct imsgbuf *ibuf, int fd,
+   struct got_pathlist_head *have_refs)
 {
 	const struct got_error *err = NULL;
+	struct ibuf *wbuf;
+	size_t len, n_have_refs = 0;
+	struct got_pathlist_entry *pe;
 
-	if (imsg_compose(ibuf, GOT_IMSG_FETCH_REQUEST, 0, 0, fd,
-	    NULL, 0) == -1) {
-		err = got_error_from_errno("imsg_compose FETCH_REQUEST");
+	len = sizeof(struct got_imsg_fetch_symrefs);
+	TAILQ_FOREACH(pe, have_refs, entry) {
+		struct got_object_id *id = pe->data;
+		len += sizeof(struct got_imsg_fetch_have_ref) +
+		    pe->path_len + sizeof(id->sha1);
+		n_have_refs++;
+	}
+	if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
+		close(fd);
+		return got_error(GOT_ERR_NO_SPACE);
+	}
+
+	wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_REQUEST, 0, 0, len);
+	if (wbuf == NULL) {
+		close(fd);
+		return got_error_from_errno("imsg_create FETCH_REQUEST");
+	}
+
+	/* Keep in sync with struct got_imsg_fetch_have_refs definition! */
+	if (imsg_add(wbuf, &n_have_refs, sizeof(n_have_refs)) == -1) {
+		err = got_error_from_errno("imsg_add FETCH_REQUEST");
+		ibuf_free(wbuf);
 		close(fd);
 		return err;
 	}
+
+	TAILQ_FOREACH(pe, have_refs, entry) {
+		const char *name = pe->path;
+		size_t name_len = pe->path_len;
+		struct got_object_id *id = pe->data;
+
+		/* Keep in sync with struct got_imsg_fetch_have_ref! */
+		if (imsg_add(wbuf, id->sha1, sizeof(id->sha1)) == -1) {
+			err = got_error_from_errno("imsg_add FETCH_REQUEST");
+			ibuf_free(wbuf);
+			close(fd);
+			return err;
+		}
+		if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1) {
+			err = got_error_from_errno("imsg_add FETCH_REQUEST");
+			ibuf_free(wbuf);
+			close(fd);
+			return err;
+		}
+		if (imsg_add(wbuf, name, name_len) == -1) {
+			err = got_error_from_errno("imsg_add FETCH_REQUEST");
+			ibuf_free(wbuf);
+			close(fd);
+			return err;
+		}
+	}
+
+	wbuf->fd = fd;
+	imsg_close(ibuf, wbuf);
 	return flush_imsg(ibuf);
 }
 
diff --git a/libexec/got-fetch-pack/got-fetch-pack.c b/libexec/got-fetch-pack/got-fetch-pack.c
index 507b79d..0bdfc1b 100644
--- a/libexec/got-fetch-pack/got-fetch-pack.c
+++ b/libexec/got-fetch-pack/got-fetch-pack.c
@@ -55,7 +55,6 @@
 struct got_object *indexed;
 static int chattygit;
 static char *fetchbranch;
-static char *upstream = "origin";
 static struct got_object_id zhash = {.sha1={0}};
 
 int
@@ -137,47 +136,22 @@ writepkt(int fd, char *buf, int nbuf)
 	return 0;
 }
 
-/* TODO: This should not access the file system! */
-int
-got_resolve_remote_ref(struct got_object_id *id, char *ref)
+static const struct got_error *
+match_remote_ref(struct got_pathlist_head *have_refs, struct got_object_id *id,
+    char *refname, char *id_str)
 {
-	char buf[128], *s;
-	int r, f;
+	struct got_pathlist_entry *pe;
 
-	if (!got_parse_sha1_digest(id->sha1, ref))
-		return 0;
+	memset(id, 0, sizeof(*id));
 
-	/* Slightly special handling: translate remote refs to local ones. */
-	if (strcmp(ref, "HEAD") == 0) {
-		if (snprintf(buf, sizeof(buf), ".git/HEAD") >= sizeof(buf))
-			return -1;
-	} else if (strstr(ref, "refs/heads") == ref) {
-		ref += strlen("refs/heads");
-		if (snprintf(buf, sizeof(buf),
-		    ".git/refs/remotes/%s/%s", upstream, ref) >= sizeof(buf))
-			return -1;
-	} else if (strstr(ref, "refs/tags") == ref) {
-		ref += strlen("refs/tags");
-		if (snprintf(buf, sizeof(buf),
-		    ".git/refs/tags/%s/%s", upstream, ref) >= sizeof(buf))
-			return -1;
-	} else {
-		return -1;
+	TAILQ_FOREACH(pe, have_refs, entry) {
+		if (strcmp(pe->path, refname) == 0) {
+			if (!got_parse_sha1_digest(id->sha1, id_str))
+				return got_error(GOT_ERR_BAD_OBJ_ID_STR);
+			break;
+		}
 	}
-
-	r = -1;
-	s = buf;
-	if ((f = open(s, O_RDONLY)) == -1)
-		goto err;
-	if (readn(f, buf, sizeof(buf)) < 40)
-		goto err;
-	if (!got_parse_sha1_digest(id->sha1, buf))
-		goto err;
-err:
-	close(f);
-	if (r == -1 && strstr(buf, "ref:") == buf)
-		return got_resolve_remote_ref(id, buf + strlen("ref:"));
-	return r;
+	return NULL;
 }
 
 static int
@@ -399,7 +373,7 @@ match_capabilities(char **my_capabilities, struct got_pathlist_head *symrefs,
 
 static const struct got_error *
 fetch_pack(int fd, int packfd, struct got_object_id *packid,
-    struct imsgbuf *ibuf)
+    struct got_pathlist_head *have_refs, struct imsgbuf *ibuf)
 {
 	const struct got_error *err = NULL;
 	char buf[GOT_PKTMAX], *sp[3];
@@ -485,8 +459,10 @@ fetch_pack(int fd, int packfd, struct got_object_id *packid,
 			goto done;
 		}
 
-		if (got_resolve_remote_ref(&have[nref], sp[1]) == -1)
-			memset(&have[nref], 0, sizeof(have[nref]));
+		err = match_remote_ref(have_refs, &have[nref], sp[0], sp[1]);
+		if (err)
+			goto done;
+
 		err = got_privsep_send_fetch_progress(ibuf, &want[nref], sp[1]);
 		if (err)
 			goto done;
@@ -597,6 +573,11 @@ main(int argc, char **argv)
 	struct got_object_id packid;
 	struct imsgbuf ibuf;
 	struct imsg imsg;
+	struct got_pathlist_head have_refs;
+	struct got_imsg_fetch_have_refs *fetch_have_refs = NULL;
+	size_t datalen;
+
+	TAILQ_INIT(&have_refs);
 
 	if (getenv("GOT_DEBUG") != NULL) {
 		fprintf(stderr, "fetch-pack being chatty!\n");
@@ -615,10 +596,23 @@ main(int argc, char **argv)
 		err = got_error(GOT_ERR_PRIVSEP_MSG);
 		goto done;
 	}
-	if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) {
+	datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+	if (datalen < sizeof(struct got_imsg_fetch_have_refs)) {
 		err = got_error(GOT_ERR_PRIVSEP_LEN);
 		goto done;
 	}
+	fetch_have_refs = (struct got_imsg_fetch_have_refs *)imsg.data;
+	if (datalen != sizeof(struct got_imsg_fetch_have_refs) +
+	    sizeof(struct got_imsg_fetch_have_ref) *
+	    fetch_have_refs->n_have_refs) {
+		err = got_error(GOT_ERR_PRIVSEP_LEN);
+		goto done;
+	}
+	if (fetch_have_refs->n_have_refs != 0) {
+		/* TODO: Incremental fetch support */
+		err = got_error(GOT_ERR_NOT_IMPL);
+		goto done;
+	}
 	fetchfd = imsg.fd;
 
 	if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
@@ -638,7 +632,7 @@ main(int argc, char **argv)
 	}
 	packfd = imsg.fd;
 
-	err = fetch_pack(fetchfd, packfd, &packid, &ibuf);
+	err = fetch_pack(fetchfd, packfd, &packid, &have_refs, &ibuf);
 	if (err)
 		goto done;
 done: