Commit Diff


commit - 91ea6bdc31d360deff8b1c26c623e85250278428
commit + 7d39de3e6c0a774e33c4433b5a3932a606d09530
blob - ba7c6aae995f0e1e618534a513d3a695412df773
blob + 6780129adeedaddd59a04e3fc4d44faf5b2d5173
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
@@ -204,6 +204,10 @@ enum got_imsg_type {
 	/* Transfer a list of object IDs. */
 	GOT_IMSG_OBJ_ID_LIST,
 	GOT_IMSG_OBJ_ID_LIST_DONE,
+
+	/* Transfer a queue of object IDs. */
+	GOT_IMSG_OBJ_ID_QUEUE,
+	GOT_IMSG_OBJ_ID_QUEUE_DONE,
 
 	/* Messages related to patch files. */
 	GOT_IMSG_PATCH_FILE,
@@ -573,6 +577,24 @@ struct got_imsg_object_idlist {
 	sizeof(struct got_imsg_object_idlist)) / sizeof(struct got_object_id))
 };
 
+/*
+ * Structure for GOT_IMSG_OBJ_ID_QUEUE data.
+ * Multiple such messages may be sent back-to-back, where each message
+ * contains a chunk of IDs. The entire list must be terminated with a
+ * GOT_IMSG_OBJ_ID_QUEUE_DONE message.
+ */
+struct got_imsg_object_id_queue {
+	size_t nids;
+
+	/*
+	 * Followed by nids * struct got_object_qid.
+	 */
+
+#define GOT_IMSG_OBJ_ID_QUEUE_MAX_NIDS \
+	((MAX_IMSGSIZE - IMSG_HEADER_SIZE - \
+	sizeof(struct got_imsg_object_id_queue)) / sizeof(struct got_object_qid))
+};
+
 /* Structure for GOT_IMSG_COMMIT_TRAVERSAL_REQUEST  */
 struct got_imsg_commit_traversal_request {
 	struct got_imsg_packed_object iobj;
@@ -817,6 +839,11 @@ const struct got_error *got_privsep_send_object_idlist
 const struct got_error *got_privsep_send_object_idlist_done(struct imsgbuf *);
 const struct got_error *got_privsep_recv_object_idlist(int *,
     struct got_object_id **, size_t *, struct imsgbuf *);
+
+const struct got_error *got_privsep_send_object_id_queue(struct imsgbuf *ibuf,
+    struct got_object_id_queue *, size_t);
+const struct got_error *got_privsep_recv_object_id_queue(int *,
+    struct got_object_id_queue *, size_t *, struct imsgbuf *);
 
 const struct got_error *got_privsep_send_delta_reuse_req(struct imsgbuf *);
 const struct got_error *got_privsep_send_reused_deltas(struct imsgbuf *,
blob - 106d1a9f8b921c7f2648c52049f36704e1ff9d87
blob + c87aeadd22be51b99cd7b2a2c28693d4c18c9a66
--- lib/privsep.c
+++ lib/privsep.c
@@ -3258,6 +3258,130 @@ got_privsep_recv_object_idlist(int *done, struct got_o
 		    *nids * sizeof(**ids));
 		break;
 	case GOT_IMSG_OBJ_ID_LIST_DONE:
+		*done = 1;
+		break;
+	default:
+		err = got_error(GOT_ERR_PRIVSEP_MSG);
+		break;
+	}
+
+	imsg_free(&imsg);
+
+	return err;
+}
+
+static const struct got_error *
+send_qidlist(struct imsgbuf *ibuf, struct got_object_qid **qids, size_t nids)
+{
+	const struct got_error *err = NULL;
+	struct got_imsg_object_id_queue idqueue;
+	struct ibuf *wbuf;
+	size_t i;
+
+	memset(&idqueue, 0, sizeof(idqueue));
+
+	if (nids > GOT_IMSG_OBJ_ID_QUEUE_MAX_NIDS)
+		return got_error(GOT_ERR_NO_SPACE);
+
+	wbuf = imsg_create(ibuf, GOT_IMSG_OBJ_ID_QUEUE, 0, 0,
+	    sizeof(idqueue) + nids * sizeof(struct got_object_qid));
+	if (wbuf == NULL) {
+		err = got_error_from_errno("imsg_create OBJ_ID_QUEUE");
+		return err;
+	}
+
+	idqueue.nids = nids;
+	if (imsg_add(wbuf, &idqueue, sizeof(idqueue)) == -1)
+		return got_error_from_errno("imsg_add OBJ_ID_QUEUE");
+
+	for (i = 0; i < nids; i++) {
+		struct got_object_qid *qid = qids[i];
+		if (imsg_add(wbuf, qid, sizeof(*qid)) == -1)
+			return got_error_from_errno("imsg_add OBJ_ID_LIST");
+	}
+
+	imsg_close(ibuf, wbuf);
+
+	return flush_imsg(ibuf);
+}
+
+const struct got_error *
+got_privsep_send_object_id_queue(struct imsgbuf *ibuf,
+    struct got_object_id_queue *ids, size_t nids)
+{
+	const struct got_error *err = NULL;
+	struct got_object_qid *qid, *qidlist[GOT_IMSG_OBJ_ID_QUEUE_MAX_NIDS];
+	int i, queued = 0;
+
+	qid = STAILQ_FIRST(ids);
+	for (i = 0; qid && i < nids; i++) {
+		qidlist[i % nitems(qidlist)] = qid;
+		queued++;
+		if (queued >= nitems(qidlist)) {
+			err = send_qidlist(ibuf, qidlist, queued);
+			if (err)
+				return err;
+			queued = 0;
+		}
+		qid = STAILQ_NEXT(qid, entry);
+	}
+
+	if (queued > 0) {
+		err = send_qidlist(ibuf, qidlist, queued);
+		if (err)
+			return err;
+	}
+
+	if (imsg_compose(ibuf, GOT_IMSG_OBJ_ID_QUEUE_DONE, 0, 0, -1, NULL, 0)
+	    == -1)
+		return got_error_from_errno("imsg_compose OBJ_ID_QUEUE_DONE");
+
+	return flush_imsg(ibuf);
+}
+
+const struct got_error *
+got_privsep_recv_object_id_queue(int *done, struct got_object_id_queue *ids,
+    size_t *nids, struct imsgbuf *ibuf)
+{
+	const struct got_error *err = NULL;
+	struct imsg imsg;
+	struct got_imsg_object_id_queue *qidlist;
+	struct got_object_qid *qid, *iqid;
+	size_t datalen;
+
+	*done = 0;
+	*nids = 0;
+
+	err = got_privsep_recv_imsg(&imsg, ibuf, 0);
+	if (err)
+		return err;
+
+	datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+	switch (imsg.hdr.type) {
+	case GOT_IMSG_OBJ_ID_QUEUE:
+		if (datalen < sizeof(*qidlist)) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			break;
+		}
+		qidlist = imsg.data;
+		if (qidlist->nids > GOT_IMSG_OBJ_ID_LIST_MAX_NIDS ||
+		    qidlist->nids * sizeof(struct got_object_qid) !=
+		    datalen - sizeof(*qidlist)) {
+			err = got_error(GOT_ERR_PRIVSEP_LEN);
+			break;
+		}
+		iqid = (struct got_object_qid *)(imsg.data + sizeof(*qidlist));
+		while (*nids < qidlist->nids) {
+			err = got_object_qid_alloc_partial(&qid);
+			if (err)
+				break;
+			memcpy(qid, iqid, sizeof(*qid));
+			STAILQ_INSERT_TAIL(ids, qid, entry);
+			(*nids)++;
+			iqid++;
+		}
+		break;
+	case GOT_IMSG_OBJ_ID_QUEUE_DONE:
 		*done = 1;
 		break;
 	default: