commit abe0f35f1af70d4413ea3b79ef5f37eb0c7db2c2 from: Stefan Sperling date: Wed Mar 18 16:10:33 2020 UTC parse symrefs from server capabilities and transmit them over imsg commit - 13ce8c9368c159db1a4d9471a6cf7cf7cd83b73b commit + abe0f35f1af70d4413ea3b79ef5f37eb0c7db2c2 blob - 83435ade8c0f36340678bfe485c738fc0cbe8fb8 blob + eec7237a4fc2f2bc544d6b22e892861661037774 --- lib/fetch.c +++ lib/fetch.c @@ -298,6 +298,10 @@ got_fetch(char *uri, char *branch_filter, char *destdi pid_t pid; char *tmppackpath = NULL, *tmpidxpath = NULL, *default_destdir = NULL; char *packpath = NULL, *idxpath = NULL, *id_str = NULL; + struct got_pathlist_head symrefs; + struct got_pathlist_entry *pe; + + TAILQ_INIT(&symrefs); fetchfd = -1; if (got_parse_uri(uri, proto, host, port, path, repo) == -1) @@ -365,7 +369,7 @@ got_fetch(char *uri, char *branch_filter, char *destdi struct got_object_id *id; char *refname; err = got_privsep_recv_fetch_progress(&done, - &id, &refname, &ibuf); + &id, &refname, &symrefs, &ibuf); if (err != NULL) return err; if (done) { @@ -373,7 +377,13 @@ got_fetch(char *uri, char *branch_filter, char *destdi if (packhash == NULL) return got_error_from_errno( "got_object_id_dup"); - } else { + printf("symrefs:"); + TAILQ_FOREACH(pe, &symrefs, entry) { + printf(" %s:%s", pe->path, + (const char *)pe->data); + } + printf("\n"); + } else if (id) { char *id_str; /* TODO Use a progress callback */ err = got_object_id_str(&id_str, id); @@ -431,6 +441,11 @@ got_fetch(char *uri, char *branch_filter, char *destdi free(packpath); free(default_destdir); free(packhash); + TAILQ_FOREACH(pe, &symrefs, entry) { + free((void *)pe->path); + free(pe->data); + } + got_pathlist_free(&symrefs); return NULL; } blob - 4b14f8cacd48ffe10d30e6cf407481cd9e12e27f blob + 96d82f6fab85ba429a3482411e1491566e7f97ce --- lib/got_lib_privsep.h +++ lib/got_lib_privsep.h @@ -110,6 +110,7 @@ enum got_imsg_type { /* Messages related to networking. */ GOT_IMSG_FETCH_REQUEST, + GOT_IMSG_FETCH_SYMREFS, GOT_IMSG_FETCH_PROGRESS, GOT_IMSG_FETCH_DONE, GOT_IMSG_IDXPACK_REQUEST, @@ -231,11 +232,27 @@ struct got_imsg_tag_object { * Followed by 'tagmsg_len' bytes of tag message data in * one or more GOT_IMSG_TAG_TAGMSG messages. */ +} __attribute__((__packed__)); + +/* Structures for GOT_IMSG_FETCH_SYMREFS data. */ +struct got_imsg_fetch_symref { + size_t name_len; + size_t target_len; + + /* + * Followed by name_len + target_len gata bytes. + */ +} __attribute__((__packed__)); + +struct got_imsg_fetch_symrefs { + size_t nsymrefs; + + /* Followed by nsymrefs times of got_imsg_fetch_symref data. */ } __attribute__((__packed__)); /* Structure for GOT_IMSG_FETCH_PROGRESS data. */ struct got_imsg_fetch_progress { - /* Descirbes a reference which will be fetched. */ + /* Describes a reference which will be fetched. */ uint8_t refid[SHA1_DIGEST_LENGTH]; /* Followed by reference name in remaining data of imsg buffer. */ }; @@ -323,10 +340,13 @@ const struct got_error *got_privsep_send_index_pack_re const struct got_error *got_privsep_send_index_pack_done(struct imsgbuf *); const struct got_error *got_privsep_wait_index_pack_done(struct imsgbuf *); const struct got_error *got_privsep_send_fetch_req(struct imsgbuf *, int); +const struct got_error *got_privsep_send_fetch_symrefs(struct imsgbuf *, + struct got_pathlist_head *); const struct got_error *got_privsep_send_fetch_progress(struct imsgbuf *, struct got_object_id *, const char *); const struct got_error *got_privsep_recv_fetch_progress(int *, - struct got_object_id **, char **, struct imsgbuf *); + struct got_object_id **, char **, struct got_pathlist_head *, + struct imsgbuf *); const struct got_error *got_privsep_send_fetch_done(struct imsgbuf *, struct got_object_id); const struct got_error *got_privsep_get_imsg_obj(struct got_object **, blob - 642c62a8f986362d8cddddd8fbeb351284c09e39 blob + 23b8318e31fac27d4a29d740ed4be0b84cdfbceb --- lib/privsep.c +++ lib/privsep.c @@ -419,6 +419,71 @@ got_privsep_send_fetch_req(struct imsgbuf *ibuf, int f } const struct got_error * +got_privsep_send_fetch_symrefs(struct imsgbuf *ibuf, + struct got_pathlist_head *symrefs) +{ + const struct got_error *err = NULL; + struct ibuf *wbuf; + size_t len, nsymrefs = 0; + struct got_pathlist_entry *pe; + + len = sizeof(struct got_imsg_fetch_symrefs); + TAILQ_FOREACH(pe, symrefs, entry) { + const char *target = pe->data; + len += sizeof(struct got_imsg_fetch_symref) + + pe->path_len + strlen(target); + nsymrefs++; + } + + if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) + return got_error(GOT_ERR_NO_SPACE); + + wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_SYMREFS, 0, 0, len); + if (wbuf == NULL) + return got_error_from_errno("imsg_create FETCH_SYMREFS"); + + /* Keep in sync with struct got_imsg_fetch_symrefs definition! */ + if (imsg_add(wbuf, &nsymrefs, sizeof(nsymrefs)) == -1) { + err = got_error_from_errno("imsg_add FETCH_SYMREFS"); + ibuf_free(wbuf); + return err; + } + + TAILQ_FOREACH(pe, symrefs, entry) { + const char *name = pe->path; + size_t name_len = pe->path_len; + const char *target = pe->data; + size_t target_len = strlen(target); + + /* Keep in sync with struct got_imsg_fetch_symref definition! */ + if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1) { + err = got_error_from_errno("imsg_add FETCH_SYMREFS"); + ibuf_free(wbuf); + return err; + } + if (imsg_add(wbuf, &target_len, sizeof(target_len)) == -1) { + err = got_error_from_errno("imsg_add FETCH_SYMREFS"); + ibuf_free(wbuf); + return err; + } + if (imsg_add(wbuf, name, name_len) == -1) { + err = got_error_from_errno("imsg_add FETCH_SYMREFS"); + ibuf_free(wbuf); + return err; + } + if (imsg_add(wbuf, target, target_len) == -1) { + err = got_error_from_errno("imsg_add FETCH_SYMREFS"); + ibuf_free(wbuf); + return err; + } + } + + wbuf->fd = -1; + imsg_close(ibuf, wbuf); + return flush_imsg(ibuf); +} + +const struct got_error * got_privsep_send_fetch_progress(struct imsgbuf *ibuf, struct got_object_id *refid, const char *refname) { @@ -463,14 +528,18 @@ got_privsep_send_fetch_done(struct imsgbuf *ibuf, stru const struct got_error * got_privsep_recv_fetch_progress(int *done, struct got_object_id **id, - char **refname, struct imsgbuf *ibuf) + char **refname, struct got_pathlist_head *symrefs, struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct imsg imsg; size_t datalen; const size_t min_datalen = - MIN(sizeof(struct got_imsg_error), - sizeof(struct got_imsg_fetch_progress)); + MIN(MIN(sizeof(struct got_imsg_error), + sizeof(struct got_imsg_fetch_progress)), + sizeof(struct got_imsg_fetch_symrefs)); + struct got_imsg_fetch_symrefs *isymrefs = NULL; + size_t n, remain; + off_t off; *done = 0; *id = NULL; @@ -485,6 +554,60 @@ got_privsep_recv_fetch_progress(int *done, struct got_ case GOT_IMSG_ERROR: err = recv_imsg_error(&imsg, datalen); break; + case GOT_IMSG_FETCH_SYMREFS: + if (datalen < sizeof(*isymrefs)) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + break; + } + if (isymrefs != NULL) { + err = got_error(GOT_ERR_PRIVSEP_MSG); + break; + } + isymrefs = (struct got_imsg_fetch_symrefs *)imsg.data; + off = sizeof(*isymrefs); + remain = datalen - off; + for (n = 0; n < isymrefs->nsymrefs; n++) { + struct got_imsg_fetch_symref *s; + char *name, *target; + if (remain < sizeof(struct got_imsg_fetch_symref)) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + s = (struct got_imsg_fetch_symref *)(imsg.data + off); + off += sizeof(*s); + remain -= sizeof(*s); + if (remain < s->name_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + name = strndup(imsg.data + off, s->name_len); + if (name == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + off += s->name_len; + remain -= s->name_len; + if (remain < s->target_len) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + free(name); + goto done; + } + target = strndup(imsg.data + off, s->target_len); + if (target == NULL) { + err = got_error_from_errno("strndup"); + free(name); + goto done; + } + off += s->target_len; + remain -= s->target_len; + err = got_pathlist_append(symrefs, name, target); + if (err) { + free(name); + free(target); + goto done; + } + } + break; case GOT_IMSG_FETCH_PROGRESS: *id = malloc(sizeof(**id)); if (*id == NULL) { @@ -520,7 +643,7 @@ got_privsep_recv_fetch_progress(int *done, struct got_ err = got_error(GOT_ERR_PRIVSEP_MSG); break; } - +done: if (err) { free(*id); *id = NULL; blob - 4fb64788f5a648f7f34e87ff0205d269d68c990d blob + 7340b1a9a9076ae86fed9a6e1276134ce7d005b7 --- libexec/got-fetch-pack/got-fetch-pack.c +++ libexec/got-fetch-pack/got-fetch-pack.c @@ -37,6 +37,7 @@ #include "got_error.h" #include "got_object.h" +#include "got_path.h" #include "got_version.h" #include "got_lib_sha1.h" @@ -353,10 +354,46 @@ match_capability(char **my_capabilities, const char *c } static const struct got_error * -match_capabilities(char **my_capabilities, char *server_capabilities) +add_symref(struct got_pathlist_head *symrefs, const char *capa) { const struct got_error *err = NULL; - char *capa; + char *colon, *name = NULL, *target = NULL; + + /* Need at least "A:B" */ + if (strlen(capa) < 3) + return NULL; + + colon = strchr(capa, ':'); + if (colon == NULL) + return NULL; + + *colon = '\0'; + name = strdup(capa); + if (name == NULL) + return got_error_from_errno("strdup"); + + target = strdup(colon + 1); + if (target == NULL) { + err = got_error_from_errno("strdup"); + goto done; + } + + /* We can't validate the ref itself here. The main process will. */ + err = got_pathlist_append(symrefs, name, target); +done: + if (err) { + free(name); + free(target); + } + return err; +} + +static const struct got_error * +match_capabilities(char **my_capabilities, struct got_pathlist_head *symrefs, + char *server_capabilities) +{ + const struct got_error *err = NULL; + char *capa, *equalsign; int i; *my_capabilities = NULL; @@ -365,6 +402,15 @@ match_capabilities(char **my_capabilities, char *serve if (capa == NULL) return NULL; + equalsign = strchr(capa, '='); + if (equalsign != NULL && + strncmp(capa, "symref", equalsign - capa) == 0) { + err = add_symref(symrefs, equalsign + 1); + if (err) + break; + continue; + } + for (i = 0; i < nitems(got_capabilities); i++) { err = match_capability(my_capabilities, capa, &got_capabilities[i]); @@ -375,7 +421,7 @@ match_capabilities(char **my_capabilities, char *serve return err; } - + static const struct got_error * fetch_pack(int fd, int packfd, struct got_object_id *packid, struct imsgbuf *ibuf) @@ -388,7 +434,11 @@ fetch_pack(int fd, int packfd, struct got_object_id *p int i, n, req; off_t packsz; char *my_capabilities = NULL; + struct got_pathlist_head symrefs; + struct got_pathlist_entry *pe; + TAILQ_INIT(&symrefs); + have = malloc(refsz * sizeof(have[0])); if (have == NULL) return got_error_from_errno("malloc"); @@ -426,12 +476,16 @@ fetch_pack(int fd, int packfd, struct got_object_id *p if (chattygit && sp[2][0] != '\0') fprintf(stderr, "server capabilities: %s\n", sp[2]); if (is_firstpkt) { - err = match_capabilities(&my_capabilities, sp[2]); + err = match_capabilities(&my_capabilities, &symrefs, + sp[2]); if (err) goto done; if (chattygit && my_capabilities) fprintf(stderr, "my matched capabilities: %s\n", my_capabilities); + err = got_privsep_send_fetch_symrefs(ibuf, &symrefs); + if (err) + goto done; } is_firstpkt = 0; if (strstr(sp[1], "^{}")) @@ -549,6 +603,11 @@ fetch_pack(int fd, int packfd, struct got_object_id *p if (got_check_pack_hash(packfd, packsz, packid->sha1) == -1) err = got_error(GOT_ERR_BAD_PACKFILE); done: + TAILQ_FOREACH(pe, &symrefs, entry) { + free((void *)pe->path); + free(pe->data); + } + got_pathlist_free(&symrefs); free(have); free(want); return err;