summaryrefslogtreecommitdiff
path: root/src/libgit2/transports/smart_pkt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libgit2/transports/smart_pkt.c')
-rw-r--r--src/libgit2/transports/smart_pkt.c149
1 files changed, 135 insertions, 14 deletions
diff --git a/src/libgit2/transports/smart_pkt.c b/src/libgit2/transports/smart_pkt.c
index 5fce42175..9127ad5fe 100644
--- a/src/libgit2/transports/smart_pkt.c
+++ b/src/libgit2/transports/smart_pkt.c
@@ -44,9 +44,16 @@ static int flush_pkt(git_pkt **out)
}
/* the rest of the line will be useful for multi_ack and multi_ack_detailed */
-static int ack_pkt(git_pkt **out, const char *line, size_t len)
+static int ack_pkt(
+ git_pkt **out,
+ const char *line,
+ size_t len,
+ git_pkt_parse_data *data)
{
git_pkt_ack *pkt;
+ size_t oid_hexsize = git_oid_hexsize(data->oid_type);
+
+ GIT_ASSERT(data && data->oid_type);
pkt = git__calloc(1, sizeof(git_pkt_ack));
GIT_ERROR_CHECK_ALLOC(pkt);
@@ -57,11 +64,11 @@ static int ack_pkt(git_pkt **out, const char *line, size_t len)
line += 4;
len -= 4;
- if (len < GIT_OID_SHA1_HEXSIZE ||
- git_oid__fromstr(&pkt->oid, line, GIT_OID_SHA1) < 0)
+ if (len < oid_hexsize ||
+ git_oid__fromstr(&pkt->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 (len && line[0] == ' ') {
line++;
@@ -436,6 +443,84 @@ static int unpack_pkt(git_pkt **out, const char *line, size_t len)
return 0;
}
+static int shallow_pkt(
+ git_pkt **out,
+ const char *line,
+ size_t len,
+ git_pkt_parse_data *data)
+{
+ git_pkt_shallow *pkt;
+ size_t oid_hexsize = git_oid_hexsize(data->oid_type);
+
+ GIT_ASSERT(data && data->oid_type);
+
+ pkt = git__calloc(1, sizeof(git_pkt_shallow));
+ GIT_ERROR_CHECK_ALLOC(pkt);
+
+ pkt->type = GIT_PKT_SHALLOW;
+
+ if (git__prefixncmp(line, len, "shallow "))
+ goto out_err;
+
+ line += 8;
+ len -= 8;
+
+ if (len != oid_hexsize)
+ goto out_err;
+
+ git_oid__fromstr(&pkt->oid, line, data->oid_type);
+ line += oid_hexsize + 1;
+ len -= oid_hexsize + 1;
+
+ *out = (git_pkt *)pkt;
+
+ return 0;
+
+out_err:
+ git_error_set(GIT_ERROR_NET, "invalid packet line");
+ git__free(pkt);
+ return -1;
+}
+
+static int unshallow_pkt(
+ git_pkt **out,
+ const char *line,
+ size_t len,
+ git_pkt_parse_data *data)
+{
+ git_pkt_shallow *pkt;
+ size_t oid_hexsize = git_oid_hexsize(data->oid_type);
+
+ GIT_ASSERT(data && data->oid_type);
+
+ pkt = git__calloc(1, sizeof(git_pkt_shallow));
+ GIT_ERROR_CHECK_ALLOC(pkt);
+
+ pkt->type = GIT_PKT_UNSHALLOW;
+
+ if (git__prefixncmp(line, len, "unshallow "))
+ goto out_err;
+
+ line += 10;
+ len -= 10;
+
+ if (len != oid_hexsize)
+ goto out_err;
+
+ git_oid__fromstr(&pkt->oid, line, data->oid_type);
+ line += oid_hexsize + 1;
+ len -= oid_hexsize + 1;
+
+ *out = (git_pkt *) pkt;
+
+ return 0;
+
+out_err:
+ git_error_set(GIT_ERROR_NET, "invalid packet line");
+ git__free(pkt);
+ return -1;
+}
+
static int parse_len(size_t *out, const char *line, size_t linelen)
{
char num[PKT_LEN_SIZE + 1];
@@ -553,7 +638,7 @@ int git_pkt_parse_line(
else if (*line == GIT_SIDE_BAND_ERROR)
error = sideband_error_pkt(pkt, line, len);
else if (!git__prefixncmp(line, len, "ACK"))
- error = ack_pkt(pkt, line, len);
+ error = ack_pkt(pkt, line, len, data);
else if (!git__prefixncmp(line, len, "NAK"))
error = nak_pkt(pkt);
else if (!git__prefixncmp(line, len, "ERR"))
@@ -566,6 +651,10 @@ int git_pkt_parse_line(
error = ng_pkt(pkt, line, len);
else if (!git__prefixncmp(line, len, "unpack"))
error = unpack_pkt(pkt, line, len);
+ else if (!git__prefixcmp(line, "shallow"))
+ error = shallow_pkt(pkt, line, len, data);
+ else if (!git__prefixcmp(line, "unshallow"))
+ error = unshallow_pkt(pkt, line, len, data);
else
error = ref_pkt(pkt, line, len, data);
@@ -638,6 +727,9 @@ static int buffer_want_with_caps(
if (caps->ofs_delta)
git_str_puts(&str, GIT_CAP_OFS_DELTA " ");
+ if (caps->shallow)
+ git_str_puts(&str, GIT_CAP_SHALLOW " ");
+
if (git_str_oom(&str))
return -1;
@@ -668,8 +760,7 @@ static int buffer_want_with_caps(
*/
int git_pkt_buffer_wants(
- const git_remote_head * const *refs,
- size_t count,
+ const git_fetch_negotiation *wants,
transport_smart_caps *caps,
git_str *buf)
{
@@ -679,7 +770,7 @@ int git_pkt_buffer_wants(
size_t oid_hexsize, want_len, i = 0;
#ifdef GIT_EXPERIMENTAL_SHA256
- oid_type = count > 0 ? refs[0]->oid.type : GIT_OID_SHA1;
+ oid_type = wants->refs_len > 0 ? wants->refs[0]->oid.type : GIT_OID_SHA1;
#else
oid_type = GIT_OID_SHA1;
#endif
@@ -690,20 +781,20 @@ int git_pkt_buffer_wants(
oid_hexsize + 1 /* LF */;
if (caps->common) {
- for (; i < count; ++i) {
- head = refs[i];
+ for (; i < wants->refs_len; ++i) {
+ head = wants->refs[i];
if (!head->local)
break;
}
- if (buffer_want_with_caps(refs[i], caps, oid_type, buf) < 0)
+ if (buffer_want_with_caps(wants->refs[i], caps, oid_type, buf) < 0)
return -1;
i++;
}
- for (; i < count; ++i) {
- head = refs[i];
+ for (; i < wants->refs_len; ++i) {
+ head = wants->refs[i];
if (head->local)
continue;
@@ -718,6 +809,36 @@ int git_pkt_buffer_wants(
return -1;
}
+ /* Tell the server about our shallow objects */
+ for (i = 0; i < wants->shallow_roots_len; i++) {
+ char oid[GIT_OID_MAX_HEXSIZE + 1];
+ git_str shallow_buf = GIT_STR_INIT;
+
+ git_oid_tostr(oid, GIT_OID_MAX_HEXSIZE + 1, &wants->shallow_roots[i]);
+ git_str_puts(&shallow_buf, "shallow ");
+ git_str_puts(&shallow_buf, oid);
+ git_str_putc(&shallow_buf, '\n');
+
+ git_str_printf(buf, "%04x%s", (unsigned int)git_str_len(&shallow_buf) + 4, git_str_cstr(&shallow_buf));
+
+ git_str_dispose(&shallow_buf);
+
+ if (git_str_oom(buf))
+ return -1;
+ }
+
+ if (wants->depth > 0) {
+ git_str deepen_buf = GIT_STR_INIT;
+
+ git_str_printf(&deepen_buf, "deepen %d\n", wants->depth);
+ git_str_printf(buf,"%04x%s", (unsigned int)git_str_len(&deepen_buf) + 4, git_str_cstr(&deepen_buf));
+
+ git_str_dispose(&deepen_buf);
+
+ if (git_str_oom(buf))
+ return -1;
+ }
+
return git_pkt_buffer_flush(buf);
}