Skip to content

Commit 0006ff6

Browse files
committed
clone: support sha256
1 parent 7186d7b commit 0006ff6

File tree

7 files changed

+173
-34
lines changed

7 files changed

+173
-34
lines changed

ci/test.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ cleanup() {
3232
kill $GIT_NAMESPACE_PID
3333
fi
3434

35+
if [ ! -z "$GIT_SHA256_PID" ]; then
36+
echo "Stopping git daemon (sha256)..."
37+
kill $GIT_SHA256_PID
38+
fi
39+
3540
if [ ! -z "$PROXY_BASIC_PID" ]; then
3641
echo "Stopping proxy (Basic)..."
3742
kill $PROXY_BASIC_PID
@@ -114,6 +119,12 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
114119
cp -R "${SOURCE_DIR}/tests/resources/namespace.git" "${GIT_NAMESPACE_DIR}/namespace.git"
115120
GIT_NAMESPACE="name1" git daemon --listen=localhost --port=9419 --export-all --enable=receive-pack --base-path="${GIT_NAMESPACE_DIR}" "${GIT_NAMESPACE_DIR}" &
116121
GIT_NAMESPACE_PID=$!
122+
123+
echo "Starting git daemon (sha256)..."
124+
GIT_SHA256_DIR=`mktemp -d ${TMPDIR}/git_sha256.XXXXXXXX`
125+
cp -R "${SOURCE_DIR}/tests/resources/testrepo_256.git" "${GIT_SHA256_DIR}/testrepo_256.git"
126+
git daemon --listen=localhost --port=9420 --export-all --enable=receive-pack --base-path="${GIT_SHA256_DIR}" "${GIT_SHA256_DIR}" &
127+
GIT_SHA256_PID=$!
117128
fi
118129

119130
if [ -z "$SKIP_PROXY_TESTS" ]; then
@@ -261,6 +272,14 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
261272
run_test gitdaemon_namespace
262273
unset GITTEST_REMOTE_URL
263274
unset GITTEST_REMOTE_BRANCH
275+
276+
echo ""
277+
echo "Running gitdaemon (sha256) tests"
278+
echo ""
279+
280+
export GITTEST_REMOTE_URL="git://localhost:9420/testrepo_256.git"
281+
run_test gitdaemon_sha256
282+
unset GITTEST_REMOTE_URL
264283
fi
265284

266285
if [ -z "$SKIP_PROXY_TESTS" ]; then

src/libgit2/transports/smart.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,12 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream
182182
int git_smart__update_heads(transport_smart *t, git_vector *symrefs);
183183

184184
/* smart_pkt.c */
185-
int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen);
185+
typedef struct {
186+
git_oid_t oid_type;
187+
int seen_capabilities: 1;
188+
} git_pkt_parse_data;
189+
190+
int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen, git_pkt_parse_data *data);
186191
int git_pkt_buffer_flush(git_str *buf);
187192
int git_pkt_send_flush(GIT_SOCKET s);
188193
int git_pkt_buffer_done(git_str *buf);

src/libgit2/transports/smart_pkt.c

Lines changed: 94 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -212,26 +212,87 @@ static int sideband_error_pkt(git_pkt **out, const char *line, size_t len)
212212
return 0;
213213
}
214214

215+
static int set_data(
216+
git_pkt_parse_data *data,
217+
const char *line,
218+
size_t len)
219+
{
220+
const char *caps, *format_str = NULL, *eos;
221+
size_t format_len;
222+
git_oid_t remote_oid_type;
223+
224+
GIT_ASSERT_ARG(data);
225+
226+
if ((caps = memchr(line, '\0', len)) != NULL) {
227+
caps++;
228+
229+
if (strncmp(caps, "object-format=", CONST_STRLEN("object-format=")) == 0)
230+
format_str = caps + CONST_STRLEN("object-format=");
231+
else if ((format_str = strstr(caps, " object-format=")) != NULL)
232+
format_str += CONST_STRLEN(" object-format=");
233+
}
234+
235+
if (format_str) {
236+
if ((eos = strchr(format_str, ' ')) == NULL)
237+
eos = strchr(format_str, '\0');
238+
239+
GIT_ASSERT(eos);
240+
241+
format_len = eos - format_str;
242+
243+
if ((remote_oid_type = git_oid_type_fromstrn(format_str, format_len)) == 0) {
244+
git_error_set(GIT_ERROR_INVALID, "unknown remote object format '%.*s'", (int)format_len, format_str);
245+
return -1;
246+
}
247+
} else {
248+
remote_oid_type = GIT_OID_SHA1;
249+
}
250+
251+
if (!data->oid_type) {
252+
data->oid_type = remote_oid_type;
253+
} else if (data->oid_type != remote_oid_type) {
254+
git_error_set(GIT_ERROR_INVALID,
255+
"the local object format '%s' does not match the remote object format '%s'",
256+
git_oid_type_name(data->oid_type),
257+
git_oid_type_name(remote_oid_type));
258+
return -1;
259+
}
260+
261+
return 0;
262+
}
263+
215264
/*
216265
* Parse an other-ref line.
217266
*/
218-
static int ref_pkt(git_pkt **out, const char *line, size_t len)
267+
static int ref_pkt(
268+
git_pkt **out,
269+
const char *line,
270+
size_t len,
271+
git_pkt_parse_data *data)
219272
{
220273
git_pkt_ref *pkt;
221-
size_t alloclen;
274+
size_t alloclen, oid_hexsize;
222275

223276
pkt = git__calloc(1, sizeof(git_pkt_ref));
224277
GIT_ERROR_CHECK_ALLOC(pkt);
225278
pkt->type = GIT_PKT_REF;
226279

227-
if (len < GIT_OID_SHA1_HEXSIZE ||
228-
git_oid__fromstr(&pkt->head.oid, line, GIT_OID_SHA1) < 0)
280+
/* Determine OID type from capabilities */
281+
if (!data->seen_capabilities && set_data(data, line, len) < 0)
282+
return -1;
283+
284+
GIT_ASSERT(data->oid_type);
285+
oid_hexsize = git_oid_hexsize(data->oid_type);
286+
287+
if (len < oid_hexsize ||
288+
git_oid__fromstr(&pkt->head.oid, line, data->oid_type) < 0)
229289
goto out_err;
230-
line += GIT_OID_SHA1_HEXSIZE;
231-
len -= GIT_OID_SHA1_HEXSIZE;
290+
line += oid_hexsize;
291+
len -= oid_hexsize;
232292

233293
if (git__prefixncmp(line, len, " "))
234294
goto out_err;
295+
235296
line++;
236297
len--;
237298

@@ -248,8 +309,14 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len)
248309
memcpy(pkt->head.name, line, len);
249310
pkt->head.name[len] = '\0';
250311

251-
if (strlen(pkt->head.name) < len)
252-
pkt->capabilities = strchr(pkt->head.name, '\0') + 1;
312+
if (strlen(pkt->head.name) < len) {
313+
if (!data->seen_capabilities)
314+
pkt->capabilities = strchr(pkt->head.name, '\0') + 1;
315+
else
316+
goto out_err;
317+
}
318+
319+
data->seen_capabilities = 1;
253320

254321
*out = (git_pkt *)pkt;
255322
return 0;
@@ -418,7 +485,11 @@ static int parse_len(size_t *out, const char *line, size_t linelen)
418485
*/
419486

420487
int git_pkt_parse_line(
421-
git_pkt **pkt, const char **endptr, const char *line, size_t linelen)
488+
git_pkt **pkt,
489+
const char **endptr,
490+
const char *line,
491+
size_t linelen,
492+
git_pkt_parse_data *data)
422493
{
423494
int error;
424495
size_t len;
@@ -493,7 +564,7 @@ int git_pkt_parse_line(
493564
else if (!git__prefixncmp(line, len, "unpack"))
494565
error = unpack_pkt(pkt, line, len);
495566
else
496-
error = ref_pkt(pkt, line, len);
567+
error = ref_pkt(pkt, line, len, data);
497568

498569
*endptr = line + len;
499570

@@ -533,8 +604,11 @@ int git_pkt_buffer_flush(git_str *buf)
533604
static int buffer_want_with_caps(const git_remote_head *head, transport_smart_caps *caps, git_str *buf)
534605
{
535606
git_str str = GIT_STR_INIT;
536-
char oid[GIT_OID_SHA1_HEXSIZE +1] = {0};
537-
size_t len;
607+
char oid[GIT_OID_MAX_HEXSIZE + 1] = {0};
608+
size_t oid_hexsize, len;
609+
610+
oid_hexsize = git_oid_hexsize(head->oid.type);
611+
git_oid_fmt(oid, &head->oid);
538612

539613
/* Prefer multi_ack_detailed */
540614
if (caps->multi_ack_detailed)
@@ -560,7 +634,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
560634
if (git_str_oom(&str))
561635
return -1;
562636

563-
len = strlen("XXXXwant ") + GIT_OID_SHA1_HEXSIZE + 1 /* NUL */ +
637+
len = strlen("XXXXwant ") + oid_hexsize + 1 /* NUL */ +
564638
git_str_len(&str) + 1 /* LF */;
565639

566640
if (len > 0xffff) {
@@ -570,9 +644,9 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
570644
}
571645

572646
git_str_grow_by(buf, len);
573-
git_oid_fmt(oid, &head->oid);
574647
git_str_printf(buf,
575-
"%04xwant %s %s\n", (unsigned int)len, oid, git_str_cstr(&str));
648+
"%04xwant %.*s %s\n", (unsigned int)len,
649+
(int)oid_hexsize, oid, git_str_cstr(&str));
576650
git_str_dispose(&str);
577651

578652
GIT_ERROR_CHECK_ALLOC_STR(buf);
@@ -608,16 +682,19 @@ int git_pkt_buffer_wants(
608682
}
609683

610684
for (; i < count; ++i) {
611-
char oid[GIT_OID_SHA1_HEXSIZE];
685+
char oid[GIT_OID_MAX_HEXSIZE];
612686

613687
head = refs[i];
688+
614689
if (head->local)
615690
continue;
616691

617692
git_oid_fmt(oid, &head->oid);
693+
618694
git_str_put(buf, pkt_want_prefix, strlen(pkt_want_prefix));
619-
git_str_put(buf, oid, GIT_OID_SHA1_HEXSIZE);
695+
git_str_put(buf, oid, git_oid_hexsize(head->oid.type));
620696
git_str_putc(buf, '\n');
697+
621698
if (git_str_oom(buf))
622699
return -1;
623700
}

src/libgit2/transports/smart_protocol.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ int git_smart__store_refs(transport_smart *t, int flushes)
3232
int error, flush = 0, recvd;
3333
const char *line_end = NULL;
3434
git_pkt *pkt = NULL;
35+
git_pkt_parse_data pkt_parse_data = { 0 };
3536
size_t i;
3637

3738
/* 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)
4546

4647
do {
4748
if (buf->offset > 0)
48-
error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset);
49+
error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset, &pkt_parse_data);
4950
else
5051
error = GIT_EBUFS;
5152

@@ -228,11 +229,12 @@ static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf
228229
{
229230
const char *ptr = buf->data, *line_end = ptr;
230231
git_pkt *pkt = NULL;
232+
git_pkt_parse_data pkt_parse_data = { 0 };
231233
int error = 0, ret;
232234

233235
do {
234236
if (buf->offset > 0)
235-
error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset);
237+
error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset, &pkt_parse_data);
236238
else
237239
error = GIT_EBUFS;
238240

@@ -723,6 +725,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
723725
static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, git_str *data_pkt_buf)
724726
{
725727
git_pkt *pkt;
728+
git_pkt_parse_data pkt_parse_data = { 0 };
726729
const char *line, *line_end = NULL;
727730
size_t line_len;
728731
int error;
@@ -741,7 +744,7 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt,
741744
}
742745

743746
while (line_len > 0) {
744-
error = git_pkt_parse_line(&pkt, &line_end, line, line_len);
747+
error = git_pkt_parse_line(&pkt, &line_end, line, line_len, &pkt_parse_data);
745748

746749
if (error == GIT_EBUFS) {
747750
/* Buffer the data when the inner packet is split
@@ -777,6 +780,7 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt,
777780
static int parse_report(transport_smart *transport, git_push *push)
778781
{
779782
git_pkt *pkt = NULL;
783+
git_pkt_parse_data pkt_parse_data = { 0 };
780784
const char *line_end = NULL;
781785
gitno_buffer *buf = &transport->buffer;
782786
int error, recvd;
@@ -785,7 +789,8 @@ static int parse_report(transport_smart *transport, git_push *push)
785789
for (;;) {
786790
if (buf->offset > 0)
787791
error = git_pkt_parse_line(&pkt, &line_end,
788-
buf->data, buf->offset);
792+
buf->data, buf->offset,
793+
&pkt_parse_data);
789794
else
790795
error = GIT_EBUFS;
791796

tests/libgit2/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ add_clar_test(libgit2_tests online -v -sonline -xonline::customcert
7070
add_clar_test(libgit2_tests online_customcert -v -sonline::customcert)
7171
add_clar_test(libgit2_tests gitdaemon -v -sonline::push)
7272
add_clar_test(libgit2_tests gitdaemon_namespace -v -sonline::clone::namespace)
73+
add_clar_test(libgit2_tests gitdaemon_sha256 -v -sonline::clone::sha256)
7374
add_clar_test(libgit2_tests ssh -v -sonline::push -sonline::clone::ssh_cert -sonline::clone::ssh_with_paths -sonline::clone::path_whitespace_ssh -sonline::clone::ssh_auth_methods)
7475
add_clar_test(libgit2_tests proxy -v -sonline::clone::proxy)
7576
add_clar_test(libgit2_tests auth_clone -v -sonline::clone::cred)

tests/libgit2/online/clone.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,3 +1058,22 @@ void test_online_clone__namespace_with_specified_branch(void)
10581058

10591059
git_reference_free(head);
10601060
}
1061+
1062+
void test_online_clone__sha256(void)
1063+
{
1064+
#ifndef GIT_EXPERIMENTAL_SHA256
1065+
cl_skip();
1066+
#else
1067+
git_clone_options options = GIT_CLONE_OPTIONS_INIT;
1068+
git_reference *head;
1069+
1070+
if (!_remote_url)
1071+
cl_skip();
1072+
1073+
cl_git_pass(git_clone(&g_repo, _remote_url, "./sha256", &options));
1074+
cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE));
1075+
cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head));
1076+
1077+
git_reference_free(head);
1078+
#endif
1079+
}

0 commit comments

Comments
 (0)