mirror of
https://github.com/libgit2/libgit2.git
synced 2026-06-22 06:26:26 +00:00
transport: teach transports about oid types and SHA256
This commit is contained in:
@@ -57,6 +57,18 @@ struct git_transport {
|
||||
unsigned int *capabilities,
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -393,12 +393,19 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c
|
||||
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;
|
||||
git_str reflog_message = GIT_STR_INIT;
|
||||
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
|
||||
git_fetch_options fetch_opts;
|
||||
git_remote *remote;
|
||||
git_oid_t oid_type;
|
||||
|
||||
GIT_ASSERT_ARG(repo);
|
||||
GIT_ASSERT_ARG(_remote);
|
||||
@@ -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));
|
||||
fetch_opts.update_fetchhead = 0;
|
||||
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));
|
||||
|
||||
/*
|
||||
* 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)
|
||||
goto cleanup;
|
||||
|
||||
|
||||
@@ -95,7 +95,6 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts)
|
||||
git_remote_head **heads;
|
||||
git_refspec tagspec, head, *spec;
|
||||
int error = 0;
|
||||
git_odb *odb;
|
||||
size_t i, heads_len;
|
||||
unsigned int remote_caps;
|
||||
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)
|
||||
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 ||
|
||||
(error = git_remote_capabilities(&remote_caps, remote)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
@@ -56,8 +56,8 @@ struct git_indexer {
|
||||
git_vector deltas;
|
||||
unsigned int fanout[256];
|
||||
git_hash_ctx hash_ctx;
|
||||
unsigned char checksum[GIT_HASH_SHA1_SIZE];
|
||||
char name[(GIT_HASH_SHA1_SIZE * 2) + 1];
|
||||
unsigned char checksum[GIT_HASH_MAX_SIZE];
|
||||
char name[(GIT_HASH_MAX_SIZE * 2) + 1];
|
||||
git_indexer_progress_cb progress_cb;
|
||||
void *progress_payload;
|
||||
char objbuf[8*1024];
|
||||
@@ -69,7 +69,7 @@ struct git_indexer {
|
||||
git_odb *odb;
|
||||
|
||||
/* 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;
|
||||
git_hash_ctx trailer;
|
||||
};
|
||||
@@ -137,6 +137,20 @@ int git_indexer_init_options(git_indexer_options *opts, unsigned int version)
|
||||
}
|
||||
#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(
|
||||
git_indexer **out,
|
||||
const char *prefix,
|
||||
@@ -149,6 +163,7 @@ static int indexer_new(
|
||||
git_indexer *idx;
|
||||
git_str path = GIT_STR_INIT, tmp_path = GIT_STR_INIT;
|
||||
static const char suff[] = "/pack";
|
||||
git_hash_algorithm_t checksum_type;
|
||||
int error, fd = -1;
|
||||
|
||||
if (in_opts)
|
||||
@@ -163,8 +178,10 @@ static int indexer_new(
|
||||
idx->mode = mode ? mode : GIT_PACK_FILE_MODE;
|
||||
git_str_init(&idx->entry_data, 0);
|
||||
|
||||
if ((error = git_hash_ctx_init(&idx->hash_ctx, GIT_HASH_ALGORITHM_SHA1)) < 0 ||
|
||||
(error = git_hash_ctx_init(&idx->trailer, GIT_HASH_ALGORITHM_SHA1)) < 0 ||
|
||||
checksum_type = indexer_hash_algorithm(idx);
|
||||
|
||||
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)
|
||||
goto cleanup;
|
||||
|
||||
@@ -182,8 +199,7 @@ static int indexer_new(
|
||||
if (fd < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* TODO: SHA256 */
|
||||
error = git_packfile_alloc(&idx->pack, git_str_cstr(&tmp_path), 0);
|
||||
error = git_packfile_alloc(&idx->pack, git_str_cstr(&tmp_path), oid_type);
|
||||
git_str_dispose(&tmp_path);
|
||||
|
||||
if (error < 0)
|
||||
@@ -614,7 +630,7 @@ static int do_progress_callback(git_indexer *idx, git_indexer_progress *stats)
|
||||
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)
|
||||
{
|
||||
size_t to_expell, to_keep;
|
||||
@@ -623,7 +639,10 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
|
||||
if (size == 0)
|
||||
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) {
|
||||
git_hash_update(&idx->trailer, idx->inbuf, idx->inbuf_len);
|
||||
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)
|
||||
{
|
||||
git_packfile_stream *stream = &idx->stream;
|
||||
off64_t entry_start = idx->off;
|
||||
size_t entry_size;
|
||||
size_t oid_size, entry_size;
|
||||
git_object_t type;
|
||||
git_mwindow *w = NULL;
|
||||
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;
|
||||
|
||||
if (!idx->have_stream) {
|
||||
@@ -963,15 +984,17 @@ static int inject_object(git_indexer *idx, git_oid *id)
|
||||
git_odb_object *obj = NULL;
|
||||
struct entry *entry = 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];
|
||||
git_str buf = GIT_STR_INIT;
|
||||
off64_t entry_start;
|
||||
const void *data;
|
||||
size_t len, hdr_len;
|
||||
size_t checksum_size = GIT_HASH_SHA1_SIZE;
|
||||
size_t checksum_size;
|
||||
int error;
|
||||
|
||||
checksum_size = git_hash_size(indexer_hash_algorithm(idx));
|
||||
|
||||
if ((error = seek_back_trailer(idx)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
@@ -1205,10 +1228,10 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
|
||||
struct git_pack_idx_header hdr;
|
||||
git_str filename = GIT_STR_INIT;
|
||||
struct entry *entry;
|
||||
unsigned char checksum[GIT_HASH_SHA1_SIZE];
|
||||
unsigned char checksum[GIT_HASH_MAX_SIZE];
|
||||
git_filebuf index_file = {0};
|
||||
void *packfile_trailer;
|
||||
size_t checksum_size = GIT_HASH_SHA1_SIZE;
|
||||
size_t checksum_size;
|
||||
bool mismatch;
|
||||
|
||||
if (!idx->parsed_header) {
|
||||
@@ -1216,6 +1239,9 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats)
|
||||
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 */
|
||||
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");
|
||||
|
||||
@@ -1026,6 +1026,24 @@ int git_remote_capabilities(unsigned int *out, git_remote *remote)
|
||||
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)
|
||||
{
|
||||
git_config_entry *ce = NULL;
|
||||
@@ -1225,24 +1243,6 @@ static int ls_to_vector(git_vector *out, git_remote *remote)
|
||||
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(
|
||||
git_remote *remote,
|
||||
int direction,
|
||||
@@ -1330,7 +1330,8 @@ int git_remote_download(
|
||||
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;
|
||||
|
||||
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0)
|
||||
@@ -1350,6 +1351,8 @@ int git_remote_fetch(
|
||||
bool prune = false;
|
||||
git_str reflog_msg_buf = GIT_STR_INIT;
|
||||
git_remote_connect_options connect_opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
|
||||
unsigned int capabilities;
|
||||
git_oid_t oid_type;
|
||||
|
||||
GIT_ASSERT_ARG(remote);
|
||||
|
||||
@@ -1358,7 +1361,8 @@ int git_remote_fetch(
|
||||
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;
|
||||
|
||||
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_FETCH, &connect_opts)) < 0)
|
||||
@@ -1369,6 +1373,10 @@ int git_remote_fetch(
|
||||
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 */
|
||||
error = git_remote__download(remote, refspecs, opts);
|
||||
|
||||
@@ -2896,16 +2904,6 @@ done:
|
||||
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(
|
||||
git_remote *remote,
|
||||
const git_strarray *refspecs,
|
||||
@@ -2924,7 +2922,8 @@ int git_remote_upload(
|
||||
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;
|
||||
|
||||
if ((error = connect_or_reset_options(remote, GIT_DIRECTION_PUSH, &connect_opts)) < 0)
|
||||
@@ -2985,7 +2984,8 @@ int git_remote_push(
|
||||
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;
|
||||
|
||||
if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
|
||||
|
||||
@@ -56,5 +56,37 @@ int git_remote_connect_options_normalize(
|
||||
const git_remote_connect_options *src);
|
||||
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
ssize_t written;
|
||||
|
||||
assert(flags == 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");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -266,6 +266,17 @@ static int local_capabilities(unsigned int *capabilities, git_transport *transpo
|
||||
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)
|
||||
{
|
||||
transport_local *t = (transport_local *)transport;
|
||||
@@ -732,6 +743,9 @@ int git_transport_local(git_transport **out, git_remote *owner, void *param)
|
||||
t->parent.connect = local_connect;
|
||||
t->parent.set_connect_opts = local_set_connect_opts;
|
||||
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.download_pack = local_download_pack;
|
||||
t->parent.push = local_push;
|
||||
|
||||
@@ -54,6 +54,12 @@ GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransp
|
||||
return -1;
|
||||
}
|
||||
|
||||
git__free(t->caps.object_format);
|
||||
t->caps.object_format = NULL;
|
||||
|
||||
git__free(t->caps.agent);
|
||||
t->caps.agent = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -242,6 +248,30 @@ static int git_smart__capabilities(unsigned int *capabilities, git_transport *tr
|
||||
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)
|
||||
{
|
||||
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
|
||||
@@ -386,6 +416,8 @@ static void git_smart__free(git_transport *transport)
|
||||
|
||||
git_remote_connect_options_dispose(&t->connect_opts);
|
||||
|
||||
git__free(t->caps.object_format);
|
||||
git__free(t->caps.agent);
|
||||
git__free(t);
|
||||
}
|
||||
|
||||
@@ -452,6 +484,9 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
|
||||
t->parent.connect = git_smart__connect;
|
||||
t->parent.set_connect_opts = git_smart__set_connect_opts;
|
||||
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.free = git_smart__free;
|
||||
t->parent.negotiate_fetch = git_smart__negotiate_fetch;
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#define GIT_CAP_SYMREF "symref"
|
||||
#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_OBJECT_FORMAT "object-format="
|
||||
#define GIT_CAP_AGENT "agent="
|
||||
|
||||
extern bool git_smart__ofs_delta_enabled;
|
||||
|
||||
@@ -133,6 +135,8 @@ typedef struct transport_smart_caps {
|
||||
thin_pack:1,
|
||||
want_tip_sha1:1,
|
||||
want_reachable_sha1:1;
|
||||
char *object_format;
|
||||
char *agent;
|
||||
} transport_smart_caps;
|
||||
|
||||
typedef int (*packetsize_cb)(size_t received, void *payload);
|
||||
|
||||
@@ -21,11 +21,14 @@
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#define PKT_LEN_SIZE 4
|
||||
static const char pkt_done_str[] = "0009done\n";
|
||||
static const char pkt_flush_str[] = "0000";
|
||||
static const char pkt_have_prefix[] = "0032have ";
|
||||
static const char pkt_want_prefix[] = "0032want ";
|
||||
#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_MAX_SIZE 0xffff
|
||||
#define PKT_MAX_WANTLEN (PKT_LEN_SIZE + CONST_STRLEN(PKT_WANT_PREFIX) + GIT_OID_MAX_HEXSIZE + 1)
|
||||
|
||||
static int flush_pkt(git_pkt **out)
|
||||
{
|
||||
@@ -598,16 +601,20 @@ void git_pkt_free(git_pkt *pkt)
|
||||
|
||||
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;
|
||||
char oid[GIT_OID_MAX_HEXSIZE + 1] = {0};
|
||||
char oid[GIT_OID_MAX_HEXSIZE];
|
||||
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);
|
||||
|
||||
/* Prefer multi_ack_detailed */
|
||||
@@ -634,18 +641,19 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
|
||||
if (git_str_oom(&str))
|
||||
return -1;
|
||||
|
||||
len = strlen("XXXXwant ") + oid_hexsize + 1 /* NUL */ +
|
||||
git_str_len(&str) + 1 /* LF */;
|
||||
|
||||
if (len > 0xffff) {
|
||||
if (str.size > (PKT_MAX_SIZE - (PKT_MAX_WANTLEN + 1))) {
|
||||
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;
|
||||
}
|
||||
|
||||
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_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));
|
||||
git_str_dispose(&str);
|
||||
|
||||
@@ -665,8 +673,21 @@ int git_pkt_buffer_wants(
|
||||
transport_smart_caps *caps,
|
||||
git_str *buf)
|
||||
{
|
||||
size_t i = 0;
|
||||
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) {
|
||||
for (; i < count; ++i) {
|
||||
@@ -675,15 +696,13 @@ int git_pkt_buffer_wants(
|
||||
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;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
for (; i < count; ++i) {
|
||||
char oid[GIT_OID_MAX_HEXSIZE];
|
||||
|
||||
head = refs[i];
|
||||
|
||||
if (head->local)
|
||||
@@ -691,9 +710,9 @@ int git_pkt_buffer_wants(
|
||||
|
||||
git_oid_fmt(oid, &head->oid);
|
||||
|
||||
git_str_put(buf, pkt_want_prefix, strlen(pkt_want_prefix));
|
||||
git_str_put(buf, oid, git_oid_hexsize(head->oid.type));
|
||||
git_str_putc(buf, '\n');
|
||||
git_str_printf(buf, "%04x%s%.*s\n",
|
||||
(unsigned int)want_len, PKT_WANT_PREFIX,
|
||||
(int)oid_hexsize, oid);
|
||||
|
||||
if (git_str_oom(buf))
|
||||
return -1;
|
||||
@@ -704,14 +723,27 @@ int git_pkt_buffer_wants(
|
||||
|
||||
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;
|
||||
size_t oid_hexsize, have_len;
|
||||
|
||||
memset(oidhex, 0x0, sizeof(oidhex));
|
||||
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)
|
||||
{
|
||||
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:
|
||||
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 */
|
||||
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
|
||||
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 */
|
||||
ptr = strchr(ptr, ' ');
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ typedef enum {
|
||||
GIT_HASH_ALGORITHM_SHA256
|
||||
} git_hash_algorithm_t;
|
||||
|
||||
#define GIT_HASH_MAX_SIZE GIT_HASH_SHA256_SIZE
|
||||
|
||||
typedef struct git_hash_ctx {
|
||||
union {
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user