commit 59d1e4a0a9c19debc27746357d97084b59a76db8 from: Stefan Sperling date: Wed Mar 10 22:49:22 2021 UTC implement raw object data access; this will be required for packing commit - 8704c7cea5c81c45015529a58461bf8b49f9c4d9 commit + 59d1e4a0a9c19debc27746357d97084b59a76db8 blob - 989af7a5c391e8d6a066b2235aecd6c3246aa0d3 blob + 44f8ac073b1d120169e3ef344f1caca1022da938 --- lib/got_lib_object.h +++ lib/got_lib_object.h @@ -35,6 +35,15 @@ struct got_object { int refcnt; /* > 0 if open and/or cached */ }; +struct got_raw_object { + FILE *f; + uint8_t *data; + off_t size; + size_t hdrlen; + size_t blocksize; + uint8_t *read_buf; +}; + struct got_commit_object { struct got_object_id *tree_id; unsigned int nparents; @@ -91,6 +100,14 @@ const struct got_error *got_object_get_path(char **, s struct got_repository *); const struct got_error *got_object_open(struct got_object **, struct got_repository *, struct got_object_id *); +const struct got_error *got_object_raw_open(struct got_raw_object **, + struct got_repository *, struct got_object_id *, size_t); +void got_object_raw_rewind(struct got_raw_object *); +size_t got_object_raw_get_hdrlen(struct got_raw_object *); +const uint8_t *got_object_raw_get_read_buf(struct got_raw_object *); +const struct got_error * got_object_raw_read_block(size_t *, + struct got_raw_object *); +const struct got_error *got_object_raw_close(struct got_raw_object *); const struct got_error *got_object_open_by_id_str(struct got_object **, struct got_repository *, const char *); void got_object_close(struct got_object *); blob - 8dbb8d0ba06da245e90c69b5db067658d496e0b0 blob + dc1687fd0232a98260fd1d1f91425364de21521b --- lib/got_lib_privsep.h +++ lib/got_lib_privsep.h @@ -160,6 +160,12 @@ enum got_imsg_type { GOT_IMSG_GOTCONFIG_STR_VAL, GOT_IMSG_GOTCONFIG_REMOTES, GOT_IMSG_GOTCONFIG_REMOTE, + + /* Raw object access. Uncompress object data but do not parse it. */ + GOT_IMSG_RAW_OBJECT_REQUEST, + GOT_IMSG_RAW_OBJECT_OUTFD, + GOT_IMSG_PACKED_RAW_OBJECT_REQUEST, + GOT_IMSG_RAW_OBJECT, }; /* Structure for GOT_IMSG_ERROR. */ @@ -234,6 +240,19 @@ struct got_imsg_blob { (MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof(struct got_imsg_blob)) }; +/* Structure for GOT_IMSG_RAW_OBJECT. */ +struct got_imsg_raw_obj { + off_t size; + size_t hdrlen; + + /* + * If size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX, object data follows + * in the imsg buffer. Otherwise, object data has been written to a + * file descriptor passed via the GOT_IMSG_RAW_OBJECT_OUTFD imsg. + */ +#define GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX \ + (MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof(struct got_imsg_raw_obj)) +}; /* Structure for GOT_IMSG_TAG data. */ struct got_imsg_tag_object { @@ -350,7 +369,8 @@ struct got_imsg_pack { } __attribute__((__packed__)); /* - * Structure for GOT_IMSG_PACKED_OBJECT_REQUEST data. + * Structure for GOT_IMSG_PACKED_OBJECT_REQUEST and + * GOT_IMSG_PACKED_RAW_OBJECT_REQUEST data. */ struct got_imsg_packed_object { uint8_t id[SHA1_DIGEST_LENGTH]; @@ -409,6 +429,8 @@ void got_privsep_send_error(struct imsgbuf *, const st const struct got_error *got_privsep_send_ack(struct imsgbuf *); const struct got_error *got_privsep_wait_ack(struct imsgbuf *); const struct got_error *got_privsep_send_obj_req(struct imsgbuf *, int); +const struct got_error *got_privsep_send_raw_obj_req(struct imsgbuf *, int); +const struct got_error *got_privsep_send_raw_obj_outfd(struct imsgbuf *, int); const struct got_error *got_privsep_send_commit_req(struct imsgbuf *, int, struct got_object_id *, int); const struct got_error *got_privsep_send_tree_req(struct imsgbuf *, int, @@ -438,6 +460,10 @@ const struct got_error *got_privsep_get_imsg_obj(struc struct imsg *, struct imsgbuf *); const struct got_error *got_privsep_recv_obj(struct got_object **, struct imsgbuf *); +const struct got_error *got_privsep_send_raw_obj(struct imsgbuf *, off_t, + size_t, uint8_t *); +const struct got_error *got_privsep_recv_raw_obj(uint8_t **, off_t *, size_t *, + struct imsgbuf *); const struct got_error *got_privsep_send_commit(struct imsgbuf *, struct got_commit_object *); const struct got_error *got_privsep_recv_commit(struct got_commit_object **, @@ -458,6 +484,8 @@ const struct got_error *got_privsep_init_pack_child(st struct got_pack *, struct got_packidx *); const struct got_error *got_privsep_send_packed_obj_req(struct imsgbuf *, int, struct got_object_id *); +const struct got_error *got_privsep_send_packed_raw_obj_req(struct imsgbuf *, + int, struct got_object_id *); const struct got_error *got_privsep_send_pack_child_ready(struct imsgbuf *); const struct got_error *got_privsep_send_gitconfig_parse_req(struct imsgbuf *, blob - b85e7651429752168e6f8eff2b764fe8bba2d501 blob + 7f6e445581c8690ccc1c4cc83d42a1ce5959a605 --- lib/object.c +++ lib/object.c @@ -190,6 +190,68 @@ request_packed_object(struct got_object **obj, struct return NULL; } +static const struct got_error * +request_packed_object_raw(uint8_t **outbuf, off_t *size, size_t *hdrlen, + int outfd, struct got_pack *pack, int idx, struct got_object_id *id) +{ + const struct got_error *err = NULL; + struct imsgbuf *ibuf = pack->privsep_child->ibuf; + int outfd_child; + int basefd, accumfd; /* temporary files for delta application */ + + basefd = got_opentempfd(); + if (basefd == -1) + return got_error_from_errno("got_opentempfd"); + + accumfd = got_opentempfd(); + if (accumfd == -1) { + close(basefd); + return got_error_from_errno("got_opentempfd"); + } + + outfd_child = dup(outfd); + if (outfd_child == -1) { + err = got_error_from_errno("dup"); + close(basefd); + close(accumfd); + return err; + } + + err = got_privsep_send_packed_raw_obj_req(ibuf, idx, id); + if (err) { + close(basefd); + close(accumfd); + close(outfd_child); + return err; + } + + err = got_privsep_send_raw_obj_outfd(ibuf, outfd_child); + if (err) { + close(basefd); + close(accumfd); + return err; + } + + + err = got_privsep_send_tmpfd(pack->privsep_child->ibuf, + basefd); + if (err) { + close(accumfd); + return err; + } + + err = got_privsep_send_tmpfd(pack->privsep_child->ibuf, + accumfd); + if (err) + return err; + + err = got_privsep_recv_raw_obj(outbuf, size, hdrlen, ibuf); + if (err) + return err; + + return NULL; +} + static void set_max_datasize(void) { @@ -269,17 +331,32 @@ read_packed_object_privsep(struct got_object **obj, { const struct got_error *err = NULL; - if (pack->privsep_child) - return request_packed_object(obj, pack, idx, id); + if (pack->privsep_child == NULL) { + err = start_pack_privsep_child(pack, packidx); + if (err) + return err; + } - err = start_pack_privsep_child(pack, packidx); - if (err) - return err; - return request_packed_object(obj, pack, idx, id); } +static const struct got_error * +read_packed_object_raw_privsep(uint8_t **outbuf, off_t *size, size_t *hdrlen, + int outfd, struct got_pack *pack, struct got_packidx *packidx, int idx, + struct got_object_id *id) +{ + const struct got_error *err = NULL; + if (pack->privsep_child == NULL) { + err = start_pack_privsep_child(pack, packidx); + if (err) + return err; + } + + return request_packed_object_raw(outbuf, size, hdrlen, outfd, pack, + idx, id); +} + static const struct got_error * open_packed_object(struct got_object **obj, struct got_object_id *id, struct got_repository *repo) @@ -329,17 +406,38 @@ request_object(struct got_object **obj, struct got_rep } static const struct got_error * -read_object_header_privsep(struct got_object **obj, struct got_repository *repo, - int obj_fd) +request_raw_object(uint8_t **outbuf, off_t *size, size_t *hdrlen, int outfd, + struct got_repository *repo, int infd) { - const struct got_error *err; + const struct got_error *err = NULL; + struct imsgbuf *ibuf; + int outfd_child; + + ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf; + + outfd_child = dup(outfd); + if (outfd_child == -1) + return got_error_from_errno("dup"); + + err = got_privsep_send_raw_obj_req(ibuf, infd); + if (err) + return err; + + err = got_privsep_send_raw_obj_outfd(ibuf, outfd_child); + if (err) + return err; + + return got_privsep_recv_raw_obj(outbuf, size, hdrlen, ibuf); +} + +static const struct got_error * +start_read_object_child(struct got_repository *repo) +{ + const struct got_error *err = NULL; int imsg_fds[2]; pid_t pid; struct imsgbuf *ibuf; - if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1) - return request_object(obj, repo, obj_fd); - ibuf = calloc(1, sizeof(*ibuf)); if (ibuf == NULL) return got_error_from_errno("calloc"); @@ -367,15 +465,48 @@ read_object_header_privsep(struct got_object **obj, st free(ibuf); return err; } + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd = imsg_fds[0]; repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].pid = pid; imsg_init(ibuf, imsg_fds[0]); repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf = ibuf; + return NULL; +} + +static const struct got_error * +read_object_header_privsep(struct got_object **obj, struct got_repository *repo, + int obj_fd) +{ + const struct got_error *err; + + if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1) + return request_object(obj, repo, obj_fd); + + err = start_read_object_child(repo); + if (err) + return err; + return request_object(obj, repo, obj_fd); } +static const struct got_error * +read_object_raw_privsep(uint8_t **outbuf, off_t *size, size_t *hdrlen, + int outfd, struct got_repository *repo, int obj_fd) +{ + const struct got_error *err; + + if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1) + return request_raw_object(outbuf, size, hdrlen, outfd, repo, + obj_fd); + + err = start_read_object_child(repo); + if (err) + return err; + + return request_raw_object(outbuf, size, hdrlen, outfd, repo, obj_fd); +} const struct got_error * got_object_open(struct got_object **obj, struct got_repository *repo, @@ -422,9 +553,164 @@ got_object_open(struct got_object **obj, struct got_re done: free(path); return err; +} +const struct got_error * +got_object_raw_open(struct got_raw_object **obj, struct got_repository *repo, + struct got_object_id *id, size_t blocksize) +{ + const struct got_error *err = NULL; + struct got_packidx *packidx = NULL; + int idx; + uint8_t *outbuf = NULL; + int outfd = -1; + off_t size = 0; + size_t hdrlen = 0; + char *path_packfile = NULL; + + *obj = NULL; + + outfd = got_opentempfd(); + if (outfd == -1) + return got_error_from_errno("got_opentempfd"); + + err = got_repo_search_packidx(&packidx, &idx, repo, id); + if (err == NULL) { + struct got_pack *pack = NULL; + + err = get_packfile_path(&path_packfile, packidx); + if (err) + goto done; + + pack = got_repo_get_cached_pack(repo, path_packfile); + if (pack == NULL) { + err = got_repo_cache_pack(&pack, repo, path_packfile, + packidx); + if (err) + goto done; + } + err = read_packed_object_raw_privsep(&outbuf, &size, &hdrlen, + outfd, pack, packidx, idx, id); + } else if (err->code == GOT_ERR_NO_OBJ) { + int fd; + + err = open_loose_object(&fd, id, repo); + if (err) + goto done; + err = read_object_raw_privsep(&outbuf, &size, &hdrlen, outfd, + repo, fd); + } + + if (hdrlen > size) { + err = got_error(GOT_ERR_BAD_OBJ_HDR); + goto done; + } + + *obj = calloc(1, sizeof(**obj)); + if (*obj == NULL) { + err = got_error_from_errno("calloc"); + goto done; + } + + (*obj)->read_buf = malloc(blocksize); + if ((*obj)->read_buf == NULL) { + err = got_error_from_errno("malloc"); + goto done; + } + + if (outbuf) { + if (close(outfd) == -1) { + err = got_error_from_errno("close"); + goto done; + } + outfd = -1; + (*obj)->f = fmemopen(outbuf, hdrlen + size, "r"); + if ((*obj)->f == NULL) { + err = got_error_from_errno("fdopen"); + goto done; + } + (*obj)->data = outbuf; + } else { + struct stat sb; + if (fstat(outfd, &sb) == -1) { + err = got_error_from_errno("fstat"); + goto done; + } + + if (sb.st_size != size) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + + (*obj)->f = fdopen(outfd, "r"); + if ((*obj)->f == NULL) { + err = got_error_from_errno("fdopen"); + goto done; + } + outfd = -1; + (*obj)->data = NULL; + } + (*obj)->hdrlen = hdrlen; + (*obj)->size = size; + (*obj)->blocksize = blocksize; +done: + free(path_packfile); + if (err) { + if (*obj) { + got_object_raw_close(*obj); + *obj = NULL; + } + if (outfd != -1) + close(outfd); + free(outbuf); + } + return err; } +void +got_object_raw_rewind(struct got_raw_object *obj) +{ + if (obj->f) + rewind(obj->f); +} + +size_t +got_object_raw_get_hdrlen(struct got_raw_object *obj) +{ + return obj->hdrlen; +} + +const uint8_t * +got_object_raw_get_read_buf(struct got_raw_object *obj) +{ + return obj->read_buf; +} + +const struct got_error * +got_object_raw_read_block(size_t *outlenp, struct got_raw_object *obj) +{ + size_t n; + + n = fread(obj->read_buf, 1, obj->blocksize, obj->f); + if (n == 0 && ferror(obj->f)) + return got_ferror(obj->f, GOT_ERR_IO); + *outlenp = n; + return NULL; +} + +const struct got_error * +got_object_raw_close(struct got_raw_object *obj) +{ + const struct got_error *err = NULL; + + free(obj->read_buf); + if (obj->f != NULL && fclose(obj->f) == EOF && err == NULL) + err = got_error_from_errno("fclose"); + free(obj->data); + free(obj); + return err; +} + const struct got_error * got_object_open_by_id_str(struct got_object **obj, struct got_repository *repo, const char *id_str) blob - 2a8fcc8c9e2afd1ce22356056ac095e73d2c28c3 blob + df3a4a17cfe53a165183f57fb4a0eebe62acab91 --- lib/privsep.c +++ lib/privsep.c @@ -244,11 +244,131 @@ got_privsep_send_obj_req(struct imsgbuf *ibuf, int fd) if (imsg_compose(ibuf, GOT_IMSG_OBJECT_REQUEST, 0, 0, fd, NULL, 0) == -1) return got_error_from_errno("imsg_compose OBJECT_REQUEST"); + + return flush_imsg(ibuf); +} + +const struct got_error * +got_privsep_send_raw_obj_req(struct imsgbuf *ibuf, int fd) +{ + if (imsg_compose(ibuf, GOT_IMSG_RAW_OBJECT_REQUEST, 0, 0, fd, NULL, 0) + == -1) + return got_error_from_errno("imsg_compose RAW_OBJECT_REQUEST"); + + return flush_imsg(ibuf); +} + +const struct got_error * +got_privsep_send_raw_obj_outfd(struct imsgbuf *ibuf, int outfd) +{ + const struct got_error *err = NULL; + + if (imsg_compose(ibuf, GOT_IMSG_RAW_OBJECT_OUTFD, 0, 0, outfd, NULL, 0) + == -1) { + err = got_error_from_errno("imsg_compose RAW_OBJECT_OUTFD"); + close(outfd); + return err; + } + + return flush_imsg(ibuf); +} + +const struct got_error * +got_privsep_send_raw_obj(struct imsgbuf *ibuf, off_t size, size_t hdrlen, + uint8_t *data) +{ + const struct got_error *err = NULL; + struct got_imsg_raw_obj iobj; + size_t len = sizeof(iobj); + struct ibuf *wbuf; + iobj.hdrlen = hdrlen; + iobj.size = size; + + if (data && size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) + len += (size_t)size; + + wbuf = imsg_create(ibuf, GOT_IMSG_RAW_OBJECT, 0, 0, len); + if (wbuf == NULL) { + err = got_error_from_errno("imsg_create RAW_OBJECT"); + return err; + } + + if (imsg_add(wbuf, &iobj, sizeof(iobj)) == -1) { + err = got_error_from_errno("imsg_add RAW_OBJECT"); + ibuf_free(wbuf); + return err; + } + + if (data && size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) { + if (imsg_add(wbuf, data, size) == -1) { + err = got_error_from_errno("imsg_add RAW_OBJECT"); + ibuf_free(wbuf); + return err; + } + } + + wbuf->fd = -1; + imsg_close(ibuf, wbuf); + return flush_imsg(ibuf); } const struct got_error * +got_privsep_recv_raw_obj(uint8_t **outbuf, off_t *size, size_t *hdrlen, + struct imsgbuf *ibuf) +{ + const struct got_error *err = NULL; + struct imsg imsg; + struct got_imsg_raw_obj *iobj; + size_t datalen; + + *outbuf = NULL; + + 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_RAW_OBJECT: + if (datalen < sizeof(*iobj)) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + break; + } + iobj = imsg.data; + *size = iobj->size; + *hdrlen = iobj->hdrlen; + + if (datalen == sizeof(*iobj)) { + /* Data has been written to file descriptor. */ + break; + } + + if (*size > GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + break; + } + + *outbuf = malloc(*size); + if (*outbuf == NULL) { + err = got_error_from_errno("malloc"); + break; + } + memcpy(*outbuf, imsg.data + sizeof(*iobj), *size); + break; + default: + err = got_error(GOT_ERR_PRIVSEP_MSG); + break; + } + + imsg_free(&imsg); + + return err; +} + +const struct got_error * got_privsep_send_commit_req(struct imsgbuf *ibuf, int fd, struct got_object_id *id, int pack_idx) { @@ -1644,6 +1764,23 @@ got_privsep_send_packed_obj_req(struct imsgbuf *ibuf, } const struct got_error * +got_privsep_send_packed_raw_obj_req(struct imsgbuf *ibuf, int idx, + struct got_object_id *id) +{ + struct got_imsg_packed_object iobj; + + iobj.idx = idx; + memcpy(iobj.id, id->sha1, sizeof(iobj.id)); + + if (imsg_compose(ibuf, GOT_IMSG_PACKED_RAW_OBJECT_REQUEST, 0, 0, -1, + &iobj, sizeof(iobj)) == -1) + return got_error_from_errno("imsg_compose " + "PACKED_OBJECT_REQUEST"); + + return flush_imsg(ibuf); +} + +const struct got_error * got_privsep_send_gitconfig_parse_req(struct imsgbuf *ibuf, int fd) { const struct got_error *err = NULL; blob - 96f238defd60d0d973d36d4b4e6c4a60845cefa6 blob + 1d8cea7e965300fd88bff54f9fcfd727a5a12b7c --- libexec/got-read-object/got-read-object.c +++ libexec/got-read-object/got-read-object.c @@ -56,6 +56,49 @@ catch_sigint(int signo) sigint_received = 1; } +static const struct got_error * +send_raw_obj(struct imsgbuf *ibuf, struct got_object *obj, int fd, int outfd) +{ + const struct got_error *err = NULL; + uint8_t *data = NULL; + size_t len = 0, consumed; + FILE *f; + + if (lseek(fd, SEEK_SET, 0) == -1) { + err = got_error_from_errno("lseek"); + close(fd); + return err; + } + + f = fdopen(fd, "r"); + if (f == NULL) { + err = got_error_from_errno("fdopen"); + close(fd); + return err; + } + + if (obj->size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) + err = got_inflate_to_mem(&data, &len, &consumed, f); + else + err = got_inflate_to_fd(&len, f, outfd); + if (err) + goto done; + + if (len < obj->hdrlen || len != obj->hdrlen + obj->size) { + fprintf(stderr, "len=%zd obj->hdrlen=%zd obj->size=%zd\n", len, obj->hdrlen, obj->size); + err = got_error(GOT_ERR_BAD_OBJ_HDR); + goto done; + } + + err = got_privsep_send_raw_obj(ibuf, len, obj->hdrlen, data); +done: + free(data); + if (fclose(f) == EOF && err == NULL) + err = got_error_from_errno("fclose"); + + return err; +} + int main(int argc, char *argv[]) { @@ -94,7 +137,8 @@ main(int argc, char *argv[]) if (imsg.hdr.type == GOT_IMSG_STOP) break; - if (imsg.hdr.type != GOT_IMSG_OBJECT_REQUEST) { + if (imsg.hdr.type != GOT_IMSG_OBJECT_REQUEST && + imsg.hdr.type != GOT_IMSG_RAW_OBJECT_REQUEST) { err = got_error(GOT_ERR_PRIVSEP_MSG); goto done; } @@ -105,13 +149,55 @@ main(int argc, char *argv[]) goto done; } + if (imsg.fd == -1) { + err = got_error(GOT_ERR_PRIVSEP_NO_FD); + goto done; + } + err = got_object_read_header(&obj, imsg.fd); if (err) goto done; - err = got_privsep_send_obj(&ibuf, obj); + if (imsg.hdr.type == GOT_IMSG_RAW_OBJECT_REQUEST) { + struct imsg imsg_outfd; + err = got_privsep_recv_imsg(&imsg_outfd, &ibuf, 0); + if (err) { + if (imsg_outfd.hdr.len == 0) + err = NULL; + goto done; + } + + if (imsg_outfd.hdr.type == GOT_IMSG_STOP) { + imsg_free(&imsg_outfd); + goto done; + } + + if (imsg_outfd.hdr.type != GOT_IMSG_RAW_OBJECT_OUTFD) { + err = got_error(GOT_ERR_PRIVSEP_MSG); + imsg_free(&imsg_outfd); + goto done; + } + + datalen = imsg_outfd.hdr.len - IMSG_HEADER_SIZE; + if (datalen != 0) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + imsg_free(&imsg_outfd); + goto done; + } + if (imsg_outfd.fd == -1) { + err = got_error(GOT_ERR_PRIVSEP_NO_FD); + imsg_free(&imsg_outfd); + goto done; + } + err = send_raw_obj(&ibuf, obj, imsg.fd, imsg_outfd.fd); + imsg.fd = -1; /* imsg.fd is owned by send_raw_obj() */ + imsg_free(&imsg_outfd); + if (err) + goto done; + } else + err = got_privsep_send_obj(&ibuf, obj); done: - if (close(imsg.fd) == -1 && err == NULL) + if (imsg.fd != -1 && close(imsg.fd) == -1 && err == NULL) err = got_error_from_errno("close"); imsg_free(&imsg); if (obj) blob - dd8568736e94cba3323acae81feb8506fe869f9f blob + 30756b439f8433c9f8b8f391bd93db8ddd6feb9f --- libexec/got-read-pack/got-read-pack.c +++ libexec/got-read-pack/got-read-pack.c @@ -773,6 +773,79 @@ done: } static const struct got_error * +raw_object_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack, + struct got_packidx *packidx, struct got_object_cache *objcache) +{ + const struct got_error *err = NULL; + uint8_t *buf = NULL; + uint64_t size = 0; + FILE *outfile = NULL, *basefile = NULL, *accumfile = NULL; + struct got_imsg_packed_object iobj; + struct got_object *obj; + struct got_object_id id; + size_t datalen; + + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + if (datalen != sizeof(iobj)) + return got_error(GOT_ERR_PRIVSEP_LEN); + memcpy(&iobj, imsg->data, sizeof(iobj)); + memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH); + + obj = got_object_cache_get(objcache, &id); + if (obj) { + obj->refcnt++; + } else { + err = open_object(&obj, pack, packidx, iobj.idx, &id, + objcache); + if (err) + return err; + } + + err = receive_file(&outfile, ibuf, GOT_IMSG_RAW_OBJECT_OUTFD); + if (err) + return err; + err = receive_file(&basefile, ibuf, GOT_IMSG_TMPFD); + if (err) + goto done; + err = receive_file(&accumfile, ibuf, GOT_IMSG_TMPFD); + if (err) + goto done; + + if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) { + err = got_pack_get_max_delta_object_size(&size, obj, pack); + if (err) + goto done; + } else + size = obj->size; + + if (size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX) + err = got_packfile_extract_object_to_mem(&buf, &obj->size, + obj, pack); + else + err = got_packfile_extract_object(pack, obj, outfile, basefile, + accumfile); + if (err) + goto done; + + err = got_privsep_send_raw_obj(ibuf, size, obj->hdrlen, buf); +done: + free(buf); + if (outfile && fclose(outfile) == EOF && err == NULL) + err = got_error_from_errno("fclose"); + if (basefile && fclose(basefile) == EOF && err == NULL) + err = got_error_from_errno("fclose"); + if (accumfile && fclose(accumfile) == EOF && err == NULL) + err = got_error_from_errno("fclose"); + got_object_close(obj); + if (err && err->code != GOT_ERR_PRIVSEP_PIPE) + got_privsep_send_error(ibuf, err); + + return err; +} + + + +static const struct got_error * receive_packidx(struct got_packidx **packidx, struct imsgbuf *ibuf) { const struct got_error *err = NULL; @@ -984,6 +1057,10 @@ main(int argc, char *argv[]) err = object_request(&imsg, &ibuf, pack, packidx, &objcache); break; + case GOT_IMSG_PACKED_RAW_OBJECT_REQUEST: + err = raw_object_request(&imsg, &ibuf, pack, packidx, + &objcache); + break; case GOT_IMSG_COMMIT_REQUEST: err = commit_request(&imsg, &ibuf, pack, packidx, &objcache);