commit - 442a3ddc59a2c8a06621dd008f5449481939cbc4
commit + bff6ca00c7e620ad075cb7bd1bbb6b3400d0078f
blob - 335f73e9a107a9edecc20e1398b3d4641dbd9111
blob + 2c9c8f8dabffa1ff8cf97e599093f4b2b60e3049
--- include/got_object.h
+++ include/got_object.h
*/
const struct got_error *got_object_blob_read_block(size_t *,
struct got_blob_object *);
+const struct got_error *got_object_commit_add_parent(struct got_commit_object *,
+ const char *);
blob - 156901f0339a8945664abed5e3624a696e2ea8b5
blob + b1af4e2fa5b6fc7b4ebe696d93b8a7697eabff1e
--- lib/got_lib_object.h
+++ lib/got_lib_object.h
#define GOT_BLOB_F_COMPRESSED 0x01
struct got_object_id id;
};
+
+struct got_commit_object *got_object_commit_alloc_partial(void);
blob - a5c748f7f02eb28b36259ccf24769609c6b5986c
blob + 759f198b5a7638bddca19286a8b32d89616ee76e
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
* This sandboxes our own repository parsing code, as well as zlib.
*/
GOT_IMSG_OBJECT,
+ GOT_IMSG_COMMIT,
+ GOT_IMSG_OBJ_ID,
GOT_IMSG_LOOSE_BLOB_OBJECT_REQUEST,
GOT_IMSG_LOOSE_TREE_OBJECT_REQUEST,
- GOT_IMSG_LOOSE_COMMIT_OBJECT_REQUEST,
GOT_IMSG_PACKED_BLOB_OBJECT_REQUEST,
GOT_IMSG_PACKED_TREE_OBJECT_REQUEST,
GOT_IMSG_PACKED_COMMIT_OBJECT_REQUEST,
int ndeltas; /* this many GOT_IMSG_DELTA messages follow */
};
+struct got_imsg_commit_object {
+ uint8_t tree_id[SHA1_DIGEST_STRING_LENGTH];
+ size_t author_len;
+ size_t committer_len;
+ size_t logmsg_len;
+ int nparents;
+
+ /* Followed by author_len + committer_len + logmsg_len data bytes */
+
+ /* Followed by 'nparents' SHA1_DIGEST_STRING_LENGTH length strings */
+
+ /* XXX should use more messages to support very large log messages */
+} __attribute__((__packed__));
+
/* Structure for GOT_IMSG_LOOSE_OBJECT_HEADER_REPLY data. */
struct got_imsg_loose_object_header_reply {
struct got_imsg_object iobj;
struct got_object *, int);
const struct got_error *got_privsep_recv_obj(struct got_object **,
struct imsgbuf *);
+const struct got_error *got_privsep_send_commit_obj(struct imsgbuf *,
+ struct got_commit_object *);
+const struct got_error *got_privsep_recv_commit_obj(struct got_commit_object **,
+ struct imsgbuf *);
/* TODO: Implement the above, and then add more message data types here. */
blob - a15d50d62d95d0e10c63f8d28e1476962f80fe09
blob + 0e0b9015dba703f4ec09dd0f4fabf42bdffa1fe5
--- lib/object.c
+++ lib/object.c
if (obj->flags & GOT_OBJ_FLAG_PACKED)
free(obj->path_packfile);
free(obj);
+}
+
+struct got_commit_object *
+got_object_commit_alloc_partial(void)
+{
+ struct got_commit_object *commit;
+
+ commit = calloc(1, sizeof(*commit));
+ if (commit == NULL)
+ return NULL;
+ commit->tree_id = calloc(1, sizeof(*commit->tree_id));
+ if (commit->tree_id == NULL) {
+ free(commit);
+ return NULL;
+ }
+
+ SIMPLEQ_INIT(&commit->parent_ids);
+
+ return commit;
+}
+
+const struct got_error *
+got_object_commit_add_parent(struct got_commit_object *commit,
+ const char *id_str)
+{
+ const struct got_error *err = NULL;
+ struct got_parent_id *pid;
+
+ pid = calloc(1, sizeof(*pid));
+ if (pid == NULL)
+ return got_error_from_errno();
+
+ pid->id = calloc(1, sizeof(*pid->id));
+ if (pid->id == NULL) {
+ err = got_error_from_errno();
+ free(pid);
+ return err;
+ }
+
+ if (!got_parse_sha1_digest(pid->id->sha1, id_str)) {
+ err = got_error(GOT_ERR_BAD_OBJ_DATA);
+ free(pid->id);
+ free(pid);
+ return err;
+ }
+
+ SIMPLEQ_INSERT_TAIL(&commit->parent_ids, pid, entry);
+ commit->nparents++;
+
+ return NULL;
}
static const struct got_error *
size_t tlen;
ssize_t remain = (ssize_t)len;
- *commit = calloc(1, sizeof(**commit));
+ *commit = got_object_commit_alloc_partial();
if (*commit == NULL)
return got_error_from_errno();
- (*commit)->tree_id = calloc(1, sizeof(*(*commit)->tree_id));
- if ((*commit)->tree_id == NULL) {
- err = got_error_from_errno();
- free(*commit);
- *commit = NULL;
- return err;
- }
- SIMPLEQ_INIT(&(*commit)->parent_ids);
-
tlen = strlen(GOT_COMMIT_TAG_TREE);
if (strncmp(s, GOT_COMMIT_TAG_TREE, tlen) == 0) {
remain -= tlen;
tlen = strlen(GOT_COMMIT_TAG_PARENT);
while (strncmp(s, GOT_COMMIT_TAG_PARENT, tlen) == 0) {
- struct got_parent_id *pid;
-
remain -= tlen;
if (remain < SHA1_DIGEST_STRING_LENGTH) {
err = got_error(GOT_ERR_BAD_OBJ_DATA);
goto done;
}
-
- pid = calloc(1, sizeof(*pid));
- if (pid == NULL) {
- err = got_error_from_errno();
- goto done;
- }
- pid->id = calloc(1, sizeof(*pid->id));
- if (pid->id == NULL) {
- err = got_error_from_errno();
- free(pid);
- goto done;
- }
s += tlen;
- if (!got_parse_sha1_digest(pid->id->sha1, s)) {
- err = got_error(GOT_ERR_BAD_OBJ_DATA);
- free(pid->id);
- free(pid);
+ err = got_object_commit_add_parent(*commit, s);
+ if (err)
goto done;
- }
- SIMPLEQ_INSERT_TAIL(&(*commit)->parent_ids, pid, entry);
- (*commit)->nparents++;
remain -= SHA1_DIGEST_STRING_LENGTH;
s += SHA1_DIGEST_STRING_LENGTH;
}
static const struct got_error *
-read_commit_object(struct got_commit_object **commit,
- struct got_repository *repo, struct got_object *obj, FILE *f)
+read_commit_object(struct got_commit_object **commit, struct got_object *obj,
+ FILE *f)
{
const struct got_error *err = NULL;
size_t len;
return err;
}
+static void
+read_commit_object_privsep_child(struct got_object *obj, int obj_fd,
+ int imsg_fds[2])
+{
+ const struct got_error *err = NULL;
+ struct got_commit_object *commit = NULL;
+ struct imsgbuf ibuf;
+ FILE *f = NULL;
+ int status = 0;
+
+ setproctitle("got: read commit object");
+ close(imsg_fds[0]);
+ imsg_init(&ibuf, imsg_fds[1]);
+
+ /* revoke access to most system calls */
+ if (pledge("stdio", NULL) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ f = fdopen(obj_fd, "rb");
+ if (f == NULL) {
+ err = got_error_from_errno();
+ close(obj_fd);
+ goto done;
+ }
+
+ err = read_commit_object(&commit, obj, f);
+ if (err)
+ goto done;
+
+ err = got_privsep_send_commit_obj(&ibuf, commit);
+done:
+ if (commit)
+ got_object_commit_close(commit);
+ if (err) {
+ got_privsep_send_error(&ibuf, err);
+ status = 1;
+ }
+ if (f)
+ fclose(f);
+ imsg_clear(&ibuf);
+ close(imsg_fds[1]);
+ _exit(status);
+}
+
+static const struct got_error *
+read_commit_object_privsep(struct got_commit_object **commit,
+ struct got_repository *repo, struct got_object *obj, int fd)
+{
+ const struct got_error *err = NULL;
+ struct imsgbuf parent_ibuf;
+ int imsg_fds[2];
+ pid_t pid;
+ int child_status;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
+ return got_error_from_errno();
+
+ pid = fork();
+ if (pid == -1)
+ return got_error_from_errno();
+ else if (pid == 0) {
+ read_commit_object_privsep_child(obj, fd, imsg_fds);
+ /* no reached */
+ }
+
+ close(imsg_fds[1]);
+ imsg_init(&parent_ibuf, imsg_fds[0]);
+ err = got_privsep_recv_commit_obj(commit, &parent_ibuf);
+ imsg_clear(&parent_ibuf);
+ waitpid(pid, &child_status, 0);
+ close(imsg_fds[0]);
+ return err;
+}
+
const struct got_error *
got_object_commit_open(struct got_commit_object **commit,
struct got_repository *repo, struct got_object *obj)
err = parse_commit_object(commit, buf, len);
free(buf);
} else {
- FILE *f;
int fd;
err = open_loose_object(&fd, obj, repo);
if (err)
return err;
- f = fdopen(fd, "rb");
- if (f == NULL) {
- err = got_error_from_errno();
- close(fd);
- return err;
- }
- err = read_commit_object(commit, repo, obj, f);
- fclose(f);
+ err = read_commit_object_privsep(commit, repo, obj, fd);
+ close(fd);
}
return err;
}
blob - 594cb27dab416cae4a30c676973c016061734800
blob + 31052e7015a354e8d691abe2926d7363bc157d85
--- lib/privsep.c
+++ lib/privsep.c
(*obj)->size = iobj.size;
for (i = 0; i < iobj.ndeltas; i++) {
/* TODO: Handle deltas */
+ }
+ break;
+ default:
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ break;
+ }
+
+ imsg_free(&imsg);
+
+ return err;
+}
+
+const struct got_error *
+got_privsep_send_commit_obj(struct imsgbuf *ibuf, struct got_commit_object *commit)
+{
+ const struct got_error *err = NULL;
+ struct got_imsg_commit_object icommit;
+ uint8_t *buf;
+ size_t len, total;
+ struct got_parent_id *pid;
+
+ if (got_sha1_digest_to_str(commit->tree_id->sha1, icommit.tree_id,
+ sizeof(icommit.tree_id)) == NULL)
+ return got_error(GOT_ERR_BAD_OBJ_ID_STR);
+ icommit.author_len = strlen(commit->author);
+ icommit.committer_len = strlen(commit->committer);
+ icommit.logmsg_len = strlen(commit->logmsg);
+ icommit.nparents = commit->nparents;
+
+ total = sizeof(icommit) + icommit.author_len +
+ icommit.committer_len + icommit.logmsg_len +
+ icommit.nparents * (SHA1_DIGEST_STRING_LENGTH);
+ /* XXX TODO support very large log messages properly */
+ if (total > MAX_IMSGSIZE)
+ return got_error(GOT_ERR_NO_SPACE);
+
+ buf = malloc(total);
+ if (buf == NULL)
+ return got_error_from_errno();
+
+ len = 0;
+ memcpy(buf + len, &icommit, sizeof(icommit));
+ len += sizeof(icommit);
+ memcpy(buf + len, commit->author, icommit.author_len);
+ 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(pid, &commit->parent_ids, entry) {
+ char id_str[SHA1_DIGEST_STRING_LENGTH];
+ if (got_sha1_digest_to_str(pid->id->sha1, id_str,
+ sizeof(id_str)) == NULL) {
+ err = got_error(GOT_ERR_BAD_OBJ_ID_STR);
+ goto done;
+ }
+ memcpy(buf + len, id_str, SHA1_DIGEST_STRING_LENGTH);
+ len += SHA1_DIGEST_STRING_LENGTH;
+ }
+
+ if (imsg_compose(ibuf, GOT_IMSG_COMMIT, 0, 0, -1, buf, len) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ err = poll_fd(ibuf->fd, POLLOUT, INFTIM);
+ if (err)
+ goto done;
+
+ if (imsg_flush(ibuf) == -1) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+done:
+ free(buf);
+ return err;
+}
+const struct got_error *
+got_privsep_recv_commit_obj(struct got_commit_object **commit,
+ struct imsgbuf *ibuf)
+{
+ const struct got_error *err = NULL;
+ struct imsg imsg;
+ struct got_imsg_commit_object icommit;
+ size_t len, datalen;
+ int i;
+ const size_t min_datalen =
+ MIN(sizeof(struct got_imsg_error),
+ sizeof(struct got_imsg_commit_object));
+ uint8_t *data;
+
+ *commit = NULL;
+
+ err = recv_one_imsg(&imsg, ibuf, min_datalen);
+ if (err)
+ return err;
+
+ data = imsg.data;
+ datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ len = 0;
+
+ switch (imsg.hdr.type) {
+ case GOT_IMSG_ERROR:
+ err = recv_imsg_error(&imsg, datalen);
+ break;
+ case GOT_IMSG_COMMIT:
+ if (datalen < sizeof(icommit)) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ break;
}
+
+ memcpy(&icommit, data, sizeof(icommit));
+ if (datalen != sizeof(icommit) + icommit.author_len +
+ icommit.committer_len + icommit.logmsg_len +
+ icommit.nparents * (SHA1_DIGEST_STRING_LENGTH)) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ break;
+ }
+ if (icommit.nparents < 0) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ break;
+ }
+ len += sizeof(icommit);
+
+ *commit = got_object_commit_alloc_partial();
+ if (*commit == NULL) {
+ err = got_error_from_errno();
+ break;
+ }
+
+ if (!got_parse_sha1_digest((*commit)->tree_id->sha1,
+ icommit.tree_id)) {
+ err = got_error(GOT_ERR_BAD_OBJ_DATA);
+ break;
+ }
+
+ if (icommit.author_len == 0) {
+ (*commit)->author = strdup("");
+ if ((*commit)->author == NULL) {
+ err = got_error_from_errno();
+ break;
+ }
+ } else {
+ (*commit)->author = malloc(icommit.author_len + 1);
+ if ((*commit)->author == NULL) {
+ err = got_error_from_errno();
+ break;
+ }
+ memcpy((*commit)->author, data + len,
+ icommit.author_len);
+ (*commit)->author[icommit.author_len] = '\0';
+ }
+ len += icommit.author_len;
+
+ if (icommit.committer_len == 0) {
+ (*commit)->committer = strdup("");
+ if ((*commit)->committer == NULL) {
+ err = got_error_from_errno();
+ break;
+ }
+ } else {
+ (*commit)->committer =
+ malloc(icommit.committer_len + 1);
+ if ((*commit)->committer == NULL) {
+ err = got_error_from_errno();
+ break;
+ }
+ memcpy((*commit)->committer, data + len,
+ icommit.committer_len);
+ (*commit)->committer[icommit.committer_len] = '\0';
+ }
+ len += icommit.committer_len;
+
+ if (icommit.logmsg_len == 0) {
+ (*commit)->logmsg = strdup("");
+ if ((*commit)->logmsg == NULL) {
+ err = got_error_from_errno();
+ break;
+ }
+ } else {
+ (*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);
+ (*commit)->logmsg[icommit.logmsg_len] = '\0';
+ }
+ len += icommit.logmsg_len;
+
+ for (i = 0; i < icommit.nparents; i++) {
+ char id_str[SHA1_DIGEST_STRING_LENGTH];
+ memcpy(id_str, data + len +
+ i * SHA1_DIGEST_STRING_LENGTH, sizeof(id_str));
+ id_str[SHA1_DIGEST_STRING_LENGTH - 1] = '\0';
+ err = got_object_commit_add_parent(*commit, id_str);
+ if (err)
+ break;
+ }
break;
default:
err = got_error(GOT_ERR_PRIVSEP_MSG);