commit c75f7264fe1eb2b57be459109a258b05ac3e5a98 from: Stefan Sperling date: Tue Sep 11 10:57:03 2018 UTC support commit log messages larger than the maximum imsg size commit - c59b334653ceb49c2009ed64fe3a16fa89e0e7f4 commit + c75f7264fe1eb2b57be459109a258b05ac3e5a98 blob - 38a83477cfa367f9bd2c029371bbe1fbcf2f0598 blob + 3620a1f18ef31e6581d44f359aba047c1430243c --- lib/got_lib_privsep.h +++ 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__)); blob - b101ac47cc0a29ad631f01913e378cc90cba9014 blob + b7cdab14cb8dc234b6f786daf2860c4c1d25e6cc --- lib/privsep.c +++ lib/privsep.c @@ -361,6 +361,31 @@ got_privsep_recv_obj(struct got_object **obj, struct i imsg_free(&imsg); 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 * @@ -371,6 +396,7 @@ got_privsep_send_commit(struct imsgbuf *ibuf, struct g 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 g 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 g 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 g } 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 **com 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 **com 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;