commit f4a881ce8b200e5283247799c39abd2b578b8e75 from: Stefan Sperling date: Sat Nov 17 15:04:05 2018 UTC more support for tag objects; new code is not yet reachable commit - c945ec50da8b849eeb8e82b3836fc106bc041419 commit + f4a881ce8b200e5283247799c39abd2b578b8e75 blob - 6ba2563737d96877e4e57392d5dd8bef4a272705 blob + c24e7e0fd473d1327a88bc5c25fd0ed0963c815e --- include/got_object.h +++ include/got_object.h @@ -18,6 +18,7 @@ struct got_object_id; struct got_blob_object; struct got_tree_object; +struct got_tag_object; struct got_tree_entry { SIMPLEQ_ENTRY(got_tree_entry) entry; @@ -224,6 +225,17 @@ const struct got_error *got_object_blob_read_block(siz const struct got_error *got_object_blob_dump_to_file(size_t *, size_t *, FILE *, struct got_blob_object *); +/* + * Attempt to open a tag object in a repository. + * The provided object must be of type GOT_OBJ_TYPE_TAG. + * The caller must dispose of the tree with got_object_tag_close(). + */ +const struct got_error *got_object_tag_open(struct got_tag_object **, + struct got_repository *, struct got_object *); + +/* Dispose of a tag object. */ +void got_object_tag_close(struct got_tag_object *); + const struct got_error * got_object_open_as_commit(struct got_commit_object **, struct got_repository *, struct got_object_id *); @@ -233,6 +245,8 @@ got_object_open_as_tree(struct got_tree_object **, const struct got_error * got_object_open_as_blob(struct got_blob_object **, struct got_repository *, struct got_object_id *, size_t); +const struct got_error *got_object_open_as_tag(struct got_tag_object **, + struct got_repository *, struct got_object_id *); const struct got_error *got_object_commit_add_parent(struct got_commit_object *, const char *); blob - fc8b2eef010a4a07760e360d7e9102d16791ddbd blob + c2619193e47de7f03830953b4c47623aafbbd7fb --- lib/got_lib_object.h +++ lib/got_lib_object.h @@ -48,3 +48,14 @@ struct got_blob_object { uint8_t *read_buf; struct got_object_id id; }; + +struct got_tag_object { + struct got_object_id id; + int obj_type; + char *tag; + time_t tagger_time; + time_t tagger_gmtoff; + char *tagger; + char *tagmsg; + int refcnt; /* > 0 if open and/or cached */ +}; blob - 067f6f0703d20cfe605969655056f62b9b24771b blob + a10ff39474235e35fee9cc7454d03acf7f84bb72 --- lib/got_lib_object_cache.h +++ lib/got_lib_object_cache.h @@ -18,6 +18,7 @@ enum got_object_cache_type { GOT_OBJECT_CACHE_TYPE_OBJ, GOT_OBJECT_CACHE_TYPE_TREE, GOT_OBJECT_CACHE_TYPE_COMMIT, + GOT_OBJECT_CACHE_TYPE_TAG, }; struct got_object_cache_entry { @@ -26,6 +27,7 @@ struct got_object_cache_entry { struct got_object *obj; struct got_tree_object *tree; struct got_commit_object *commit; + struct got_tag_object *tag; } data; }; blob - f53705294442da0455ee9f988a17bdd3966aaf58 blob + dcc76200ee994833fb286f365a9b936071eb118e --- lib/got_lib_object_parse.h +++ lib/got_lib_object_parse.h @@ -26,11 +26,15 @@ const struct got_error *got_object_read_commit_privsep struct got_repository *); const struct got_error *got_object_read_tree_privsep(struct got_tree_object **, struct got_object *, int, struct got_repository *); +const struct got_error *got_object_read_tag_privsep(struct got_tag_object **, + struct got_object *, int, struct got_repository *); const struct got_error *got_object_parse_commit(struct got_commit_object **, char *, size_t); const struct got_error *got_object_parse_tree(struct got_tree_object **, uint8_t *, size_t); +const struct got_error *got_object_parse_tag(struct got_tag_object **, + uint8_t *, size_t); const struct got_error *got_read_file_to_mem(uint8_t **, size_t *, FILE *); void got_object_tree_entry_close(struct got_tree_entry *); @@ -45,3 +49,5 @@ const struct got_error *got_object_read_packed_commit_ struct got_commit_object **, struct got_object *, struct got_pack *); const struct got_error *got_object_read_packed_tree_privsep( struct got_tree_object **, struct got_object *, struct got_pack *); +const struct got_error *got_object_read_packed_tag_privsep( + struct got_tag_object **, struct got_object *, struct got_pack *); blob - a396e2c12db9ff8b8e8881e7c68a292bbab832e0 blob + 871454f5b88c501bfe8560503f16b0d734fafba9 --- lib/got_lib_privsep.h +++ lib/got_lib_privsep.h @@ -39,6 +39,7 @@ #define GOT_PROG_READ_TREE got-read-tree #define GOT_PROG_READ_COMMIT got-read-commit #define GOT_PROG_READ_BLOB got-read-blob +#define GOT_PROG_READ_TAG got-read-tag #define GOT_PROG_READ_PACK got-read-pack #define GOT_STRINGIFY(x) #x @@ -53,6 +54,8 @@ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_COMMIT) #define GOT_PATH_PROG_READ_BLOB \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_BLOB) +#define GOT_PATH_PROG_READ_TAG \ + GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_TAG) #define GOT_PATH_PROG_READ_PACK \ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_PACK) @@ -88,6 +91,9 @@ enum got_imsg_type { GOT_IMSG_BLOB_REQUEST, GOT_IMSG_BLOB_OUTFD, GOT_IMSG_BLOB, + GOT_IMSG_TAG_REQUEST, + GOT_IMSG_TAG, + GOT_IMSG_TAG_TAGMSG, /* Messages related to pack files. */ GOT_IMSG_PACKIDX, @@ -162,6 +168,26 @@ struct got_imsg_blob { size_t size; }; +/* Structure for GOT_IMSG_TAG data. */ +struct got_imsg_tag_object { + uint8_t id[SHA1_DIGEST_LENGTH]; + int obj_type; + size_t tag_len; + size_t tagger_len; + time_t tagger_time; + time_t tagger_gmtoff; + size_t tagmsg_len; + + /* + * Followed by tag_len + tagger_len data bytes + */ + + /* + * Followed by 'tagmsg_len' bytes of tag message data in + * one or more GOT_IMSG_TAG_TAGMSG messages. + */ +} __attribute__((__packed__)); + /* Structure for GOT_IMSG_PACKIDX. */ struct got_imsg_packidx { size_t len; @@ -212,6 +238,10 @@ const struct got_error *got_privsep_send_tree(struct i struct got_tree_object *); const struct got_error *got_privsep_send_blob(struct imsgbuf *, size_t); const struct got_error *got_privsep_recv_blob(size_t *, struct imsgbuf *); +const struct got_error *got_privsep_send_tag(struct imsgbuf *, + struct got_tag_object *); +const struct got_error *got_privsep_recv_tag(struct got_tag_object **, + struct imsgbuf *); const struct got_error *got_privsep_init_pack_child(struct imsgbuf *, struct got_pack *, struct got_packidx *); const struct got_error *got_privsep_send_packed_obj_req(struct imsgbuf *, int, blob - feabca184d20dfd1ca4c681d9ccb24e0c7717d12 blob + 4379222e6238860a7965b41526f817c2614aa6e5 --- lib/got_lib_repository.h +++ lib/got_lib_repository.h @@ -28,16 +28,18 @@ struct got_repository { struct got_pack packs[GOT_PACK_CACHE_SIZE]; /* Handles to child processes for reading loose objects. */ - struct got_privsep_child privsep_children[4]; + struct got_privsep_child privsep_children[5]; #define GOT_REPO_PRIVSEP_CHILD_OBJECT 0 #define GOT_REPO_PRIVSEP_CHILD_COMMIT 1 #define GOT_REPO_PRIVSEP_CHILD_TREE 2 #define GOT_REPO_PRIVSEP_CHILD_BLOB 3 +#define GOT_REPO_PRIVSEP_CHILD_TAG 4 /* Caches for open objects. */ struct got_object_cache objcache; struct got_object_cache treecache; struct got_object_cache commitcache; + struct got_object_cache tagcache; }; const struct got_error*got_repo_cache_object(struct got_repository *, @@ -52,6 +54,10 @@ const struct got_error*got_repo_cache_commit(struct go struct got_object_id *, struct got_commit_object *); struct got_commit_object *got_repo_get_cached_commit(struct got_repository *, struct got_object_id *); +const struct got_error*got_repo_cache_tag(struct got_repository *, + struct got_object_id *, struct got_tag_object *); +struct got_tag_object *got_repo_get_cached_tag(struct got_repository *, + struct got_object_id *); const struct got_error *got_repo_cache_packidx(struct got_repository *, struct got_packidx *); const struct got_error *got_repo_search_packidx(struct got_packidx **, int *, blob - 6bb2eb4489271559e6ddb7579f548ba80e7d7ff0 blob + 641b24fbfac455d82e70678c29699656df2e9b22 --- lib/object.c +++ lib/object.c @@ -700,6 +700,85 @@ got_object_blob_dump_to_file(size_t *total_len, size_t rewind(outfile); return NULL; +} + +static const struct got_error * +open_tag(struct got_tag_object **tag, + struct got_repository *repo, struct got_object *obj, int check_cache) +{ + const struct got_error *err = NULL; + + if (check_cache) { + *tag = got_repo_get_cached_tag(repo, &obj->id); + if (*tag != NULL) { + (*tag)->refcnt++; + return NULL; + } + } else + *tag = NULL; + + if (obj->type != GOT_OBJ_TYPE_TAG) + return got_error(GOT_ERR_OBJ_TYPE); + + if (obj->flags & GOT_OBJ_FLAG_PACKED) { + struct got_pack *pack; + pack = got_repo_get_cached_pack(repo, obj->path_packfile); + if (pack == NULL) { + err = got_repo_cache_pack(&pack, repo, + obj->path_packfile, NULL); + if (err) + return err; + } + err = got_object_read_packed_tag_privsep(tag, obj, pack); + } else { + int fd; + err = open_loose_object(&fd, obj, repo); + if (err) + return err; + err = got_object_read_tag_privsep(tag, obj, fd, repo); + close(fd); + } + + if (err == NULL) { + (*tag)->refcnt++; + err = got_repo_cache_tag(repo, &obj->id, *tag); + } + + return err; +} + +const struct got_error * +got_object_open_as_tag(struct got_tag_object **tag, + struct got_repository *repo, struct got_object_id *id) +{ + const struct got_error *err; + struct got_object *obj; + + *tag = got_repo_get_cached_tag(repo, id); + if (*tag != NULL) { + (*tag)->refcnt++; + return NULL; + } + + err = got_object_open(&obj, repo, id); + if (err) + return err; + if (got_object_get_type(obj) != GOT_OBJ_TYPE_COMMIT) { + err = got_error(GOT_ERR_OBJ_TYPE); + goto done; + } + + err = open_tag(tag, repo, obj, 0); +done: + got_object_close(obj); + return err; +} + +const struct got_error * +got_object_tag_open(struct got_tag_object **tag, + struct got_repository *repo, struct got_object *obj) +{ + return open_tag(tag, repo, obj, 1); } static struct got_tree_entry * @@ -1074,7 +1153,6 @@ done: return err; } - static const struct got_error * request_commit(struct got_commit_object **commit, struct got_repository *repo, struct got_object *obj, int fd) @@ -1276,4 +1354,70 @@ got_object_read_blob_privsep(size_t *size, int outfd, repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].ibuf = ibuf; return request_blob(size, outfd, infd, ibuf); +} + +static const struct got_error * +request_tag(struct got_tag_object **tag, struct got_repository *repo, + struct got_object *obj, int fd) +{ + const struct got_error *err = NULL; + struct imsgbuf *ibuf; + + ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].ibuf; + + err = got_privsep_send_obj_req(ibuf, fd, obj); + if (err) + return err; + + return got_privsep_recv_tag(tag, ibuf); +} + +const struct got_error * +got_object_read_packed_tag_privsep(struct got_tag_object **tag, + struct got_object *obj, struct got_pack *pack) +{ + const struct got_error *err = NULL; + + err = got_privsep_send_obj_req(pack->privsep_child->ibuf, -1, obj); + if (err) + return err; + + return got_privsep_recv_tag(tag, pack->privsep_child->ibuf); +} + +const struct got_error * +got_object_read_tag_privsep(struct got_tag_object **tag, + struct got_object *obj, int obj_fd, struct got_repository *repo) +{ + int imsg_fds[2]; + pid_t pid; + struct imsgbuf *ibuf; + + if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].imsg_fd != -1) + return request_tag(tag, repo, obj, obj_fd); + + ibuf = calloc(1, sizeof(*ibuf)); + if (ibuf == NULL) + return got_error_from_errno(); + + 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) { + exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_TAG, + repo->path); + /* not reached */ + } + + close(imsg_fds[1]); + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].imsg_fd = + imsg_fds[0]; + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].pid = pid; + imsg_init(ibuf, imsg_fds[0]); + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].ibuf = ibuf; + + return request_tag(tag, repo, obj, obj_fd); } blob - 3325c9fb156df0f75d84e0b7075b5827a4cf25cc blob + 63b2ca2a42f301ea74c82bfe070daf1cf71508ab --- lib/object_cache.c +++ lib/object_cache.c @@ -35,6 +35,7 @@ #define GOT_OBJECT_CACHE_SIZE_OBJ 256 #define GOT_OBJECT_CACHE_SIZE_TREE 256 #define GOT_OBJECT_CACHE_SIZE_COMMIT 64 +#define GOT_OBJECT_CACHE_SIZE_TAG 32 const struct got_error * got_object_cache_init(struct got_object_cache *cache, @@ -57,6 +58,9 @@ got_object_cache_init(struct got_object_cache *cache, case GOT_OBJECT_CACHE_TYPE_COMMIT: cache->size = GOT_OBJECT_CACHE_SIZE_COMMIT; break; + case GOT_OBJECT_CACHE_TYPE_TAG: + cache->size = GOT_OBJECT_CACHE_SIZE_TAG; + break; } return NULL; } @@ -84,6 +88,9 @@ got_object_cache_add(struct got_object_cache *cache, s case GOT_OBJECT_CACHE_TYPE_COMMIT: got_object_commit_close(ce->data.commit); break; + case GOT_OBJECT_CACHE_TYPE_TAG: + got_object_tag_close(ce->data.tag); + break; } free(ce); cache->cache_evict++; @@ -103,6 +110,9 @@ got_object_cache_add(struct got_object_cache *cache, s case GOT_OBJECT_CACHE_TYPE_COMMIT: ce->data.commit = (struct got_commit_object *)item; break; + case GOT_OBJECT_CACHE_TYPE_TAG: + ce->data.tag = (struct got_tag_object *)item; + break; } err = got_object_idset_add(cache->idset, id, ce); @@ -131,6 +141,8 @@ got_object_cache_get(struct got_object_cache *cache, s return ce->data.tree; case GOT_OBJECT_CACHE_TYPE_COMMIT: return ce->data.commit; + case GOT_OBJECT_CACHE_TYPE_TAG: + return ce->data.tag; } } @@ -157,6 +169,7 @@ check_refcount(struct got_object_id *id, void *data, v struct got_object *obj; struct got_tree_object *tree; struct got_commit_object *commit; + struct got_tag_object *tag; char *id_str; if (got_object_id_str(&id_str, id) != NULL) @@ -184,6 +197,13 @@ check_refcount(struct got_object_id *id, void *data, v fprintf(stderr, "commit %s has %d unclaimed references\n", id_str, commit->refcnt - 1); break; + case GOT_OBJECT_CACHE_TYPE_TAG: + tag = ce->data.tag; + if (tag->refcnt == 1) + break; + fprintf(stderr, "tag %s has %d unclaimed references\n", + id_str, tag->refcnt - 1); + break; } free(id_str); return NULL; blob - 0c8445c525924957e8cc178b0f1f868028a3699d blob + 433a6598256a2714af7dc3ab5859a6231a30150d --- lib/object_parse.c +++ lib/object_parse.c @@ -53,11 +53,21 @@ #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) #endif +#define GOT_OBJ_TAG_COMMIT "commit" +#define GOT_OBJ_TAG_TREE "tree" +#define GOT_OBJ_TAG_BLOB "blob" +#define GOT_OBJ_TAG_TAG "tag" + #define GOT_COMMIT_TAG_TREE "tree " #define GOT_COMMIT_TAG_PARENT "parent " #define GOT_COMMIT_TAG_AUTHOR "author " #define GOT_COMMIT_TAG_COMMITTER "committer " +#define GOT_TAG_TAG_OBJECT "object " +#define GOT_TAG_TAG_TYPE "type " +#define GOT_TAG_TAG_TAG "tag " +#define GOT_TAG_TAG_TAGGER "tagger " + int got_object_id_cmp(const struct got_object_id *id1, const struct got_object_id *id2) @@ -518,7 +528,188 @@ got_object_parse_tree(struct got_tree_object **tree, u return NULL; } +void +got_object_tag_close(struct got_tag_object *tag) +{ + free(tag->tag); + free(tag->tagger); + free(tag->tagmsg); + free(tag); +} + const struct got_error * +got_object_parse_tag(struct got_tag_object **tag, uint8_t *buf, size_t len) +{ + const struct got_error *err = NULL; + size_t remain = len; + char *s = buf; + size_t tlen; + + *tag = calloc(1, sizeof(**tag)); + if (*tag == NULL) + return got_error_from_errno(); + + tlen = strlen(GOT_TAG_TAG_OBJECT); + if (strncmp(s, GOT_TAG_TAG_OBJECT, tlen) == 0) { + remain -= tlen; + if (remain < SHA1_DIGEST_STRING_LENGTH) { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + s += tlen; + if (!got_parse_sha1_digest((*tag)->id.sha1, s)) { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + remain -= SHA1_DIGEST_STRING_LENGTH; + s += SHA1_DIGEST_STRING_LENGTH; + } else { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + + if (remain <= 0) { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + + tlen = strlen(GOT_TAG_TAG_TYPE); + if (strncmp(s, GOT_TAG_TAG_TYPE, tlen) == 0) { + remain -= tlen; + if (remain <= 0) { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + s += tlen; + if (strncmp(s, GOT_OBJ_TAG_COMMIT, + strlen(GOT_OBJ_TAG_COMMIT)) == 0) { + (*tag)->obj_type = GOT_OBJ_TYPE_COMMIT; + tlen = strlen(GOT_OBJ_TAG_COMMIT); + s += tlen; + remain -= tlen; + } else if (strncmp(s, GOT_OBJ_TAG_TREE, + strlen(GOT_OBJ_TAG_TREE)) == 0) { + (*tag)->obj_type = GOT_OBJ_TYPE_TREE; + tlen = strlen(GOT_OBJ_TAG_TREE); + s += tlen; + remain -= tlen; + } else if (strncmp(s, GOT_OBJ_TAG_BLOB, + strlen(GOT_OBJ_TAG_BLOB)) == 0) { + (*tag)->obj_type = GOT_OBJ_TYPE_BLOB; + tlen = strlen(GOT_OBJ_TAG_BLOB); + s += tlen; + remain -= tlen; + } else if (strncmp(s, GOT_OBJ_TAG_TAG, + strlen(GOT_OBJ_TAG_TAG)) == 0) { + (*tag)->obj_type = GOT_OBJ_TYPE_TAG; + tlen = strlen(GOT_OBJ_TAG_TAG); + s += tlen; + remain -= tlen; + } else { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + + if (remain <= 0 || *s != '\n') { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + s++; + remain--; + if (remain <= 0) { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + } else { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + + tlen = strlen(GOT_TAG_TAG_TAG); + if (strncmp(s, GOT_TAG_TAG_TAG, tlen) == 0) { + char *p; + size_t slen; + remain -= tlen; + if (remain <= 0) { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + s += tlen; + p = strchr(s, '\n'); + if (p == NULL) { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + *p = '\0'; + slen = strlen(s); + (*tag)->tag = strndup(s, slen); + if ((*tag)->tag == NULL) { + err = got_error_from_errno(); + goto done; + } + s += slen + 1; + remain -= slen + 1; + if (remain <= 0) { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + } else { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + + tlen = strlen(GOT_TAG_TAG_TAGGER); + if (strncmp(s, GOT_TAG_TAG_TAGGER, tlen) == 0) { + char *p; + size_t slen; + + remain -= tlen; + if (remain <= 0) { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + s += tlen; + p = strchr(s, '\n'); + if (p == NULL) { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + *p = '\0'; + slen = strlen(s); + err = parse_commit_time(&(*tag)->tagger_time, + &(*tag)->tagger_gmtoff, s); + if (err) + goto done; + (*tag)->tagger = strdup(s); + if ((*tag)->tagger == NULL) { + err = got_error_from_errno(); + goto done; + } + s += slen + 1; + remain -= slen + 1; + if (remain <= 0) { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + } else { + err = got_error(GOT_ERR_BAD_OBJ_DATA); + goto done; + } + + (*tag)->tagmsg = strndup(s, remain); + if ((*tag)->tagmsg == NULL) { + err = got_error_from_errno(); + goto done; + } +done: + if (err) { + got_object_tag_close(*tag); + *tag = NULL; + } + return err; +} + +const struct got_error * got_read_file_to_mem(uint8_t **outbuf, size_t *outlen, FILE *f) { const struct got_error *err = NULL; blob - 28b85018e0bd0857fe3c037382a2318f2f331963 blob + d95f5012099136dd65c3fbc85cbf8a99a89abdf7 --- lib/privsep.c +++ lib/privsep.c @@ -237,6 +237,9 @@ got_privsep_send_obj_req(struct imsgbuf *ibuf, int fd, break; case GOT_OBJ_TYPE_BLOB: imsg_code = GOT_IMSG_BLOB_REQUEST; + break; + case GOT_OBJ_TYPE_TAG: + imsg_code = GOT_IMSG_TAG_REQUEST; break; default: return got_error(GOT_ERR_OBJ_TYPE); @@ -814,6 +817,211 @@ got_privsep_recv_blob(size_t *size, struct imsgbuf *ib iblob = imsg.data; *size = iblob->size; /* Data has been written to file descriptor. */ + break; + default: + err = got_error(GOT_ERR_PRIVSEP_MSG); + break; + } + + imsg_free(&imsg); + + return err; +} + +static const struct got_error * +send_tagmsg(struct imsgbuf *ibuf, struct got_tag_object *tag, size_t tagmsg_len) +{ + const struct got_error *err = NULL; + size_t offset, remain; + + offset = 0; + remain = tagmsg_len; + while (remain > 0) { + size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE, remain); + + if (imsg_compose(ibuf, GOT_IMSG_TAG_TAGMSG, 0, 0, -1, + tag->tagmsg + offset, n) == -1) { + err = got_error_from_errno(); + break; + } + + err = flush_imsg(ibuf); + if (err) + break; + + offset += n; + remain -= n; + } + + return err; +} + +const struct got_error * +got_privsep_send_tag(struct imsgbuf *ibuf, struct got_tag_object *tag) +{ + const struct got_error *err = NULL; + struct got_imsg_tag_object *itag; + uint8_t *buf; + size_t len, total; + size_t tag_len = strlen(tag->tag); + size_t tagger_len = strlen(tag->tagger); + size_t tagmsg_len = strlen(tag->tagmsg); + + total = sizeof(*itag) + tag_len + tagger_len + tagmsg_len; + + buf = malloc(total); + if (buf == NULL) + return got_error_from_errno(); + + itag = (struct got_imsg_tag_object *)buf; + memcpy(itag->id, tag->id.sha1, sizeof(itag->id)); + itag->obj_type = tag->obj_type; + itag->tag_len = tag_len; + itag->tagger_len = tagger_len; + itag->tagger_time = tag->tagger_time; + itag->tagger_gmtoff = tag->tagger_gmtoff; + itag->tagmsg_len = tagmsg_len; + + len = sizeof(*itag); + memcpy(buf + len, tag->tag, tag_len); + len += tag_len; + memcpy(buf + len, tag->tagger, tagger_len); + len += tagger_len; + + if (imsg_compose(ibuf, GOT_IMSG_TAG, 0, 0, -1, buf, len) == -1) { + err = got_error_from_errno(); + goto done; + } + + if (tagmsg_len == 0 || + tagmsg_len + len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { + err = flush_imsg(ibuf); + if (err) + goto done; + } + err = send_tagmsg(ibuf, tag, tagmsg_len); +done: + free(buf); + return err; +} + +const struct got_error * +got_privsep_recv_tag(struct got_tag_object **tag, struct imsgbuf *ibuf) +{ + const struct got_error *err = NULL; + struct imsg imsg; + struct got_imsg_tag_object *itag; + size_t len, datalen; + const size_t min_datalen = + MIN(sizeof(struct got_imsg_error), + sizeof(struct got_imsg_tag_object)); + + *tag = NULL; + + err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen); + if (err) + return err; + + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + len = 0; + + switch (imsg.hdr.type) { + case GOT_IMSG_TAG: + if (datalen < sizeof(*itag)) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + break; + } + itag = imsg.data; + if (datalen != sizeof(*itag) + itag->tag_len + + itag->tagger_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + break; + } + len += sizeof(*itag); + + *tag = calloc(1, sizeof(**tag)); + if (*tag == NULL) { + err = got_error_from_errno(); + break; + } + + memcpy((*tag)->id.sha1, itag->id, SHA1_DIGEST_LENGTH); + + if (itag->tag_len == 0) { + (*tag)->tag = strdup(""); + if ((*tag)->tag == NULL) { + err = got_error_from_errno(); + break; + } + } else { + (*tag)->tag = malloc(itag->tag_len + 1); + if ((*tag)->tag == NULL) { + err = got_error_from_errno(); + break; + } + memcpy((*tag)->tag, imsg.data + len, + itag->tag_len); + (*tag)->tag[itag->tag_len] = '\0'; + } + len += itag->tag_len; + + (*tag)->obj_type = itag->obj_type; + (*tag)->tagger_time = itag->tagger_time; + (*tag)->tagger_gmtoff = itag->tagger_gmtoff; + + if (itag->tagger_len == 0) { + (*tag)->tagger = strdup(""); + if ((*tag)->tagger == NULL) { + err = got_error_from_errno(); + break; + } + } else { + (*tag)->tagger = malloc(itag->tagger_len + 1); + if ((*tag)->tagger == NULL) { + err = got_error_from_errno(); + break; + } + memcpy((*tag)->tagger, imsg.data + len, + itag->tagger_len); + (*tag)->tagger[itag->tagger_len] = '\0'; + } + len += itag->tagger_len; + + if (itag->tagmsg_len == 0) { + (*tag)->tagmsg = strdup(""); + if ((*tag)->tagmsg == NULL) { + err = got_error_from_errno(); + break; + } + } else { + size_t offset = 0, remain = itag->tagmsg_len; + + (*tag)->tagmsg = malloc(itag->tagmsg_len + 1); + if ((*tag)->tagmsg == NULL) { + err = got_error_from_errno(); + break; + } + 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_TAG_TAGMSG) + return got_error(GOT_ERR_PRIVSEP_MSG); + + memcpy((*tag)->tagmsg + offset, imsg_log.data, + n); + imsg_free(&imsg_log); + offset += n; + remain -= n; + } + (*tag)->tagmsg[itag->tagmsg_len] = '\0'; + } + break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); blob - 3becb1ca45ed5e33df2ffa0843361e63961071ad blob + 941438ef7171b50941a6d4601ad0c38546dfebed --- lib/repository.c +++ lib/repository.c @@ -229,6 +229,27 @@ got_repo_get_cached_commit(struct got_repository *repo { return (struct got_commit_object *)got_object_cache_get( &repo->commitcache, id); +} + +const struct got_error * +got_repo_cache_tag(struct got_repository *repo, struct got_object_id *id, + struct got_tag_object *tag) +{ +#ifndef GOT_NO_OBJ_CACHE + const struct got_error *err = NULL; + err = got_object_cache_add(&repo->tagcache, id, tag); + if (err) + return err; + tag->refcnt++; +#endif + return NULL; +} + +struct got_tag_object * +got_repo_get_cached_tag(struct got_repository *repo, struct got_object_id *id) +{ + return (struct got_tag_object *)got_object_cache_get( + &repo->tagcache, id); } const struct got_error * @@ -354,6 +375,10 @@ got_repo_open(struct got_repository **repop, const cha GOT_OBJECT_CACHE_TYPE_COMMIT); if (err) goto done; + err = got_object_cache_init(&repo->tagcache, + GOT_OBJECT_CACHE_TYPE_TAG); + if (err) + goto done; normpath = got_path_normalize(abspath); if (normpath == NULL) { @@ -413,6 +438,7 @@ got_repo_close(struct got_repository *repo) got_object_cache_close(&repo->objcache); got_object_cache_close(&repo->treecache); got_object_cache_close(&repo->commitcache); + got_object_cache_close(&repo->tagcache); for (i = 0; i < nitems(repo->privsep_children); i++) { if (repo->privsep_children[i].imsg_fd == -1) blob - 7738a57cd9ee8350a5e72c39a576e5b654aa263c blob + ae3722c08c1905a6e64dee0e34ec327baf6cb82c --- libexec/got-read-object/got-read-object.c +++ libexec/got-read-object/got-read-object.c @@ -45,6 +45,7 @@ #define GOT_OBJ_TAG_COMMIT "commit" #define GOT_OBJ_TAG_TREE "tree" #define GOT_OBJ_TAG_BLOB "blob" +#define GOT_OBJ_TAG_TAG "tag" static volatile sig_atomic_t sigint_received; @@ -60,12 +61,14 @@ parse_object_header(struct got_object **obj, char *buf const char *obj_tags[] = { GOT_OBJ_TAG_COMMIT, GOT_OBJ_TAG_TREE, - GOT_OBJ_TAG_BLOB + GOT_OBJ_TAG_BLOB, + GOT_OBJ_TAG_TAG, }; const int obj_types[] = { GOT_OBJ_TYPE_COMMIT, GOT_OBJ_TYPE_TREE, GOT_OBJ_TYPE_BLOB, + GOT_OBJ_TYPE_TAG, }; int type = 0; size_t size = 0, hdrlen = 0; blob - 24f359a343b084dcfe5e2654c1b4ae57fcaa9e05 blob + e5d58ee0bb72b099f33b72f3367599d9f6fee2eb --- libexec/got-read-pack/got-read-pack.c +++ libexec/got-read-pack/got-read-pack.c @@ -272,6 +272,43 @@ done: } static const struct got_error * +tag_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; + struct got_object *obj = NULL; + struct got_tag_object *tag = NULL; + uint8_t *buf; + size_t len; + + err = get_object(&obj, imsg, ibuf, pack, packidx, objcache, + GOT_OBJ_TYPE_TAG); + if (err) + return err; + + err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack); + if (err) + return err; + + obj->size = len; + err = got_object_parse_tag(&tag, buf, len); + free(buf); + + err = got_privsep_send_tag(ibuf, tag); + if (obj) + got_object_close(obj); + got_object_tag_close(tag); + if (err) { + if (err->code == GOT_ERR_PRIVSEP_PIPE) + err = NULL; + else + 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; @@ -488,6 +525,10 @@ main(int argc, char *argv[]) err = blob_request(&imsg, &ibuf, pack, packidx, &objcache); break; + case GOT_IMSG_TAG_REQUEST: + err = tag_request(&imsg, &ibuf, pack, packidx, + &objcache); + break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break;