commit bd3d9e54cb422cb58d52b267c6a8afc3376842d2 from: Stefan Sperling date: Sun Sep 05 14:21:02 2021 UTC move more code used by got-send-pack and got-fetch-pack to a common file Move functions and data structures which implement Git protocol features required for fetching and sending pack files to new files lib/gitproto.c and lib/got_lib_gitproto.h. This code was duplicated in got-fetch-pack and got-send-pack. No functional change. commit - f024663dea0dea05a0d4c17d2314f38f73e85bc6 commit + bd3d9e54cb422cb58d52b267c6a8afc3376842d2 blob - /dev/null blob + 436c3e0854074e30dfdfca92ce23d908e5c94bbf (mode 644) --- /dev/null +++ lib/gitproto.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2019 Ori Bernstein + * Copyright (c) 2021 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include + +#include "got_error.h" +#include "got_path.h" + +#include "got_lib_gitproto.h" + +#ifndef nitems +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + +static const struct got_error * +tokenize_refline(char **tokens, char *line, int len, int maxtokens) +{ + const struct got_error *err = NULL; + char *p; + size_t i, n = 0; + + for (i = 0; i < maxtokens; i++) + tokens[i] = NULL; + + for (i = 0; n < len && i < maxtokens; i++) { + while (isspace(*line)) { + line++; + n++; + } + p = line; + while (*line != '\0' && n < len && + (!isspace(*line) || i == maxtokens - 1)) { + line++; + n++; + } + tokens[i] = strndup(p, line - p); + if (tokens[i] == NULL) { + err = got_error_from_errno("strndup"); + goto done; + } + /* Skip \0 field-delimiter at end of token. */ + while (line[0] == '\0' && n < len) { + line++; + n++; + } + } + if (i <= 2) + err = got_error(GOT_ERR_BAD_PACKET); +done: + if (err) { + int j; + for (j = 0; j < i; j++) { + free(tokens[j]); + tokens[j] = NULL; + } + } + return err; +} + +const struct got_error * +got_gitproto_parse_refline(char **id_str, char **refname, + char **server_capabilities, char *line, int len) +{ + const struct got_error *err = NULL; + char *tokens[3]; + + err = tokenize_refline(tokens, line, len, nitems(tokens)); + if (err) + return err; + + if (tokens[0]) + *id_str = tokens[0]; + if (tokens[1]) + *refname = tokens[1]; + if (tokens[2]) { + char *p; + *server_capabilities = tokens[2]; + p = strrchr(*server_capabilities, '\n'); + if (p) + *p = '\0'; + } + + return NULL; +} + +static const struct got_error * +match_capability(char **my_capabilities, const char *capa, + const struct got_capability *mycapa) +{ + char *equalsign; + char *s; + + equalsign = strchr(capa, '='); + if (equalsign) { + if (strncmp(capa, mycapa->key, equalsign - capa) != 0) + return NULL; + } else { + if (strcmp(capa, mycapa->key) != 0) + return NULL; + } + + if (asprintf(&s, "%s %s%s%s", + *my_capabilities != NULL ? *my_capabilities : "", + mycapa->key, + mycapa->value != NULL ? "=" : "", + mycapa->value != NULL? mycapa->value : "") == -1) + return got_error_from_errno("asprintf"); + + free(*my_capabilities); + *my_capabilities = s; + return NULL; +} + +static const struct got_error * +add_symref(struct got_pathlist_head *symrefs, char *capa) +{ + const struct got_error *err = NULL; + 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; +} + +const struct got_error * +got_gitproto_match_capabilities(char **common_capabilities, + struct got_pathlist_head *symrefs, char *server_capabilities, + const struct got_capability my_capabilities[], size_t ncapa) +{ + const struct got_error *err = NULL; + char *capa, *equalsign; + size_t i; + + *common_capabilities = NULL; + do { + capa = strsep(&server_capabilities, " "); + if (capa == NULL) + return NULL; + + equalsign = strchr(capa, '='); + if (equalsign != NULL && symrefs != NULL && + strncmp(capa, "symref", equalsign - capa) == 0) { + err = add_symref(symrefs, equalsign + 1); + if (err) + break; + continue; + } + + for (i = 0; i < ncapa; i++) { + err = match_capability(common_capabilities, + capa, &my_capabilities[i]); + if (err) + break; + } + } while (capa); + + if (*common_capabilities == NULL) { + *common_capabilities = strdup(""); + if (*common_capabilities == NULL) + err = got_error_from_errno("strdup"); + } + return err; +} blob - /dev/null blob + cffe349e03b4a8a0cd9126b511ed9198af1c3c57 (mode 644) --- /dev/null +++ lib/got_lib_gitproto.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Ori Bernstein + * Copyright (c) 2021 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define GOT_CAPA_AGENT "agent" +#define GOT_CAPA_OFS_DELTA "ofs-delta" +#define GOT_CAPA_SIDE_BAND_64K "side-band-64k" +#define GOT_CAPA_REPORT_STATUS "report-status" +#define GOT_CAPA_DELETE_REFS "delete-refs" + +#define GOT_SIDEBAND_PACKFILE_DATA 1 +#define GOT_SIDEBAND_PROGRESS_INFO 2 +#define GOT_SIDEBAND_ERROR_INFO 3 + +struct got_capability { + const char *key; + const char *value; +}; + +struct got_pathlist_head; + +const struct got_error *got_gitproto_parse_refline(char **id_str, + char **refname, char **server_capabilities, char *line, int len); +const struct got_error *got_gitproto_match_capabilities( + char **common_capabilities, + struct got_pathlist_head *symrefs, char *server_capabilities, + const struct got_capability my_capabilities[], size_t ncapa); blob - 322eb5182bf517fe519edba355c7eb691286ed23 blob + 7df6b00656bdfc711605a13a29e30f4b21aa2f3a --- libexec/got-fetch-pack/Makefile +++ libexec/got-fetch-pack/Makefile @@ -4,7 +4,7 @@ PROG= got-fetch-pack SRCS= got-fetch-pack.c error.c inflate.c object_parse.c \ - path.c privsep.c sha1.c pkt.c + path.c privsep.c sha1.c pkt.c gitproto.c CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib LDADD = -lutil -lz blob - 1b1a71e4dc4357b0153e9ebfa2b776af69bf006b blob + 42a19bfb5390548d4249bd5c2f9432a6a853b121 --- libexec/got-fetch-pack/got-fetch-pack.c +++ libexec/got-fetch-pack/got-fetch-pack.c @@ -49,6 +49,7 @@ #include "got_lib_privsep.h" #include "got_lib_pack.h" #include "got_lib_pkt.h" +#include "got_lib_gitproto.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) @@ -58,6 +59,12 @@ struct got_object *indexed; static int chattygot; static struct got_object_id zhash = {.sha1={0}}; +static const struct got_capability got_capabilities[] = { + { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR }, + { GOT_CAPA_OFS_DELTA, NULL }, + { GOT_CAPA_SIDE_BAND_64K, NULL }, +}; + static void match_remote_ref(struct got_pathlist_head *have_refs, struct got_object_id *my_id, char *refname) @@ -114,201 +121,9 @@ match_wanted_ref(const char *refname, const char *want /* Allow exact match. */ return (strcmp(refname, wanted_ref) == 0); -} - -static const struct got_error * -tokenize_refline(char **tokens, char *line, int len, int maxtokens) -{ - const struct got_error *err = NULL; - char *p; - size_t i, n = 0; - - for (i = 0; i < maxtokens; i++) - tokens[i] = NULL; - - for (i = 0; n < len && i < maxtokens; i++) { - while (isspace(*line)) { - line++; - n++; - } - p = line; - while (*line != '\0' && n < len && - (!isspace(*line) || i == maxtokens - 1)) { - line++; - n++; - } - tokens[i] = strndup(p, line - p); - if (tokens[i] == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - /* Skip \0 field-delimiter at end of token. */ - while (line[0] == '\0' && n < len) { - line++; - n++; - } - } - if (i <= 2) - err = got_error(GOT_ERR_BAD_PACKET); -done: - if (err) { - int j; - for (j = 0; j < i; j++) { - free(tokens[j]); - tokens[j] = NULL; - } - } - return err; -} - -static const struct got_error * -parse_refline(char **id_str, char **refname, char **server_capabilities, - char *line, int len) -{ - const struct got_error *err = NULL; - char *tokens[3]; - - err = tokenize_refline(tokens, line, len, nitems(tokens)); - if (err) - return err; - - if (tokens[0]) - *id_str = tokens[0]; - if (tokens[1]) - *refname = tokens[1]; - if (tokens[2]) { - char *p; - *server_capabilities = tokens[2]; - p = strrchr(*server_capabilities, '\n'); - if (p) - *p = '\0'; - } - - return NULL; -} - -#define GOT_CAPA_AGENT "agent" -#define GOT_CAPA_OFS_DELTA "ofs-delta" -#define GOT_CAPA_SIDE_BAND_64K "side-band-64k" - -#define GOT_SIDEBAND_PACKFILE_DATA 1 -#define GOT_SIDEBAND_PROGRESS_INFO 2 -#define GOT_SIDEBAND_ERROR_INFO 3 - - -struct got_capability { - const char *key; - const char *value; -}; -static const struct got_capability got_capabilities[] = { - { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR }, - { GOT_CAPA_OFS_DELTA, NULL }, - { GOT_CAPA_SIDE_BAND_64K, NULL }, -}; - -static const struct got_error * -match_capability(char **my_capabilities, const char *capa, - const struct got_capability *mycapa) -{ - char *equalsign; - char *s; - - equalsign = strchr(capa, '='); - if (equalsign) { - if (strncmp(capa, mycapa->key, equalsign - capa) != 0) - return NULL; - } else { - if (strcmp(capa, mycapa->key) != 0) - return NULL; - } - - if (asprintf(&s, "%s %s%s%s", - *my_capabilities != NULL ? *my_capabilities : "", - mycapa->key, - mycapa->value != NULL ? "=" : "", - mycapa->value != NULL? mycapa->value : "") == -1) - return got_error_from_errno("asprintf"); - - free(*my_capabilities); - *my_capabilities = s; - return NULL; -} - -static const struct got_error * -add_symref(struct got_pathlist_head *symrefs, char *capa) -{ - const struct got_error *err = NULL; - 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; - size_t i; - - *my_capabilities = NULL; - do { - capa = strsep(&server_capabilities, " "); - 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]); - if (err) - break; - } - } while (capa); - - if (*my_capabilities == NULL) { - *my_capabilities = strdup(""); - if (*my_capabilities == NULL) - err = got_error_from_errno("strdup"); - } - return err; -} - -static const struct got_error * send_fetch_server_progress(struct imsgbuf *ibuf, const char *msg, size_t msglen) { if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) @@ -345,8 +160,6 @@ send_fetch_done(struct imsgbuf *ibuf, uint8_t *pack_sh return got_privsep_flush_imsg(ibuf); } - - static const struct got_error * fetch_progress(struct imsgbuf *ibuf, const char *buf, size_t len) { @@ -534,16 +347,17 @@ fetch_pack(int fd, int packfd, uint8_t *pack_sha1, err = fetch_error(&buf[4], n - 4); goto done; } - err = parse_refline(&id_str, &refname, &server_capabilities, - buf, n); + err = got_gitproto_parse_refline(&id_str, &refname, + &server_capabilities, buf, n); if (err) goto done; if (is_firstpkt) { if (chattygot && server_capabilities[0] != '\0') fprintf(stderr, "%s: server capabilities: %s\n", getprogname(), server_capabilities); - err = match_capabilities(&my_capabilities, &symrefs, - server_capabilities); + err = got_gitproto_match_capabilities(&my_capabilities, + &symrefs, server_capabilities, + got_capabilities, nitems(got_capabilities)); if (err) goto done; if (chattygot) blob - ddc73e59aea2891c17b777b954fffa3a0bec90c6 blob + c4d5d83a73cd53d7437213cdf349daaec168facd --- libexec/got-send-pack/Makefile +++ libexec/got-send-pack/Makefile @@ -4,7 +4,7 @@ PROG= got-send-pack SRCS= got-send-pack.c error.c inflate.c object_parse.c \ - path.c privsep.c sha1.c pkt.c + path.c privsep.c sha1.c pkt.c gitproto.c CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib LDADD = -lutil -lz blob - 059def3f0aaec687446cd952534fdb52768ea4d8 blob + fc22714cab99aae6b98600a9b4c3bfdb0815c41c --- libexec/got-send-pack/got-send-pack.c +++ libexec/got-send-pack/got-send-pack.c @@ -50,6 +50,7 @@ #include "got_lib_privsep.h" #include "got_lib_pack.h" #include "got_lib_pkt.h" +#include "got_lib_gitproto.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) @@ -58,92 +59,6 @@ struct got_object *indexed; static int chattygot; -static const struct got_error * -tokenize_refline(char **tokens, char *line, int len, int maxtokens) -{ - const struct got_error *err = NULL; - char *p; - size_t i, n = 0; - - for (i = 0; i < maxtokens; i++) - tokens[i] = NULL; - - for (i = 0; n < len && i < maxtokens; i++) { - while (isspace(*line)) { - line++; - n++; - } - p = line; - while (*line != '\0' && n < len && - (!isspace(*line) || i == maxtokens - 1)) { - line++; - n++; - } - tokens[i] = strndup(p, line - p); - if (tokens[i] == NULL) { - err = got_error_from_errno("strndup"); - goto done; - } - /* Skip \0 field-delimiter at end of token. */ - while (line[0] == '\0' && n < len) { - line++; - n++; - } - } - if (i <= 2) - err = got_error(GOT_ERR_NOT_REF); -done: - if (err) { - int j; - for (j = 0; j < i; j++) { - free(tokens[j]); - tokens[j] = NULL; - } - } - return err; -} - -static const struct got_error * -parse_refline(char **id_str, char **refname, char **server_capabilities, - char *line, int len) -{ - const struct got_error *err = NULL; - char *tokens[3]; - - err = tokenize_refline(tokens, line, len, nitems(tokens)); - if (err) - return err; - - if (tokens[0]) - *id_str = tokens[0]; - if (tokens[1]) - *refname = tokens[1]; - if (tokens[2]) { - char *p; - *server_capabilities = tokens[2]; - p = strrchr(*server_capabilities, '\n'); - if (p) - *p = '\0'; - } - - return NULL; -} - -#define GOT_CAPA_AGENT "agent" -#define GOT_CAPA_OFS_DELTA "ofs-delta" -#define GOT_CAPA_SIDE_BAND_64K "side-band-64k" -#define GOT_CAPA_REPORT_STATUS "report-status" -#define GOT_CAPA_DELETE_REFS "delete-refs" - -#define GOT_SIDEBAND_PACKFILE_DATA 1 -#define GOT_SIDEBAND_PROGRESS_INFO 2 -#define GOT_SIDEBAND_ERROR_INFO 3 - - -struct got_capability { - const char *key; - const char *value; -}; static const struct got_capability got_capabilities[] = { { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR }, { GOT_CAPA_OFS_DELTA, NULL }, @@ -153,67 +68,6 @@ static const struct got_capability got_capabilities[] { GOT_CAPA_REPORT_STATUS, NULL }, { GOT_CAPA_DELETE_REFS, NULL }, }; - -static const struct got_error * -match_capability(char **my_capabilities, const char *capa, - const struct got_capability *mycapa) -{ - char *equalsign; - char *s; - - equalsign = strchr(capa, '='); - if (equalsign) { - if (strncmp(capa, mycapa->key, equalsign - capa) != 0) - return NULL; - } else { - if (strcmp(capa, mycapa->key) != 0) - return NULL; - } - - if (asprintf(&s, "%s %s%s%s", - *my_capabilities != NULL ? *my_capabilities : "", - mycapa->key, - mycapa->value != NULL ? "=" : "", - mycapa->value != NULL? mycapa->value : "") == -1) - return got_error_from_errno("asprintf"); - - free(*my_capabilities); - *my_capabilities = s; - return NULL; -} - -static const struct got_error * -match_capabilities(char **my_capabilities, char *server_capabilities) -{ - const struct got_error *err = NULL; - char *capa; - size_t i; - - *my_capabilities = NULL; - do { - capa = strsep(&server_capabilities, " "); - for (i = 0; capa != NULL && i < nitems(got_capabilities); i++) { - err = match_capability(my_capabilities, - capa, &got_capabilities[i]); - if (err) - goto done; - } - } while (capa); - - if (*my_capabilities == NULL) { - *my_capabilities = strdup(""); - if (*my_capabilities == NULL) { - err = got_error_from_errno("strdup"); - goto done; - } - } -done: - if (err) { - free(*my_capabilities); - *my_capabilities = NULL; - } - return err; -} static const struct got_error * send_upload_progress(struct imsgbuf *ibuf, off_t bytes) @@ -500,16 +354,17 @@ send_pack(int fd, struct got_pathlist_head *refs, err = send_error(&buf[4], n - 4); goto done; } - err = parse_refline(&id_str, &refname, &server_capabilities, - buf, n); + err = got_gitproto_parse_refline(&id_str, &refname, + &server_capabilities, buf, n); if (err) goto done; if (is_firstpkt) { if (chattygot && server_capabilities[0] != '\0') fprintf(stderr, "%s: server capabilities: %s\n", getprogname(), server_capabilities); - err = match_capabilities(&my_capabilities, - server_capabilities); + err = got_gitproto_match_capabilities(&my_capabilities, + NULL, server_capabilities, got_capabilities, + nitems(got_capabilities)); if (err) goto done; if (chattygot)