Skip to content

Commit 53fcd5b

Browse files
committed
transport: teach transports about oid types and SHA256
1 parent 0006ff6 commit 53fcd5b

File tree

13 files changed

+298
-83
lines changed

13 files changed

+298
-83
lines changed

include/git2/sys/transport.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ struct git_transport {
5757
unsigned int *capabilities,
5858
git_transport *transport);
5959

60+
#ifdef GIT_EXPERIMENTAL_SHA256
61+
/**
62+
* Gets the object type for the remote repository.
63+
*
64+
* This function may be called after a successful call to
65+
* `connect()`.
66+
*/
67+
int GIT_CALLBACK(oid_type)(
68+
git_oid_t *object_type,
69+
git_transport *transport);
70+
#endif
71+
6072
/**
6173
* Get the list of available references in the remote repository.
6274
*

src/libgit2/clone.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,12 +393,19 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c
393393
return error;
394394
}
395395

396-
static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch_options *opts, const git_checkout_options *co_opts, const char *branch)
396+
static int clone_into(
397+
git_repository *repo,
398+
git_remote *_remote,
399+
const git_fetch_options *opts,
400+
const git_checkout_options *co_opts,
401+
const char *branch)
397402
{
398403
int error;
399404
git_str reflog_message = GIT_STR_INIT;
405+
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
400406
git_fetch_options fetch_opts;
401407
git_remote *remote;
408+
git_oid_t oid_type;
402409

403410
GIT_ASSERT_ARG(repo);
404411
GIT_ASSERT_ARG(_remote);
@@ -414,8 +421,25 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch
414421
memcpy(&fetch_opts, opts, sizeof(git_fetch_options));
415422
fetch_opts.update_fetchhead = 0;
416423
fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
424+
425+
if ((error = git_remote_connect_options__from_fetch_opts(&connect_opts, remote, &fetch_opts)) < 0)
426+
return error;
427+
417428
git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote));
418429

430+
/*
431+
* Connect to the server so that we can identify the remote
432+
* object format.
433+
*/
434+
435+
if ((error = git_remote_connect_ext(remote, GIT_DIRECTION_FETCH,
436+
&connect_opts)) < 0)
437+
goto cleanup;
438+
439+
if ((error = git_remote_oid_type(&oid_type, remote)) < 0 ||
440+
(error = git_repository__set_objectformat(repo, oid_type)) < 0)
441+
goto cleanup;
442+
419443
if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_str_cstr(&reflog_message))) != 0)
420444
goto cleanup;
421445

src/libgit2/fetch.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts)
9595
git_remote_head **heads;
9696
git_refspec tagspec, head, *spec;
9797
int error = 0;
98-
git_odb *odb;
9998
size_t i, heads_len;
10099
unsigned int remote_caps;
101100
unsigned int oid_mask = GIT_REMOTE_CAPABILITY_TIP_OID |
@@ -126,9 +125,6 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts)
126125
goto cleanup;
127126
}
128127

129-
if ((error = git_repository_odb__weakptr(&odb, remote->repo)) < 0)
130-
goto cleanup;
131-
132128
if ((error = git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote)) < 0 ||
133129
(error = git_remote_capabilities(&remote_caps, remote)) < 0)
134130
goto cleanup;

src/libgit2/indexer.c

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ struct git_indexer {
5656
git_vector deltas;
5757
unsigned int fanout[256];
5858
git_hash_ctx hash_ctx;
59-
unsigned char checksum[GIT_HASH_SHA1_SIZE];
60-
char name[(GIT_HASH_SHA1_SIZE * 2) + 1];
59+
unsigned char checksum[GIT_HASH_MAX_SIZE];
60+
char name[(GIT_HASH_MAX_SIZE * 2) + 1];
6161
git_indexer_progress_cb progress_cb;
6262
void *progress_payload;
6363
char objbuf[8*1024];
@@ -69,7 +69,7 @@ struct git_indexer {
6969
git_odb *odb;
7070

7171
/* Fields for calculating the packfile trailer (hash of everything before it) */
72-
char inbuf[GIT_OID_MAX_SIZE];
72+
char inbuf[GIT_HASH_MAX_SIZE];
7373
size_t inbuf_len;
7474
git_hash_ctx trailer;
7575
};
@@ -137,6 +137,20 @@ int git_indexer_init_options(git_indexer_options *opts, unsigned int version)
137137
}
138138
#endif
139139

140+
GIT_INLINE(git_hash_algorithm_t) indexer_hash_algorithm(git_indexer *idx)
141+
{
142+
switch (idx->oid_type) {
143+
case GIT_OID_SHA1:
144+
return GIT_HASH_ALGORITHM_SHA1;
145+
#ifdef GIT_EXPERIMENTAL_SHA256
146+
case GIT_OID_SHA256:
147+
return GIT_HASH_ALGORITHM_SHA256;
148+
#endif
149+
}
150+
151+
return GIT_HASH_ALGORITHM_NONE;
152+
}
153+
140154
static int indexer_new(
141155
git_indexer **out,
142156
const char *prefix,
@@ -149,6 +163,7 @@ static int indexer_new(
149163
git_indexer *idx;
150164
git_str path = GIT_STR_INIT, tmp_path = GIT_STR_INIT;
151165
static const char suff[] = "/pack";
166+
git_hash_algorithm_t checksum_type;
152167
int error, fd = -1;
153168

154169
if (in_opts)
@@ -163,8 +178,10 @@ static int indexer_new(
163178
idx->mode = mode ? mode : GIT_PACK_FILE_MODE;
164179
git_str_init(&idx->entry_data, 0);
165180

166-
if ((error = git_hash_ctx_init(&idx->hash_ctx, GIT_HASH_ALGORITHM_SHA1)) < 0 ||
167-
(error = git_hash_ctx_init(&idx->trailer, GIT_HASH_ALGORITHM_SHA1)) < 0 ||
181+
checksum_type = indexer_hash_algorithm(idx);
182+
183+
if ((error = git_hash_ctx_init(&idx->hash_ctx, checksum_type)) < 0 ||
184+
(error = git_hash_ctx_init(&idx->trailer, checksum_type)) < 0 ||
168185
(error = git_oidmap_new(&idx->expected_oids)) < 0)
169186
goto cleanup;
170187

@@ -182,8 +199,7 @@ static int indexer_new(
182199
if (fd < 0)
183200
goto cleanup;
184201

185-
/* TODO: SHA256 */
186-
error = git_packfile_alloc(&idx->pack, git_str_cstr(&tmp_path), 0);
202+
error = git_packfile_alloc(&idx->pack, git_str_cstr(&tmp_path), oid_type);
187203
git_str_dispose(&tmp_path);
188204

189205
if (error < 0)
@@ -614,7 +630,7 @@ static int do_progress_callback(git_indexer *idx, git_indexer_progress *stats)
614630
return 0;
615631
}
616632

617-
/* Hash everything but the last 20B of input */
633+
/* Hash everything but the checksum trailer */
618634
static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
619635
{
620636
size_t to_expell, to_keep;
@@ -623,7 +639,10 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
623639
if (size == 0)
624640
return;
625641

626-
/* Easy case, dump the buffer and the data minus the last 20 bytes */
642+
/*
643+
* Easy case, dump the buffer and the data minus the trailing
644+
* checksum (SHA1 or SHA256).
645+
*/
627646
if (size >= oid_size) {
628647
git_hash_update(&idx->trailer, idx->inbuf, idx->inbuf_len);
629648
git_hash_update(&idx->trailer, data, size - oid_size);
@@ -761,12 +780,14 @@ static int read_stream_object(git_indexer *idx, git_indexer_progress *stats)
761780
{
762781
git_packfile_stream *stream = &idx->stream;
763782
off64_t entry_start = idx->off;
764-
size_t entry_size;
783+
size_t oid_size, entry_size;
765784
git_object_t type;
766785
git_mwindow *w = NULL;
767786
int error;
768787

769-
if (idx->pack->mwf.size <= idx->off + 20)
788+
oid_size = git_oid_size(idx->oid_type);
789+
790+
if (idx->pack->mwf.size <= idx->off + (long long)oid_size)
770791
return GIT_EBUFS;
771792

772793
if (!idx->have_stream) {
@@ -963,15 +984,17 @@ static int inject_object(git_indexer *idx, git_oid *id)
963984
git_odb_object *obj = NULL;
964985
struct entry *entry = NULL;
965986
struct git_pack_entry *pentry = NULL;
966-
unsigned char empty_checksum[GIT_HASH_SHA1_SIZE] = {0};
987+
unsigned char empty_checksum[GIT_HASH_MAX_SIZE] = {0};
967988
unsigned char hdr[64];
968989
git_str buf = GIT_STR_INIT;
969990
off64_t entry_start;
970991
const void *data;
971992
size_t len, hdr_len;
972-
size_t checksum_size = GIT_HASH_SHA1_SIZE;
993+
size_t checksum_size;
973994
int error;
974995

996+
checksum_size = git_hash_size(indexer_hash_algorithm(idx));
997+
975998
if ((error = seek_back_trailer(idx)) < 0)
976999
goto cleanup;
9771000

@@ -1205,17 +1228,20 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
12051228
struct git_pack_idx_header hdr;
12061229
git_str filename = GIT_STR_INIT;
12071230
struct entry *entry;
1208-
unsigned char checksum[GIT_HASH_SHA1_SIZE];
1231+
unsigned char checksum[GIT_HASH_MAX_SIZE];
12091232
git_filebuf index_file = {0};
12101233
void *packfile_trailer;
1211-
size_t checksum_size = GIT_HASH_SHA1_SIZE;
1234+
size_t checksum_size;
12121235
bool mismatch;
12131236

12141237
if (!idx->parsed_header) {
12151238
git_error_set(GIT_ERROR_INDEXER, "incomplete pack header");
12161239
return -1;
12171240
}
12181241

1242+
checksum_size = git_hash_size(indexer_hash_algorithm(idx));
1243+
GIT_ASSERT(checksum_size);
1244+
12191245
/* Test for this before resolve_deltas(), as it plays with idx->off */
12201246
if (idx->off + (ssize_t)checksum_size < idx->pack->mwf.size) {
12211247
git_error_set(GIT_ERROR_INDEXER, "unexpected data at the end of the pack");

src/libgit2/remote.c

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,24 @@ int git_remote_capabilities(unsigned int *out, git_remote *remote)
10261026
return remote->transport->capabilities(out, remote->transport);
10271027
}
10281028

1029+
int git_remote_oid_type(git_oid_t *out, git_remote *remote)
1030+
{
1031+
GIT_ASSERT_ARG(remote);
1032+
1033+
if (!remote->transport) {
1034+
git_error_set(GIT_ERROR_NET, "this remote has never connected");
1035+
*out = 0;
1036+
return -1;
1037+
}
1038+
1039+
#ifdef GIT_EXPERIMENTAL_SHA256
1040+
return remote->transport->oid_type(out, remote->transport);
1041+
#else
1042+
*out = GIT_OID_SHA1;
1043+
return 0;
1044+
#endif
1045+
}
1046+
10291047
static int lookup_config(char **out, git_config *cfg, const char *name)
10301048
{
10311049
git_config_entry *ce = NULL;
@@ -1225,24 +1243,6 @@ static int ls_to_vector(git_vector *out, git_remote *remote)
12251243
return 0;
12261244
}
12271245

1228-
#define copy_opts(out, in) \
1229-
if (in) { \
1230-
(out)->callbacks = (in)->callbacks; \
1231-
(out)->proxy_opts = (in)->proxy_opts; \
1232-
(out)->custom_headers = (in)->custom_headers; \
1233-
(out)->follow_redirects = (in)->follow_redirects; \
1234-
}
1235-
1236-
GIT_INLINE(int) connect_opts_from_fetch_opts(
1237-
git_remote_connect_options *out,
1238-
git_remote *remote,
1239-
const git_fetch_options *fetch_opts)
1240-
{
1241-
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
1242-
copy_opts(&tmp, fetch_opts);
1243-
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
1244-
}
1245-
12461246
static int connect_or_reset_options(
12471247
git_remote *remote,
12481248
int direction,
@@ -1330,7 +1330,8 @@ int git_remote_download(
13301330
return -1;
13311331
}
13321332

1333-
if (connect_opts_from_fetch_opts(&connect_opts, remote, opts) < 0)
1333+
if (git_remote_connect_options__from_fetch_opts(&connect_opts,
1334+
remote, opts) < 0)
13341335
return -1;
13351336

13361337
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0)
@@ -1350,6 +1351,8 @@ int git_remote_fetch(
13501351
bool prune = false;
13511352
git_str reflog_msg_buf = GIT_STR_INIT;
13521353
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
1354+
unsigned int capabilities;
1355+
git_oid_t oid_type;
13531356

13541357
GIT_ASSERT_ARG(remote);
13551358

@@ -1358,7 +1361,8 @@ int git_remote_fetch(
13581361
return -1;
13591362
}
13601363

1361-
if (connect_opts_from_fetch_opts(&connect_opts, remote, opts) < 0)
1364+
if (git_remote_connect_options__from_fetch_opts(&connect_opts,
1365+
remote, opts) < 0)
13621366
return -1;
13631367

13641368
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0)
@@ -1369,6 +1373,10 @@ int git_remote_fetch(
13691373
tagopt = opts->download_tags;
13701374
}
13711375

1376+
if ((error = git_remote_capabilities(&capabilities, remote)) < 0 ||
1377+
(error = git_remote_oid_type(&oid_type, remote)) < 0)
1378+
return error;
1379+
13721380
/* Connect and download everything */
13731381
error = git_remote__download(remote, refspecs, opts);
13741382

@@ -2896,16 +2904,6 @@ int git_remote__default_branch(git_str *out, git_remote *remote)
28962904
return error;
28972905
}
28982906

2899-
GIT_INLINE(int) connect_opts_from_push_opts(
2900-
git_remote_connect_options *out,
2901-
git_remote *remote,
2902-
const git_push_options *push_opts)
2903-
{
2904-
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
2905-
copy_opts(&tmp, push_opts);
2906-
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
2907-
}
2908-
29092907
int git_remote_upload(
29102908
git_remote *remote,
29112909
const git_strarray *refspecs,
@@ -2924,7 +2922,8 @@ int git_remote_upload(
29242922
return -1;
29252923
}
29262924

2927-
if ((error = connect_opts_from_push_opts(&connect_opts, remote, opts)) < 0)
2925+
if ((error = git_remote_connect_options__from_push_opts(
2926+
&connect_opts, remote, opts)) < 0)
29282927
goto cleanup;
29292928

29302929
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_PUSH, &connect_opts)) < 0)
@@ -2985,7 +2984,8 @@ int git_remote_push(
29852984
return -1;
29862985
}
29872986

2988-
if (connect_opts_from_push_opts(&connect_opts, remote, opts) < 0)
2987+
if (git_remote_connect_options__from_push_opts(&connect_opts,
2988+
remote, opts) < 0)
29892989
return -1;
29902990

29912991
if ((error = git_remote_upload(remote, refspecs, opts)) < 0)

0 commit comments

Comments
 (0)