Commit 53fcd5b8 by Edward Thomson

transport: teach transports about oid types and SHA256

parent 0006ff63
...@@ -57,6 +57,18 @@ struct git_transport { ...@@ -57,6 +57,18 @@ struct git_transport {
unsigned int *capabilities, unsigned int *capabilities,
git_transport *transport); git_transport *transport);
#ifdef GIT_EXPERIMENTAL_SHA256
/**
* Gets the object type for the remote repository.
*
* This function may be called after a successful call to
* `connect()`.
*/
int GIT_CALLBACK(oid_type)(
git_oid_t *object_type,
git_transport *transport);
#endif
/** /**
* Get the list of available references in the remote repository. * Get the list of available references in the remote repository.
* *
......
...@@ -393,12 +393,19 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c ...@@ -393,12 +393,19 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c
return error; return error;
} }
static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch_options *opts, const git_checkout_options *co_opts, const char *branch) static int clone_into(
git_repository *repo,
git_remote *_remote,
const git_fetch_options *opts,
const git_checkout_options *co_opts,
const char *branch)
{ {
int error; int error;
git_str reflog_message = GIT_STR_INIT; git_str reflog_message = GIT_STR_INIT;
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
git_fetch_options fetch_opts; git_fetch_options fetch_opts;
git_remote *remote; git_remote *remote;
git_oid_t oid_type;
GIT_ASSERT_ARG(repo); GIT_ASSERT_ARG(repo);
GIT_ASSERT_ARG(_remote); GIT_ASSERT_ARG(_remote);
...@@ -414,8 +421,25 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch ...@@ -414,8 +421,25 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch
memcpy(&fetch_opts, opts, sizeof(git_fetch_options)); memcpy(&fetch_opts, opts, sizeof(git_fetch_options));
fetch_opts.update_fetchhead = 0; fetch_opts.update_fetchhead = 0;
fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
if ((error = git_remote_connect_options__from_fetch_opts(&connect_opts, remote, &fetch_opts)) < 0)
return error;
git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote));
/*
* Connect to the server so that we can identify the remote
* object format.
*/
if ((error = git_remote_connect_ext(remote, GIT_DIRECTION_FETCH,
&connect_opts)) < 0)
goto cleanup;
if ((error = git_remote_oid_type(&oid_type, remote)) < 0 ||
(error = git_repository__set_objectformat(repo, oid_type)) < 0)
goto cleanup;
if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_str_cstr(&reflog_message))) != 0) if ((error = git_remote_fetch(remote, NULL, &fetch_opts, git_str_cstr(&reflog_message))) != 0)
goto cleanup; goto cleanup;
......
...@@ -95,7 +95,6 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts) ...@@ -95,7 +95,6 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts)
git_remote_head **heads; git_remote_head **heads;
git_refspec tagspec, head, *spec; git_refspec tagspec, head, *spec;
int error = 0; int error = 0;
git_odb *odb;
size_t i, heads_len; size_t i, heads_len;
unsigned int remote_caps; unsigned int remote_caps;
unsigned int oid_mask = GIT_REMOTE_CAPABILITY_TIP_OID | 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) ...@@ -126,9 +125,6 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts)
goto cleanup; goto cleanup;
} }
if ((error = git_repository_odb__weakptr(&odb, remote->repo)) < 0)
goto cleanup;
if ((error = git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote)) < 0 || if ((error = git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote)) < 0 ||
(error = git_remote_capabilities(&remote_caps, remote)) < 0) (error = git_remote_capabilities(&remote_caps, remote)) < 0)
goto cleanup; goto cleanup;
......
...@@ -56,8 +56,8 @@ struct git_indexer { ...@@ -56,8 +56,8 @@ struct git_indexer {
git_vector deltas; git_vector deltas;
unsigned int fanout[256]; unsigned int fanout[256];
git_hash_ctx hash_ctx; git_hash_ctx hash_ctx;
unsigned char checksum[GIT_HASH_SHA1_SIZE]; unsigned char checksum[GIT_HASH_MAX_SIZE];
char name[(GIT_HASH_SHA1_SIZE * 2) + 1]; char name[(GIT_HASH_MAX_SIZE * 2) + 1];
git_indexer_progress_cb progress_cb; git_indexer_progress_cb progress_cb;
void *progress_payload; void *progress_payload;
char objbuf[8*1024]; char objbuf[8*1024];
...@@ -69,7 +69,7 @@ struct git_indexer { ...@@ -69,7 +69,7 @@ struct git_indexer {
git_odb *odb; git_odb *odb;
/* Fields for calculating the packfile trailer (hash of everything before it) */ /* Fields for calculating the packfile trailer (hash of everything before it) */
char inbuf[GIT_OID_MAX_SIZE]; char inbuf[GIT_HASH_MAX_SIZE];
size_t inbuf_len; size_t inbuf_len;
git_hash_ctx trailer; git_hash_ctx trailer;
}; };
...@@ -137,6 +137,20 @@ int git_indexer_init_options(git_indexer_options *opts, unsigned int version) ...@@ -137,6 +137,20 @@ int git_indexer_init_options(git_indexer_options *opts, unsigned int version)
} }
#endif #endif
GIT_INLINE(git_hash_algorithm_t) indexer_hash_algorithm(git_indexer *idx)
{
switch (idx->oid_type) {
case GIT_OID_SHA1:
return GIT_HASH_ALGORITHM_SHA1;
#ifdef GIT_EXPERIMENTAL_SHA256
case GIT_OID_SHA256:
return GIT_HASH_ALGORITHM_SHA256;
#endif
}
return GIT_HASH_ALGORITHM_NONE;
}
static int indexer_new( static int indexer_new(
git_indexer **out, git_indexer **out,
const char *prefix, const char *prefix,
...@@ -149,6 +163,7 @@ static int indexer_new( ...@@ -149,6 +163,7 @@ static int indexer_new(
git_indexer *idx; git_indexer *idx;
git_str path = GIT_STR_INIT, tmp_path = GIT_STR_INIT; git_str path = GIT_STR_INIT, tmp_path = GIT_STR_INIT;
static const char suff[] = "/pack"; static const char suff[] = "/pack";
git_hash_algorithm_t checksum_type;
int error, fd = -1; int error, fd = -1;
if (in_opts) if (in_opts)
...@@ -163,8 +178,10 @@ static int indexer_new( ...@@ -163,8 +178,10 @@ static int indexer_new(
idx->mode = mode ? mode : GIT_PACK_FILE_MODE; idx->mode = mode ? mode : GIT_PACK_FILE_MODE;
git_str_init(&idx->entry_data, 0); git_str_init(&idx->entry_data, 0);
if ((error = git_hash_ctx_init(&idx->hash_ctx, GIT_HASH_ALGORITHM_SHA1)) < 0 || checksum_type = indexer_hash_algorithm(idx);
(error = git_hash_ctx_init(&idx->trailer, GIT_HASH_ALGORITHM_SHA1)) < 0 ||
if ((error = git_hash_ctx_init(&idx->hash_ctx, checksum_type)) < 0 ||
(error = git_hash_ctx_init(&idx->trailer, checksum_type)) < 0 ||
(error = git_oidmap_new(&idx->expected_oids)) < 0) (error = git_oidmap_new(&idx->expected_oids)) < 0)
goto cleanup; goto cleanup;
...@@ -182,8 +199,7 @@ static int indexer_new( ...@@ -182,8 +199,7 @@ static int indexer_new(
if (fd < 0) if (fd < 0)
goto cleanup; goto cleanup;
/* TODO: SHA256 */ error = git_packfile_alloc(&idx->pack, git_str_cstr(&tmp_path), oid_type);
error = git_packfile_alloc(&idx->pack, git_str_cstr(&tmp_path), 0);
git_str_dispose(&tmp_path); git_str_dispose(&tmp_path);
if (error < 0) if (error < 0)
...@@ -614,7 +630,7 @@ static int do_progress_callback(git_indexer *idx, git_indexer_progress *stats) ...@@ -614,7 +630,7 @@ static int do_progress_callback(git_indexer *idx, git_indexer_progress *stats)
return 0; return 0;
} }
/* Hash everything but the last 20B of input */ /* Hash everything but the checksum trailer */
static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size) static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
{ {
size_t to_expell, to_keep; size_t to_expell, to_keep;
...@@ -623,7 +639,10 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size) ...@@ -623,7 +639,10 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
if (size == 0) if (size == 0)
return; return;
/* Easy case, dump the buffer and the data minus the last 20 bytes */ /*
* Easy case, dump the buffer and the data minus the trailing
* checksum (SHA1 or SHA256).
*/
if (size >= oid_size) { if (size >= oid_size) {
git_hash_update(&idx->trailer, idx->inbuf, idx->inbuf_len); git_hash_update(&idx->trailer, idx->inbuf, idx->inbuf_len);
git_hash_update(&idx->trailer, data, size - oid_size); 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) ...@@ -761,12 +780,14 @@ static int read_stream_object(git_indexer *idx, git_indexer_progress *stats)
{ {
git_packfile_stream *stream = &idx->stream; git_packfile_stream *stream = &idx->stream;
off64_t entry_start = idx->off; off64_t entry_start = idx->off;
size_t entry_size; size_t oid_size, entry_size;
git_object_t type; git_object_t type;
git_mwindow *w = NULL; git_mwindow *w = NULL;
int error; int error;
if (idx->pack->mwf.size <= idx->off + 20) oid_size = git_oid_size(idx->oid_type);
if (idx->pack->mwf.size <= idx->off + (long long)oid_size)
return GIT_EBUFS; return GIT_EBUFS;
if (!idx->have_stream) { if (!idx->have_stream) {
...@@ -963,15 +984,17 @@ static int inject_object(git_indexer *idx, git_oid *id) ...@@ -963,15 +984,17 @@ static int inject_object(git_indexer *idx, git_oid *id)
git_odb_object *obj = NULL; git_odb_object *obj = NULL;
struct entry *entry = NULL; struct entry *entry = NULL;
struct git_pack_entry *pentry = NULL; struct git_pack_entry *pentry = NULL;
unsigned char empty_checksum[GIT_HASH_SHA1_SIZE] = {0}; unsigned char empty_checksum[GIT_HASH_MAX_SIZE] = {0};
unsigned char hdr[64]; unsigned char hdr[64];
git_str buf = GIT_STR_INIT; git_str buf = GIT_STR_INIT;
off64_t entry_start; off64_t entry_start;
const void *data; const void *data;
size_t len, hdr_len; size_t len, hdr_len;
size_t checksum_size = GIT_HASH_SHA1_SIZE; size_t checksum_size;
int error; int error;
checksum_size = git_hash_size(indexer_hash_algorithm(idx));
if ((error = seek_back_trailer(idx)) < 0) if ((error = seek_back_trailer(idx)) < 0)
goto cleanup; goto cleanup;
...@@ -1205,10 +1228,10 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats) ...@@ -1205,10 +1228,10 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
struct git_pack_idx_header hdr; struct git_pack_idx_header hdr;
git_str filename = GIT_STR_INIT; git_str filename = GIT_STR_INIT;
struct entry *entry; struct entry *entry;
unsigned char checksum[GIT_HASH_SHA1_SIZE]; unsigned char checksum[GIT_HASH_MAX_SIZE];
git_filebuf index_file = {0}; git_filebuf index_file = {0};
void *packfile_trailer; void *packfile_trailer;
size_t checksum_size = GIT_HASH_SHA1_SIZE; size_t checksum_size;
bool mismatch; bool mismatch;
if (!idx->parsed_header) { if (!idx->parsed_header) {
...@@ -1216,6 +1239,9 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats) ...@@ -1216,6 +1239,9 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
return -1; return -1;
} }
checksum_size = git_hash_size(indexer_hash_algorithm(idx));
GIT_ASSERT(checksum_size);
/* Test for this before resolve_deltas(), as it plays with idx->off */ /* Test for this before resolve_deltas(), as it plays with idx->off */
if (idx->off + (ssize_t)checksum_size < idx->pack->mwf.size) { if (idx->off + (ssize_t)checksum_size < idx->pack->mwf.size) {
git_error_set(GIT_ERROR_INDEXER, "unexpected data at the end of the pack"); git_error_set(GIT_ERROR_INDEXER, "unexpected data at the end of the pack");
......
...@@ -1026,6 +1026,24 @@ int git_remote_capabilities(unsigned int *out, git_remote *remote) ...@@ -1026,6 +1026,24 @@ int git_remote_capabilities(unsigned int *out, git_remote *remote)
return remote->transport->capabilities(out, remote->transport); return remote->transport->capabilities(out, remote->transport);
} }
int git_remote_oid_type(git_oid_t *out, git_remote *remote)
{
GIT_ASSERT_ARG(remote);
if (!remote->transport) {
git_error_set(GIT_ERROR_NET, "this remote has never connected");
*out = 0;
return -1;
}
#ifdef GIT_EXPERIMENTAL_SHA256
return remote->transport->oid_type(out, remote->transport);
#else
*out = GIT_OID_SHA1;
return 0;
#endif
}
static int lookup_config(char **out, git_config *cfg, const char *name) static int lookup_config(char **out, git_config *cfg, const char *name)
{ {
git_config_entry *ce = NULL; git_config_entry *ce = NULL;
...@@ -1225,24 +1243,6 @@ static int ls_to_vector(git_vector *out, git_remote *remote) ...@@ -1225,24 +1243,6 @@ static int ls_to_vector(git_vector *out, git_remote *remote)
return 0; return 0;
} }
#define copy_opts(out, in) \
if (in) { \
(out)->callbacks = (in)->callbacks; \
(out)->proxy_opts = (in)->proxy_opts; \
(out)->custom_headers = (in)->custom_headers; \
(out)->follow_redirects = (in)->follow_redirects; \
}
GIT_INLINE(int) connect_opts_from_fetch_opts(
git_remote_connect_options *out,
git_remote *remote,
const git_fetch_options *fetch_opts)
{
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
copy_opts(&tmp, fetch_opts);
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
}
static int connect_or_reset_options( static int connect_or_reset_options(
git_remote *remote, git_remote *remote,
int direction, int direction,
...@@ -1330,7 +1330,8 @@ int git_remote_download( ...@@ -1330,7 +1330,8 @@ int git_remote_download(
return -1; return -1;
} }
if (connect_opts_from_fetch_opts(&connect_opts, remote, opts) < 0) if (git_remote_connect_options__from_fetch_opts(&connect_opts,
remote, opts) < 0)
return -1; return -1;
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0) if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0)
...@@ -1350,6 +1351,8 @@ int git_remote_fetch( ...@@ -1350,6 +1351,8 @@ int git_remote_fetch(
bool prune = false; bool prune = false;
git_str reflog_msg_buf = GIT_STR_INIT; git_str reflog_msg_buf = GIT_STR_INIT;
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT; git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
unsigned int capabilities;
git_oid_t oid_type;
GIT_ASSERT_ARG(remote); GIT_ASSERT_ARG(remote);
...@@ -1358,7 +1361,8 @@ int git_remote_fetch( ...@@ -1358,7 +1361,8 @@ int git_remote_fetch(
return -1; return -1;
} }
if (connect_opts_from_fetch_opts(&connect_opts, remote, opts) < 0) if (git_remote_connect_options__from_fetch_opts(&connect_opts,
remote, opts) < 0)
return -1; return -1;
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0) if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0)
...@@ -1369,6 +1373,10 @@ int git_remote_fetch( ...@@ -1369,6 +1373,10 @@ int git_remote_fetch(
tagopt = opts->download_tags; tagopt = opts->download_tags;
} }
if ((error = git_remote_capabilities(&capabilities, remote)) < 0 ||
(error = git_remote_oid_type(&oid_type, remote)) < 0)
return error;
/* Connect and download everything */ /* Connect and download everything */
error = git_remote__download(remote, refspecs, opts); error = git_remote__download(remote, refspecs, opts);
...@@ -2896,16 +2904,6 @@ done: ...@@ -2896,16 +2904,6 @@ done:
return error; return error;
} }
GIT_INLINE(int) connect_opts_from_push_opts(
git_remote_connect_options *out,
git_remote *remote,
const git_push_options *push_opts)
{
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
copy_opts(&tmp, push_opts);
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
}
int git_remote_upload( int git_remote_upload(
git_remote *remote, git_remote *remote,
const git_strarray *refspecs, const git_strarray *refspecs,
...@@ -2924,7 +2922,8 @@ int git_remote_upload( ...@@ -2924,7 +2922,8 @@ int git_remote_upload(
return -1; return -1;
} }
if ((error = connect_opts_from_push_opts(&connect_opts, remote, opts)) < 0) if ((error = git_remote_connect_options__from_push_opts(
&connect_opts, remote, opts)) < 0)
goto cleanup; goto cleanup;
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_PUSH, &connect_opts)) < 0) if ((error = connect_or_reset_options(remote, GIT_DIRECTION_PUSH, &connect_opts)) < 0)
...@@ -2985,7 +2984,8 @@ int git_remote_push( ...@@ -2985,7 +2984,8 @@ int git_remote_push(
return -1; return -1;
} }
if (connect_opts_from_push_opts(&connect_opts, remote, opts) < 0) if (git_remote_connect_options__from_push_opts(&connect_opts,
remote, opts) < 0)
return -1; return -1;
if ((error = git_remote_upload(remote, refspecs, opts)) < 0) if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
......
...@@ -56,5 +56,37 @@ int git_remote_connect_options_normalize( ...@@ -56,5 +56,37 @@ int git_remote_connect_options_normalize(
const git_remote_connect_options *src); const git_remote_connect_options *src);
int git_remote_capabilities(unsigned int *out, git_remote *remote); int git_remote_capabilities(unsigned int *out, git_remote *remote);
int git_remote_oid_type(git_oid_t *out, git_remote *remote);
#define git_remote_connect_options__copy_opts(out, in) \
if (in) { \
(out)->callbacks = (in)->callbacks; \
(out)->proxy_opts = (in)->proxy_opts; \
(out)->custom_headers = (in)->custom_headers; \
(out)->follow_redirects = (in)->follow_redirects; \
}
GIT_INLINE(int) git_remote_connect_options__from_fetch_opts(
git_remote_connect_options *out,
git_remote *remote,
const git_fetch_options *fetch_opts)
{
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
git_remote_connect_options__copy_opts(&tmp, fetch_opts);
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
}
GIT_INLINE(int) git_remote_connect_options__from_push_opts(
git_remote_connect_options *out,
git_remote *remote,
const git_push_options *push_opts)
{
git_remote_connect_options tmp = GIT_REMOTE_CONNECT_OPTIONS_INIT;
git_remote_connect_options__copy_opts(&tmp, push_opts);
return git_remote_connect_options_normalize(out, remote->repo, &tmp);
}
#undef git_remote_connect_options__copy_opts
#endif #endif
...@@ -135,9 +135,11 @@ static ssize_t socket_write(git_stream *stream, const char *data, size_t len, in ...@@ -135,9 +135,11 @@ static ssize_t socket_write(git_stream *stream, const char *data, size_t len, in
git_socket_stream *st = (git_socket_stream *) stream; git_socket_stream *st = (git_socket_stream *) stream;
ssize_t written; ssize_t written;
assert(flags == 0);
errno = 0; errno = 0;
if ((written = p_send(st->s, data, len, flags)) < 0) { if ((written = p_send(st->s, data, len, 0)) < 0) {
net_set_error("error sending data"); net_set_error("error sending data");
return -1; return -1;
} }
......
...@@ -266,6 +266,17 @@ static int local_capabilities(unsigned int *capabilities, git_transport *transpo ...@@ -266,6 +266,17 @@ static int local_capabilities(unsigned int *capabilities, git_transport *transpo
return 0; return 0;
} }
#ifdef GIT_EXPERIMENTAL_SHA256
static int local_oid_type(git_oid_t *out, git_transport *transport)
{
transport_local *t = (transport_local *)transport;
*out = t->repo->oid_type;
return 0;
}
#endif
static int local_ls(const git_remote_head ***out, size_t *size, git_transport *transport) static int local_ls(const git_remote_head ***out, size_t *size, git_transport *transport)
{ {
transport_local *t = (transport_local *)transport; transport_local *t = (transport_local *)transport;
...@@ -732,6 +743,9 @@ int git_transport_local(git_transport **out, git_remote *owner, void *param) ...@@ -732,6 +743,9 @@ int git_transport_local(git_transport **out, git_remote *owner, void *param)
t->parent.connect = local_connect; t->parent.connect = local_connect;
t->parent.set_connect_opts = local_set_connect_opts; t->parent.set_connect_opts = local_set_connect_opts;
t->parent.capabilities = local_capabilities; t->parent.capabilities = local_capabilities;
#ifdef GIT_EXPERIMENTAL_SHA256
t->parent.oid_type = local_oid_type;
#endif
t->parent.negotiate_fetch = local_negotiate_fetch; t->parent.negotiate_fetch = local_negotiate_fetch;
t->parent.download_pack = local_download_pack; t->parent.download_pack = local_download_pack;
t->parent.push = local_push; t->parent.push = local_push;
......
...@@ -54,6 +54,12 @@ GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransp ...@@ -54,6 +54,12 @@ GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransp
return -1; return -1;
} }
git__free(t->caps.object_format);
t->caps.object_format = NULL;
git__free(t->caps.agent);
t->caps.agent = NULL;
return 0; return 0;
} }
...@@ -242,6 +248,30 @@ static int git_smart__capabilities(unsigned int *capabilities, git_transport *tr ...@@ -242,6 +248,30 @@ static int git_smart__capabilities(unsigned int *capabilities, git_transport *tr
return 0; return 0;
} }
#ifdef GIT_EXPERIMENTAL_SHA256
static int git_smart__oid_type(git_oid_t *out, git_transport *transport)
{
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
*out = 0;
if (t->caps.object_format == NULL) {
*out = GIT_OID_DEFAULT;
} else {
*out = git_oid_type_fromstr(t->caps.object_format);
if (!*out) {
git_error_set(GIT_ERROR_INVALID,
"unknown object format '%s'",
t->caps.object_format);
return -1;
}
}
return 0;
}
#endif
static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transport *transport) static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transport *transport)
{ {
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
...@@ -386,6 +416,8 @@ static void git_smart__free(git_transport *transport) ...@@ -386,6 +416,8 @@ static void git_smart__free(git_transport *transport)
git_remote_connect_options_dispose(&t->connect_opts); git_remote_connect_options_dispose(&t->connect_opts);
git__free(t->caps.object_format);
git__free(t->caps.agent);
git__free(t); git__free(t);
} }
...@@ -452,6 +484,9 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) ...@@ -452,6 +484,9 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
t->parent.connect = git_smart__connect; t->parent.connect = git_smart__connect;
t->parent.set_connect_opts = git_smart__set_connect_opts; t->parent.set_connect_opts = git_smart__set_connect_opts;
t->parent.capabilities = git_smart__capabilities; t->parent.capabilities = git_smart__capabilities;
#ifdef GIT_EXPERIMENTAL_SHA256
t->parent.oid_type = git_smart__oid_type;
#endif
t->parent.close = git_smart__close; t->parent.close = git_smart__close;
t->parent.free = git_smart__free; t->parent.free = git_smart__free;
t->parent.negotiate_fetch = git_smart__negotiate_fetch; t->parent.negotiate_fetch = git_smart__negotiate_fetch;
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#define GIT_CAP_SYMREF "symref" #define GIT_CAP_SYMREF "symref"
#define GIT_CAP_WANT_TIP_SHA1 "allow-tip-sha1-in-want" #define GIT_CAP_WANT_TIP_SHA1 "allow-tip-sha1-in-want"
#define GIT_CAP_WANT_REACHABLE_SHA1 "allow-reachable-sha1-in-want" #define GIT_CAP_WANT_REACHABLE_SHA1 "allow-reachable-sha1-in-want"
#define GIT_CAP_OBJECT_FORMAT "object-format="
#define GIT_CAP_AGENT "agent="
extern bool git_smart__ofs_delta_enabled; extern bool git_smart__ofs_delta_enabled;
...@@ -133,6 +135,8 @@ typedef struct transport_smart_caps { ...@@ -133,6 +135,8 @@ typedef struct transport_smart_caps {
thin_pack:1, thin_pack:1,
want_tip_sha1:1, want_tip_sha1:1,
want_reachable_sha1:1; want_reachable_sha1:1;
char *object_format;
char *agent;
} transport_smart_caps; } transport_smart_caps;
typedef int (*packetsize_cb)(size_t received, void *payload); typedef int (*packetsize_cb)(size_t received, void *payload);
......
...@@ -21,11 +21,14 @@ ...@@ -21,11 +21,14 @@
#include <ctype.h> #include <ctype.h>
#define PKT_DONE_STR "0009done\n"
#define PKT_FLUSH_STR "0000"
#define PKT_HAVE_PREFIX "have "
#define PKT_WANT_PREFIX "want "
#define PKT_LEN_SIZE 4 #define PKT_LEN_SIZE 4
static const char pkt_done_str[] = "0009done\n"; #define PKT_MAX_SIZE 0xffff
static const char pkt_flush_str[] = "0000"; #define PKT_MAX_WANTLEN (PKT_LEN_SIZE + CONST_STRLEN(PKT_WANT_PREFIX) + GIT_OID_MAX_HEXSIZE + 1)
static const char pkt_have_prefix[] = "0032have ";
static const char pkt_want_prefix[] = "0032want ";
static int flush_pkt(git_pkt **out) static int flush_pkt(git_pkt **out)
{ {
...@@ -598,16 +601,20 @@ void git_pkt_free(git_pkt *pkt) ...@@ -598,16 +601,20 @@ void git_pkt_free(git_pkt *pkt)
int git_pkt_buffer_flush(git_str *buf) int git_pkt_buffer_flush(git_str *buf)
{ {
return git_str_put(buf, pkt_flush_str, strlen(pkt_flush_str)); return git_str_put(buf, PKT_FLUSH_STR, CONST_STRLEN(PKT_FLUSH_STR));
} }
static int buffer_want_with_caps(const git_remote_head *head, transport_smart_caps *caps, git_str *buf) static int buffer_want_with_caps(
const git_remote_head *head,
transport_smart_caps *caps,
git_oid_t oid_type,
git_str *buf)
{ {
git_str str = GIT_STR_INIT; git_str str = GIT_STR_INIT;
char oid[GIT_OID_MAX_HEXSIZE + 1] = {0}; char oid[GIT_OID_MAX_HEXSIZE];
size_t oid_hexsize, len; size_t oid_hexsize, len;
oid_hexsize = git_oid_hexsize(head->oid.type); oid_hexsize = git_oid_hexsize(oid_type);
git_oid_fmt(oid, &head->oid); git_oid_fmt(oid, &head->oid);
/* Prefer multi_ack_detailed */ /* Prefer multi_ack_detailed */
...@@ -634,18 +641,19 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca ...@@ -634,18 +641,19 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
if (git_str_oom(&str)) if (git_str_oom(&str))
return -1; return -1;
len = strlen("XXXXwant ") + oid_hexsize + 1 /* NUL */ + if (str.size > (PKT_MAX_SIZE - (PKT_MAX_WANTLEN + 1))) {
git_str_len(&str) + 1 /* LF */;
if (len > 0xffff) {
git_error_set(GIT_ERROR_NET, git_error_set(GIT_ERROR_NET,
"tried to produce packet with invalid length %" PRIuZ, len); "tried to produce packet with invalid caps length %" PRIuZ, str.size);
return -1; return -1;
} }
len = PKT_LEN_SIZE + CONST_STRLEN(PKT_WANT_PREFIX) +
oid_hexsize + 1 /* NUL */ +
git_str_len(&str) + 1 /* LF */;
git_str_grow_by(buf, len); git_str_grow_by(buf, len);
git_str_printf(buf, git_str_printf(buf,
"%04xwant %.*s %s\n", (unsigned int)len, "%04x%s%.*s %s\n", (unsigned int)len, PKT_WANT_PREFIX,
(int)oid_hexsize, oid, git_str_cstr(&str)); (int)oid_hexsize, oid, git_str_cstr(&str));
git_str_dispose(&str); git_str_dispose(&str);
...@@ -665,8 +673,21 @@ int git_pkt_buffer_wants( ...@@ -665,8 +673,21 @@ int git_pkt_buffer_wants(
transport_smart_caps *caps, transport_smart_caps *caps,
git_str *buf) git_str *buf)
{ {
size_t i = 0;
const git_remote_head *head; const git_remote_head *head;
char oid[GIT_OID_MAX_HEXSIZE];
git_oid_t oid_type;
size_t oid_hexsize, want_len, i = 0;
#ifdef GIT_EXPERIMENTAL_SHA256
oid_type = count > 0 ? refs[0]->oid.type : GIT_OID_SHA1;
#else
oid_type = GIT_OID_SHA1;
#endif
oid_hexsize = git_oid_hexsize(oid_type);
want_len = PKT_LEN_SIZE + CONST_STRLEN(PKT_WANT_PREFIX) +
oid_hexsize + 1 /* LF */;
if (caps->common) { if (caps->common) {
for (; i < count; ++i) { for (; i < count; ++i) {
...@@ -675,15 +696,13 @@ int git_pkt_buffer_wants( ...@@ -675,15 +696,13 @@ int git_pkt_buffer_wants(
break; break;
} }
if (buffer_want_with_caps(refs[i], caps, buf) < 0) if (buffer_want_with_caps(refs[i], caps, oid_type, buf) < 0)
return -1; return -1;
i++; i++;
} }
for (; i < count; ++i) { for (; i < count; ++i) {
char oid[GIT_OID_MAX_HEXSIZE];
head = refs[i]; head = refs[i];
if (head->local) if (head->local)
...@@ -691,9 +710,9 @@ int git_pkt_buffer_wants( ...@@ -691,9 +710,9 @@ int git_pkt_buffer_wants(
git_oid_fmt(oid, &head->oid); git_oid_fmt(oid, &head->oid);
git_str_put(buf, pkt_want_prefix, strlen(pkt_want_prefix)); git_str_printf(buf, "%04x%s%.*s\n",
git_str_put(buf, oid, git_oid_hexsize(head->oid.type)); (unsigned int)want_len, PKT_WANT_PREFIX,
git_str_putc(buf, '\n'); (int)oid_hexsize, oid);
if (git_str_oom(buf)) if (git_str_oom(buf))
return -1; return -1;
...@@ -704,14 +723,27 @@ int git_pkt_buffer_wants( ...@@ -704,14 +723,27 @@ int git_pkt_buffer_wants(
int git_pkt_buffer_have(git_oid *oid, git_str *buf) int git_pkt_buffer_have(git_oid *oid, git_str *buf)
{ {
char oidhex[GIT_OID_SHA1_HEXSIZE + 1]; char oid_str[GIT_OID_MAX_HEXSIZE];
git_oid_t oid_type;
memset(oidhex, 0x0, sizeof(oidhex)); size_t oid_hexsize, have_len;
git_oid_fmt(oidhex, oid);
return git_str_printf(buf, "%s%s\n", pkt_have_prefix, oidhex); #ifdef GIT_EXPERIMENTAL_SHA256
oid_type = oid->type;
#else
oid_type = GIT_OID_SHA1;
#endif
oid_hexsize = git_oid_hexsize(oid_type);
have_len = PKT_LEN_SIZE + CONST_STRLEN(PKT_HAVE_PREFIX) +
oid_hexsize + 1 /* LF */;
git_oid_fmt(oid_str, oid);
return git_str_printf(buf, "%04x%s%.*s\n",
(unsigned int)have_len, PKT_HAVE_PREFIX,
(int)oid_hexsize, oid_str);
} }
int git_pkt_buffer_done(git_str *buf) int git_pkt_buffer_done(git_str *buf)
{ {
return git_str_puts(buf, pkt_done_str); return git_str_put(buf, PKT_DONE_STR, CONST_STRLEN(PKT_DONE_STR));
} }
...@@ -134,9 +134,12 @@ on_invalid: ...@@ -134,9 +134,12 @@ on_invalid:
return -1; return -1;
} }
int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vector *symrefs) int git_smart__detect_caps(
git_pkt_ref *pkt,
transport_smart_caps *caps,
git_vector *symrefs)
{ {
const char *ptr; const char *ptr, *start;
/* No refs or capabilities, odd but not a problem */ /* No refs or capabilities, odd but not a problem */
if (pkt == NULL || pkt->capabilities == NULL) if (pkt == NULL || pkt->capabilities == NULL)
...@@ -218,6 +221,28 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec ...@@ -218,6 +221,28 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec
continue; continue;
} }
if (!git__prefixcmp(ptr, GIT_CAP_OBJECT_FORMAT)) {
ptr += strlen(GIT_CAP_OBJECT_FORMAT);
start = ptr;
ptr = strchr(ptr, ' ');
if ((caps->object_format = git__strndup(start, (ptr - start))) == NULL)
return -1;
continue;
}
if (!git__prefixcmp(ptr, GIT_CAP_AGENT)) {
ptr += strlen(GIT_CAP_AGENT);
start = ptr;
ptr = strchr(ptr, ' ');
if ((caps->agent = git__strndup(start, (ptr - start))) == NULL)
return -1;
continue;
}
/* We don't know this capability, so skip it */ /* We don't know this capability, so skip it */
ptr = strchr(ptr, ' '); ptr = strchr(ptr, ' ');
} }
......
...@@ -23,6 +23,8 @@ typedef enum { ...@@ -23,6 +23,8 @@ typedef enum {
GIT_HASH_ALGORITHM_SHA256 GIT_HASH_ALGORITHM_SHA256
} git_hash_algorithm_t; } git_hash_algorithm_t;
#define GIT_HASH_MAX_SIZE GIT_HASH_SHA256_SIZE
typedef struct git_hash_ctx { typedef struct git_hash_ctx {
union { union {
git_hash_sha1_ctx sha1; git_hash_sha1_ctx sha1;
...@@ -45,4 +47,15 @@ int git_hash_vec(unsigned char *out, git_str_vec *vec, size_t n, git_hash_algori ...@@ -45,4 +47,15 @@ int git_hash_vec(unsigned char *out, git_str_vec *vec, size_t n, git_hash_algori
int git_hash_fmt(char *out, unsigned char *hash, size_t hash_len); int git_hash_fmt(char *out, unsigned char *hash, size_t hash_len);
GIT_INLINE(size_t) git_hash_size(git_hash_algorithm_t algorithm) {
switch (algorithm) {
case GIT_HASH_ALGORITHM_SHA1:
return GIT_HASH_SHA1_SIZE;
case GIT_HASH_ALGORITHM_SHA256:
return GIT_HASH_SHA256_SIZE;
default:
return 0;
}
}
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment