Commit 53fcd5b8 by Edward Thomson

transport: teach transports about oid types and SHA256

parent 0006ff63
......@@ -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];
memset(oidhex, 0x0, sizeof(oidhex));
git_oid_fmt(oidhex, oid);
return git_str_printf(buf, "%s%s\n", pkt_have_prefix, oidhex);
char oid_str[GIT_OID_MAX_HEXSIZE];
git_oid_t oid_type;
size_t oid_hexsize, have_len;
#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
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