diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2022-11-23 22:05:29 +0000 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2022-11-23 22:12:00 +0000 |
commit | fb36b3e9e06ba2b50163c34c99adf0257d5c0d12 (patch) | |
tree | 13919fe5c87945b60c17660ff2ee498fa487a43f /src/libgit2/transports/smart_pkt.c | |
parent | 31e65bb11202a9f7ca247fa7b9bb11bf88d5f18b (diff) | |
download | libgit2-ethomson/sha256_experimental-old.tar.gz |
clone: support sha256ethomson/sha256_experimental-old
Diffstat (limited to 'src/libgit2/transports/smart_pkt.c')
-rw-r--r-- | src/libgit2/transports/smart_pkt.c | 111 |
1 files changed, 94 insertions, 17 deletions
diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c index e679819fa..b6428d845 100644 --- a/src/libgit2/transports/smart_pkt.c +++ b/src/libgit2/transports/smart_pkt.c @@ -212,26 +212,87 @@ static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) return 0; } +static int set_data( + git_pkt_parse_data *data, + const char *line, + size_t len) +{ + const char *caps, *format_str = NULL, *eos; + size_t format_len; + git_oid_t remote_oid_type; + + GIT_ASSERT_ARG(data); + + if ((caps = memchr(line, '\0', len)) != NULL) { + caps++; + + if (strncmp(caps, "object-format=", CONST_STRLEN("object-format=")) == 0) + format_str = caps + CONST_STRLEN("object-format="); + else if ((format_str = strstr(caps, " object-format=")) != NULL) + format_str += CONST_STRLEN(" object-format="); + } + + if (format_str) { + if ((eos = strchr(format_str, ' ')) == NULL) + eos = strchr(format_str, '\0'); + + GIT_ASSERT(eos); + + format_len = eos - format_str; + + if ((remote_oid_type = git_oid_type_fromstrn(format_str, format_len)) == 0) { + git_error_set(GIT_ERROR_INVALID, "unknown remote object format '%.*s'", (int)format_len, format_str); + return -1; + } + } else { + remote_oid_type = GIT_OID_SHA1; + } + + if (!data->oid_type) { + data->oid_type = remote_oid_type; + } else if (data->oid_type != remote_oid_type) { + git_error_set(GIT_ERROR_INVALID, + "the local object format '%s' does not match the remote object format '%s'", + git_oid_type_name(data->oid_type), + git_oid_type_name(remote_oid_type)); + return -1; + } + + return 0; +} + /* * Parse an other-ref line. */ -static int ref_pkt(git_pkt **out, const char *line, size_t len) +static int ref_pkt( + git_pkt **out, + const char *line, + size_t len, + git_pkt_parse_data *data) { git_pkt_ref *pkt; - size_t alloclen; + size_t alloclen, oid_hexsize; pkt = git__calloc(1, sizeof(git_pkt_ref)); GIT_ERROR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_REF; - if (len < GIT_OID_SHA1_HEXSIZE || - git_oid__fromstr(&pkt->head.oid, line, GIT_OID_SHA1) < 0) + /* Determine OID type from capabilities */ + if (!data->seen_capabilities && set_data(data, line, len) < 0) + return -1; + + GIT_ASSERT(data->oid_type); + oid_hexsize = git_oid_hexsize(data->oid_type); + + if (len < oid_hexsize || + git_oid__fromstr(&pkt->head.oid, line, data->oid_type) < 0) goto out_err; - line += GIT_OID_SHA1_HEXSIZE; - len -= GIT_OID_SHA1_HEXSIZE; + line += oid_hexsize; + len -= oid_hexsize; if (git__prefixncmp(line, len, " ")) goto out_err; + line++; len--; @@ -248,8 +309,14 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len) memcpy(pkt->head.name, line, len); pkt->head.name[len] = '\0'; - if (strlen(pkt->head.name) < len) - pkt->capabilities = strchr(pkt->head.name, '\0') + 1; + if (strlen(pkt->head.name) < len) { + if (!data->seen_capabilities) + pkt->capabilities = strchr(pkt->head.name, '\0') + 1; + else + goto out_err; + } + + data->seen_capabilities = 1; *out = (git_pkt *)pkt; return 0; @@ -418,7 +485,11 @@ static int parse_len(size_t *out, const char *line, size_t linelen) */ int git_pkt_parse_line( - git_pkt **pkt, const char **endptr, const char *line, size_t linelen) + git_pkt **pkt, + const char **endptr, + const char *line, + size_t linelen, + git_pkt_parse_data *data) { int error; size_t len; @@ -493,7 +564,7 @@ int git_pkt_parse_line( else if (!git__prefixncmp(line, len, "unpack")) error = unpack_pkt(pkt, line, len); else - error = ref_pkt(pkt, line, len); + error = ref_pkt(pkt, line, len, data); *endptr = line + len; @@ -533,8 +604,11 @@ int git_pkt_buffer_flush(git_str *buf) static int buffer_want_with_caps(const git_remote_head *head, transport_smart_caps *caps, git_str *buf) { git_str str = GIT_STR_INIT; - char oid[GIT_OID_SHA1_HEXSIZE +1] = {0}; - size_t len; + char oid[GIT_OID_MAX_HEXSIZE + 1] = {0}; + size_t oid_hexsize, len; + + oid_hexsize = git_oid_hexsize(head->oid.type); + git_oid_fmt(oid, &head->oid); /* Prefer multi_ack_detailed */ if (caps->multi_ack_detailed) @@ -560,7 +634,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca if (git_str_oom(&str)) return -1; - len = strlen("XXXXwant ") + GIT_OID_SHA1_HEXSIZE + 1 /* NUL */ + + len = strlen("XXXXwant ") + oid_hexsize + 1 /* NUL */ + git_str_len(&str) + 1 /* LF */; if (len > 0xffff) { @@ -570,9 +644,9 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca } git_str_grow_by(buf, len); - git_oid_fmt(oid, &head->oid); git_str_printf(buf, - "%04xwant %s %s\n", (unsigned int)len, oid, git_str_cstr(&str)); + "%04xwant %.*s %s\n", (unsigned int)len, + (int)oid_hexsize, oid, git_str_cstr(&str)); git_str_dispose(&str); GIT_ERROR_CHECK_ALLOC_STR(buf); @@ -608,16 +682,19 @@ int git_pkt_buffer_wants( } for (; i < count; ++i) { - char oid[GIT_OID_SHA1_HEXSIZE]; + char oid[GIT_OID_MAX_HEXSIZE]; head = refs[i]; + if (head->local) continue; git_oid_fmt(oid, &head->oid); + git_str_put(buf, pkt_want_prefix, strlen(pkt_want_prefix)); - git_str_put(buf, oid, GIT_OID_SHA1_HEXSIZE); + git_str_put(buf, oid, git_oid_hexsize(head->oid.type)); git_str_putc(buf, '\n'); + if (git_str_oom(buf)) return -1; } |