summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2022-11-23 22:05:29 +0000
committerEdward Thomson <ethomson@edwardthomson.com>2023-02-12 22:02:00 +0000
commit0006ff63359358bc5e65ea5a2b6ef7ba5eca2e8e (patch)
tree718faf6e1bb532226d155de91897e4f4bf2bb227 /src
parent7186d7baadfe3e5e129710e07bdd57b1c7c0e862 (diff)
downloadlibgit2-0006ff63359358bc5e65ea5a2b6ef7ba5eca2e8e.tar.gz
clone: support sha256
Diffstat (limited to 'src')
-rw-r--r--src/libgit2/transports/smart.h7
-rw-r--r--src/libgit2/transports/smart_pkt.c111
-rw-r--r--src/libgit2/transports/smart_protocol.c13
3 files changed, 109 insertions, 22 deletions
diff --git a/src/libgit2/transports/smart.h b/src/libgit2/transports/smart.h
index 9323d6c44..ca6496163 100644
--- a/src/libgit2/transports/smart.h
+++ b/src/libgit2/transports/smart.h
@@ -182,7 +182,12 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream
int git_smart__update_heads(transport_smart *t, git_vector *symrefs);
/* smart_pkt.c */
-int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen);
+typedef struct {
+ git_oid_t oid_type;
+ int seen_capabilities: 1;
+} git_pkt_parse_data;
+
+int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen, git_pkt_parse_data *data);
int git_pkt_buffer_flush(git_str *buf);
int git_pkt_send_flush(GIT_SOCKET s);
int git_pkt_buffer_done(git_str *buf);
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;
}
diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c
index 88c208fb5..86d02df83 100644
--- a/src/libgit2/transports/smart_protocol.c
+++ b/src/libgit2/transports/smart_protocol.c
@@ -32,6 +32,7 @@ int git_smart__store_refs(transport_smart *t, int flushes)
int error, flush = 0, recvd;
const char *line_end = NULL;
git_pkt *pkt = NULL;
+ git_pkt_parse_data pkt_parse_data = { 0 };
size_t i;
/* Clear existing refs in case git_remote_connect() is called again
@@ -45,7 +46,7 @@ int git_smart__store_refs(transport_smart *t, int flushes)
do {
if (buf->offset > 0)
- error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset);
+ error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset, &pkt_parse_data);
else
error = GIT_EBUFS;
@@ -228,11 +229,12 @@ static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf
{
const char *ptr = buf->data, *line_end = ptr;
git_pkt *pkt = NULL;
+ git_pkt_parse_data pkt_parse_data = { 0 };
int error = 0, ret;
do {
if (buf->offset > 0)
- error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset);
+ error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset, &pkt_parse_data);
else
error = GIT_EBUFS;
@@ -723,6 +725,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, git_str *data_pkt_buf)
{
git_pkt *pkt;
+ git_pkt_parse_data pkt_parse_data = { 0 };
const char *line, *line_end = NULL;
size_t line_len;
int error;
@@ -741,7 +744,7 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt,
}
while (line_len > 0) {
- error = git_pkt_parse_line(&pkt, &line_end, line, line_len);
+ error = git_pkt_parse_line(&pkt, &line_end, line, line_len, &pkt_parse_data);
if (error == GIT_EBUFS) {
/* Buffer the data when the inner packet is split
@@ -777,6 +780,7 @@ done:
static int parse_report(transport_smart *transport, git_push *push)
{
git_pkt *pkt = NULL;
+ git_pkt_parse_data pkt_parse_data = { 0 };
const char *line_end = NULL;
gitno_buffer *buf = &transport->buffer;
int error, recvd;
@@ -785,7 +789,8 @@ static int parse_report(transport_smart *transport, git_push *push)
for (;;) {
if (buf->offset > 0)
error = git_pkt_parse_line(&pkt, &line_end,
- buf->data, buf->offset);
+ buf->data, buf->offset,
+ &pkt_parse_data);
else
error = GIT_EBUFS;