support commit log messages larger than the maximum imsg size
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
diff --git a/lib/got_lib_privsep.h b/lib/got_lib_privsep.h
index 38a8347..3620a1f 100644
--- a/lib/got_lib_privsep.h
+++ b/lib/got_lib_privsep.h
@@ -81,6 +81,7 @@ enum got_imsg_type {
GOT_IMSG_OBJECT,
GOT_IMSG_COMMIT_REQUEST,
GOT_IMSG_COMMIT,
+ GOT_IMSG_COMMIT_LOGMSG,
GOT_IMSG_TREE_REQUEST,
GOT_IMSG_TREE,
GOT_IMSG_TREE_ENTRY,
@@ -127,12 +128,15 @@ struct got_imsg_commit_object {
int nparents;
/*
- * Followed by author_len + committer_len + logmsg_len data bytes
+ * Followed by author_len + committer_len data bytes
*/
/* Followed by 'nparents' SHA1_DIGEST_LENGTH length strings */
- /* XXX should use more messages to support very large log messages */
+ /*
+ * Followed by 'logmsg_len' bytes of commit log message data in
+ * one or more GOT_IMSG_COMMIT_LOGMSG messages.
+ */
} __attribute__((__packed__));
diff --git a/lib/privsep.c b/lib/privsep.c
index b101ac4..b7cdab1 100644
--- a/lib/privsep.c
+++ b/lib/privsep.c
@@ -363,6 +363,31 @@ got_privsep_recv_obj(struct got_object **obj, struct imsgbuf *ibuf)
return err;
}
+static const struct got_error *
+send_commit_logmsg(struct imsgbuf *ibuf, struct got_commit_object *commit,
+ size_t logmsg_len)
+{
+ size_t offset, remain;
+
+ offset = 0;
+ remain = logmsg_len;
+ while (remain > 0) {
+ size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE, remain);
+
+ if (imsg_compose(ibuf, GOT_IMSG_COMMIT_LOGMSG, 0, 0, -1,
+ commit->logmsg + offset, n) == -1)
+ return got_error_from_errno();
+
+ if (imsg_flush(ibuf) == -1)
+ return got_error_from_errno();
+
+ offset += n;
+ remain -= n;
+ }
+
+ return NULL;
+}
+
const struct got_error *
got_privsep_send_commit(struct imsgbuf *ibuf, struct got_commit_object *commit)
{
@@ -371,6 +396,7 @@ got_privsep_send_commit(struct imsgbuf *ibuf, struct got_commit_object *commit)
uint8_t *buf;
size_t len, total;
struct got_object_qid *qid;
+ size_t logmsg_len = strlen(commit->logmsg);
memcpy(icommit.tree_id, commit->tree_id->sha1, sizeof(icommit.tree_id));
icommit.author_len = strlen(commit->author);
@@ -379,15 +405,11 @@ got_privsep_send_commit(struct imsgbuf *ibuf, struct got_commit_object *commit)
icommit.committer_len = strlen(commit->committer);
memcpy(&icommit.tm_committer, &commit->tm_committer,
sizeof(icommit.tm_committer));
- icommit.logmsg_len = strlen(commit->logmsg);
+ icommit.logmsg_len = logmsg_len;
icommit.nparents = commit->nparents;
total = sizeof(icommit) + icommit.author_len +
- icommit.committer_len + icommit.logmsg_len +
- icommit.nparents * SHA1_DIGEST_LENGTH;
- /* XXX TODO support very large log messages properly */
- if (total > MAX_IMSGSIZE)
- return got_error(GOT_ERR_NO_SPACE);
+ icommit.committer_len + icommit.nparents * SHA1_DIGEST_LENGTH;
buf = malloc(total);
if (buf == NULL)
@@ -400,8 +422,6 @@ got_privsep_send_commit(struct imsgbuf *ibuf, struct got_commit_object *commit)
len += icommit.author_len;
memcpy(buf + len, commit->committer, icommit.committer_len);
len += icommit.committer_len;
- memcpy(buf + len, commit->logmsg, icommit.logmsg_len);
- len += icommit.logmsg_len;
SIMPLEQ_FOREACH(qid, &commit->parent_ids, entry) {
memcpy(buf + len, qid->id, SHA1_DIGEST_LENGTH);
len += SHA1_DIGEST_LENGTH;
@@ -413,6 +433,10 @@ got_privsep_send_commit(struct imsgbuf *ibuf, struct got_commit_object *commit)
}
err = flush_imsg(ibuf);
+ if (err)
+ goto done;
+
+ err = send_commit_logmsg(ibuf, commit, logmsg_len);
done:
free(buf);
return err;
@@ -453,7 +477,7 @@ got_privsep_recv_commit(struct got_commit_object **commit, struct imsgbuf *ibuf)
memcpy(&icommit, data, sizeof(icommit));
if (datalen != sizeof(icommit) + icommit.author_len +
- icommit.committer_len + icommit.logmsg_len +
+ icommit.committer_len +
icommit.nparents * SHA1_DIGEST_LENGTH) {
err = got_error(GOT_ERR_PRIVSEP_LEN);
break;
@@ -521,16 +545,33 @@ got_privsep_recv_commit(struct got_commit_object **commit, struct imsgbuf *ibuf)
break;
}
} else {
+ size_t offset = 0, remain = icommit.logmsg_len;
+
(*commit)->logmsg = malloc(icommit.logmsg_len + 1);
if ((*commit)->logmsg == NULL) {
err = got_error_from_errno();
break;
}
- memcpy((*commit)->logmsg, data + len,
- icommit.logmsg_len);
+ while (remain > 0) {
+ struct imsg imsg_log;
+ size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE,
+ remain);
+
+ err = got_privsep_recv_imsg(&imsg_log, ibuf, n);
+ if (err)
+ return err;
+
+ if (imsg_log.hdr.type != GOT_IMSG_COMMIT_LOGMSG)
+ return got_error(GOT_ERR_PRIVSEP_MSG);
+
+ memcpy((*commit)->logmsg + offset,
+ imsg_log.data, n);
+ imsg_free(&imsg_log);
+ offset += n;
+ remain -= n;
+ }
(*commit)->logmsg[icommit.logmsg_len] = '\0';
}
- len += icommit.logmsg_len;
for (i = 0; i < icommit.nparents; i++) {
struct got_object_qid *qid;