Download raw body.
add SHA256 support to gotd
The patch below adds sha256 support to gotd.
I will not wait very long for reviews before committing this patch.
The gotd test suite is passing with either SHA1 or SHA256 repositories now.
So this is a good enough base to start with. We can improve things in-tree.
Additional run-time testing would be appreciated if anyone wants to give
it a spin on their server.
Ok?
M gotd/gotd.c | 0+ 26-
M gotd/gotd.h | 24+ 13-
M gotd/repo_imsg.c | 6+ 4-
M gotd/repo_read.c | 28+ 11-
M gotd/repo_write.c | 70+ 50-
M gotd/session_read.c | 9+ 7-
M gotd/session_write.c | 28+ 16-
M include/got_object.h | 3+ 0-
M lib/gitproto.c | 16+ 2-
M lib/got_lib_hash.h | 3+ 3-
M lib/hash.c | 14+ 0-
M lib/serve.c | 260+ 92-
M regress/gotd/Makefile | 2+ 0-
M regress/gotd/README | 5+ 0-
M regress/gotd/common.sh | 1+ 1-
M regress/gotd/repo_write.sh | 11+ 2-
M regress/gotd/repo_write_empty.sh | 11+ 2-
M regress/gotd/request_bad.sh | 34+ 16-
18 files changed, 525 insertions(+), 245 deletions(-)
commit - ed18463dc30bea2f53daa2e3557929d3906c51c9
commit + 5ca9d69e442eb4cdad171bddd3bbc2cf6901ce6e
blob - 83907bca5a321b20da0b228f0bb2bde1323d7c01
blob + 2834557503a15dc41af62b49c84f17155a6e7369
--- gotd/gotd.c
+++ gotd/gotd.c
@@ -3417,7 +3417,6 @@ main(int argc, char **argv)
enum gotd_procid proc_id = GOTD_PROC_GOTD;
struct event evsigint, evsigterm, evsighup, evsigusr1, evsigchld;
int *pack_fds = NULL, *temp_fds = NULL;
- struct gotd_repo *repo = NULL;
char hostname[_POSIX_HOST_NAME_MAX + 1];
FILE *fp;
FILE *diff_f1 = NULL, *diff_f2 = NULL, *tmp_f1 = NULL, *tmp_f2 = NULL;
@@ -3549,31 +3548,6 @@ main(int argc, char **argv)
if (pw->pw_uid == 0)
fatalx("cannot run %s as the superuser", getprogname());
- /*
- * SHA2 repositories cannot be used with gotd until Git protov2
- * support is added. Reject them at startup for now.
- */
- TAILQ_FOREACH(repo, &gotd.repos, entry) {
- struct got_repository *r;
-
- error = got_repo_open(&r, repo->path, NULL, NULL);
- if (error) {
- if (error->code == GOT_ERR_ERRNO &&
- errno == ENOENT)
- continue;
- fatalx("%s: %s", repo->path, error->msg);
- }
-
- if (got_repo_get_object_format(r) != GOT_HASH_SHA1) {
- error = got_error_msg(GOT_ERR_NOT_IMPL,
- "sha256 object IDs unsupported in network "
- "protocol");
- fatalx("%s: %s", repo->path, error->msg);
- }
-
- got_repo_close(r);
- }
-
if (noaction) {
fprintf(stderr, "configuration OK\n");
return 0;
blob - c7d6f9af6df636630f65ecdae5ca98226c2059c0
blob + 5df45de744a4ee1ecc485e5e517d4a9b06a733b7
--- gotd/gotd.h
+++ gotd/gotd.h
@@ -355,13 +355,15 @@ struct gotd_imsg_list_refs {
/* Structure for GOTD_IMSG_REFLIST. */
struct gotd_imsg_reflist {
size_t nrefs;
+ int algo;
/* Followed by nrefs times of gotd_imsg_ref/gotd_imsg_symref data. */
} __attribute__((__packed__));
/* Structure for GOTD_IMSG_REF data. */
struct gotd_imsg_ref {
- uint8_t id[SHA1_DIGEST_LENGTH];
+ uint8_t id[GOT_OBJECT_ID_MAXLEN];
+ int algo;
size_t name_len;
/* Followed by name_len data bytes. */
} __attribute__((__packed__));
@@ -370,7 +372,8 @@ struct gotd_imsg_ref {
struct gotd_imsg_symref {
size_t name_len;
size_t target_len;
- uint8_t target_id[SHA1_DIGEST_LENGTH];
+ uint8_t target_id[GOT_OBJECT_ID_MAXLEN];
+ int algo;
/*
* Followed by name_len + target_len data bytes.
@@ -398,22 +401,26 @@ struct gotd_imsg_capability {
/* Structure for GOTD_IMSG_WANT data. */
struct gotd_imsg_want {
- uint8_t object_id[SHA1_DIGEST_LENGTH];
+ uint8_t object_id[GOT_OBJECT_ID_MAXLEN];
+ int algo;
} __attribute__((__packed__));
/* Structure for GOTD_IMSG_HAVE data. */
struct gotd_imsg_have {
- uint8_t object_id[SHA1_DIGEST_LENGTH];
+ uint8_t object_id[GOT_OBJECT_ID_MAXLEN];
+ int algo;
} __attribute__((__packed__));
/* Structure for GOTD_IMSG_ACK data. */
struct gotd_imsg_ack {
- uint8_t object_id[SHA1_DIGEST_LENGTH];
+ uint8_t object_id[GOT_OBJECT_ID_MAXLEN];
+ int algo;
} __attribute__((__packed__));
/* Structure for GOTD_IMSG_NAK data. */
struct gotd_imsg_nak {
- uint8_t object_id[SHA1_DIGEST_LENGTH];
+ uint8_t object_id[GOT_OBJECT_ID_MAXLEN];
+ int algo;
} __attribute__((__packed__));
/* Structure for GOTD_IMSG_PACKFILE_STATUS data. */
@@ -426,8 +433,9 @@ struct gotd_imsg_packfile_status {
/* Structure for GOTD_IMSG_REF_UPDATE data. */
struct gotd_imsg_ref_update {
- uint8_t old_id[SHA1_DIGEST_LENGTH];
- uint8_t new_id[SHA1_DIGEST_LENGTH];
+ uint8_t old_id[GOT_OBJECT_ID_MAXLEN];
+ uint8_t new_id[GOT_OBJECT_ID_MAXLEN];
+ int algo;
int ref_is_new;
int delete_ref;
size_t name_len;
@@ -468,8 +476,9 @@ struct gotd_imsg_ref_updates_start {
/* Structure for GOTD_IMSG_REF_UPDATE_OK data. */
struct gotd_imsg_ref_update_ok {
- uint8_t old_id[SHA1_DIGEST_LENGTH];
- uint8_t new_id[SHA1_DIGEST_LENGTH];
+ uint8_t old_id[GOT_OBJECT_ID_MAXLEN];
+ uint8_t new_id[GOT_OBJECT_ID_MAXLEN];
+ int algo;
int ref_is_new;
size_t name_len;
@@ -478,8 +487,9 @@ struct gotd_imsg_ref_update_ok {
/* Structure for GOTD_IMSG_REF_UPDATE_NG data. */
struct gotd_imsg_ref_update_ng {
- uint8_t old_id[SHA1_DIGEST_LENGTH];
- uint8_t new_id[SHA1_DIGEST_LENGTH];
+ uint8_t old_id[GOT_OBJECT_ID_MAXLEN];
+ uint8_t new_id[GOT_OBJECT_ID_MAXLEN];
+ int algo;
size_t name_len;
size_t reason_len;
@@ -524,7 +534,8 @@ struct gotd_imsg_packfile_progress {
/* Structure for GOTD_IMSG_PACKFILE_INSTALL. */
struct gotd_imsg_packfile_install {
- uint8_t pack_sha1[SHA1_DIGEST_LENGTH];
+ uint8_t pack_hash[GOT_HASH_DIGEST_MAXLEN];
+ int algo;
};
/* Structure for GOTD_IMSG_LISTEN_SOCKET data. */
blob - cde254c906d136723be9be3524aa383c26132dad
blob + 1cec9cd92ef573d07372cb2a88cf029a98a33d8a
--- gotd/repo_imsg.c
+++ gotd/repo_imsg.c
@@ -44,14 +44,15 @@ gotd_imsg_send_ack(struct got_object_id *id, struct im
{
const struct got_error *err = NULL;
struct gotd_imsg_ack iack;
- char hex[SHA1_DIGEST_STRING_LENGTH];
+ char hex[GOT_HASH_DIGEST_STRING_MAXLEN];
if (log_getverbose() > 0 &&
got_object_id_hex(id, hex, sizeof(hex)))
log_debug("sending ACK for %s", hex);
memset(&iack, 0, sizeof(iack));
- memcpy(iack.object_id, id->hash, SHA1_DIGEST_LENGTH);
+ memcpy(iack.object_id, id->hash, got_hash_digest_length(id->algo));
+ iack.algo = id->algo;
if (imsg_compose(ibuf, GOTD_IMSG_ACK, peerid, pid, -1,
&iack, sizeof(iack)) == -1) {
@@ -71,14 +72,15 @@ gotd_imsg_send_nak(struct got_object_id *id, struct im
{
const struct got_error *err = NULL;
struct gotd_imsg_nak inak;
- char hex[SHA1_DIGEST_STRING_LENGTH];
+ char hex[GOT_HASH_DIGEST_STRING_MAXLEN];
if (log_getverbose() > 0 &&
got_object_id_hex(id, hex, sizeof(hex)))
log_debug("sending NAK for %s", hex);
memset(&inak, 0, sizeof(inak));
- memcpy(inak.object_id, id->hash, SHA1_DIGEST_LENGTH);
+ memcpy(inak.object_id, id->hash, got_hash_digest_length(id->algo));
+ inak.algo = id->algo;
if (imsg_compose(ibuf, GOTD_IMSG_NAK, peerid, pid, -1,
&inak, sizeof(inak)) == -1) {
blob - 18cf4fa2c562efeff6cd0d5b354d8121fe4a983b
blob + 445fe097b742d1fe728e18747cd8cfbc27384d57
--- gotd/repo_read.c
+++ gotd/repo_read.c
@@ -117,6 +117,7 @@ send_symref(struct got_reference *symref, struct got_o
isymref.name_len = strlen(refname);
isymref.target_len = strlen(target);
memcpy(isymref.target_id, target_id->hash, sizeof(isymref.target_id));
+ isymref.algo = got_repo_get_object_format(repo_read.repo);
len = sizeof(isymref) + isymref.name_len + isymref.target_len;
if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
@@ -155,6 +156,7 @@ send_peeled_tag_ref(struct got_reference *ref, struct
{
const struct got_error *err = NULL;
struct got_tag_object *tag;
+ int algo = got_repo_get_object_format(repo_read.repo);
size_t namelen, len;
char *peeled_refname = NULL;
struct got_object_id *id;
@@ -186,10 +188,14 @@ send_peeled_tag_ref(struct got_reference *ref, struct
}
/* Keep in sync with struct gotd_imsg_ref definition. */
- if (imsg_add(wbuf, id->hash, SHA1_DIGEST_LENGTH) == -1) {
+ if (imsg_add(wbuf, id->hash, GOT_OBJECT_ID_MAXLEN) == -1) {
err = got_error_from_errno("imsg_add REF");
goto done;
}
+ if (imsg_add(wbuf, &algo, sizeof(algo)) == -1) {
+ err = got_error_from_errno("imsg_add REF");
+ goto done;
+ }
if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1) {
err = got_error_from_errno("imsg_add REF");
goto done;
@@ -215,6 +221,7 @@ send_ref(struct got_reference *ref, struct imsgbuf *ib
struct got_object *obj = NULL;
size_t len;
struct ibuf *wbuf;
+ int algo = got_repo_get_object_format(repo_read.repo);
namelen = strlen(refname);
@@ -234,8 +241,12 @@ send_ref(struct got_reference *ref, struct imsgbuf *ib
}
/* Keep in sync with struct gotd_imsg_ref definition. */
- if (imsg_add(wbuf, id->hash, SHA1_DIGEST_LENGTH) == -1)
+ if (imsg_add(wbuf, id->hash, GOT_OBJECT_ID_MAXLEN) == -1)
return got_error_from_errno("imsg_add REF");
+ if (imsg_add(wbuf, &algo, sizeof(algo)) == -1) {
+ err = got_error_from_errno("imsg_add REF");
+ goto done;
+ }
if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1)
return got_error_from_errno("imsg_add REF");
if (imsg_add(wbuf, refname, namelen) == -1)
@@ -293,6 +304,7 @@ list_refs(struct imsg *imsg)
return err;
memset(&irefs, 0, sizeof(irefs));
+ irefs.algo = got_repo_get_object_format(repo_read.repo);
TAILQ_FOREACH(re, &refs, entry) {
struct got_object_id *id;
int obj_type;
@@ -404,18 +416,23 @@ recv_want(struct imsg *imsg)
struct repo_read_client *client = &repo_read_client;
struct gotd_imsg_want iwant;
size_t datalen;
- char hex[SHA1_DIGEST_STRING_LENGTH];
+ char hex[GOT_HASH_DIGEST_STRING_MAXLEN];
struct got_object_id id;
int obj_type;
struct imsgbuf ibuf;
+ int algo = got_repo_get_object_format(repo_read.repo);
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
if (datalen != sizeof(iwant))
return got_error(GOT_ERR_PRIVSEP_LEN);
memcpy(&iwant, imsg->data, sizeof(iwant));
+ if (iwant.algo != algo)
+ return got_error(GOT_ERR_OBJECT_FORMAT);
+
memset(&id, 0, sizeof(id));
- memcpy(id.hash, iwant.object_id, SHA1_DIGEST_LENGTH);
+ memcpy(id.hash, iwant.object_id, GOT_OBJECT_ID_MAXLEN);
+ id.algo = algo;
if (log_getverbose() > 0 &&
got_object_id_hex(&id, hex, sizeof(hex)))
@@ -451,18 +468,23 @@ recv_have(struct imsg *imsg)
struct repo_read_client *client = &repo_read_client;
struct gotd_imsg_have ihave;
size_t datalen;
- char hex[SHA1_DIGEST_STRING_LENGTH];
+ char hex[GOT_HASH_DIGEST_STRING_MAXLEN];
struct got_object_id id;
int obj_type;
struct imsgbuf ibuf;
+ int algo = got_repo_get_object_format(repo_read.repo);
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
if (datalen != sizeof(ihave))
return got_error(GOT_ERR_PRIVSEP_LEN);
memcpy(&ihave, imsg->data, sizeof(ihave));
+ if (ihave.algo != algo)
+ return got_error(GOT_ERR_OBJECT_FORMAT);
+
memset(&id, 0, sizeof(id));
- memcpy(id.hash, ihave.object_id, SHA1_DIGEST_LENGTH);
+ memcpy(id.hash, ihave.object_id, GOT_OBJECT_ID_MAXLEN);
+ id.algo = algo;
if (log_getverbose() > 0 &&
got_object_id_hex(&id, hex, sizeof(hex)))
@@ -894,11 +916,6 @@ repo_read_main(const char *title, const char *repo_pat
"bare git repository required");
goto done;
}
- if (got_repo_get_object_format(repo_read.repo) != GOT_HASH_SHA1) {
- err = got_error_msg(GOT_ERR_NOT_IMPL,
- "sha256 object IDs unsupported in network protocol");
- goto done;
- }
got_repo_temp_fds_set(repo_read.repo, temp_fds);
blob - 195b1aa7776138c2bbbe0c1acf78bb03c53e04f6
blob + 95a4a8e471cea3a9f5c100b2fe1d3d113c2c6803
--- gotd/repo_write.c
+++ gotd/repo_write.c
@@ -110,7 +110,7 @@ static struct repo_write_client {
int pack_pipe;
struct got_pack pack;
struct got_packidx *packidx;
- uint8_t pack_sha1[SHA1_DIGEST_LENGTH];
+ uint8_t pack_hash[GOT_HASH_DIGEST_MAXLEN];
int packidx_fd;
struct gotd_ref_updates ref_updates;
int nref_updates;
@@ -153,6 +153,7 @@ send_peeled_tag_ref(struct got_reference *ref, struct
char *peeled_refname = NULL;
struct got_object_id *id;
struct ibuf *wbuf;
+ int algo = got_repo_get_object_format(repo_write.repo);
err = got_object_tag_open(&tag, repo_write.repo, obj);
if (err)
@@ -180,10 +181,14 @@ send_peeled_tag_ref(struct got_reference *ref, struct
}
/* Keep in sync with struct gotd_imsg_ref definition. */
- if (imsg_add(wbuf, id->hash, SHA1_DIGEST_LENGTH) == -1) {
+ if (imsg_add(wbuf, id->hash, GOT_OBJECT_ID_MAXLEN) == -1) {
err = got_error_from_errno("imsg_add REF");
goto done;
}
+ if (imsg_add(wbuf, &algo, sizeof(algo)) == -1) {
+ err = got_error_from_errno("imsg_add REF");
+ goto done;
+ }
if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1) {
err = got_error_from_errno("imsg_add REF");
goto done;
@@ -209,6 +214,7 @@ send_ref(struct got_reference *ref, struct imsgbuf *ib
struct got_object *obj = NULL;
size_t len;
struct ibuf *wbuf;
+ int algo = got_repo_get_object_format(repo_write.repo);
namelen = strlen(refname);
@@ -228,8 +234,10 @@ send_ref(struct got_reference *ref, struct imsgbuf *ib
}
/* Keep in sync with struct gotd_imsg_ref definition. */
- if (imsg_add(wbuf, id->hash, SHA1_DIGEST_LENGTH) == -1)
+ if (imsg_add(wbuf, id->hash, GOT_OBJECT_ID_MAXLEN) == -1)
return got_error_from_errno("imsg_add REF");
+ if (imsg_add(wbuf, &algo, sizeof(algo)) == -1)
+ return got_error_from_errno("imsg_add REF");
if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1)
return got_error_from_errno("imsg_add REF");
if (imsg_add(wbuf, refname, namelen) == -1)
@@ -291,6 +299,7 @@ list_refs(struct imsg *imsg)
return err;
memset(&irefs, 0, sizeof(irefs));
+ irefs.algo = got_repo_get_object_format(repo_write.repo);
TAILQ_FOREACH(re, &refs, entry) {
struct got_object_id *id;
int obj_type;
@@ -367,7 +376,7 @@ verify_object_type(struct got_object_id *id, int expec
struct got_pack *pack, struct got_packidx *packidx)
{
const struct got_error *err;
- char hex[SHA1_DIGEST_STRING_LENGTH];
+ char hex[GOT_HASH_DIGEST_STRING_MAXLEN];
struct got_object *obj;
int idx;
const char *typestr;
@@ -426,7 +435,7 @@ protect_require_yca(struct got_object_id *tip_id,
struct got_object_id *expected_yca_id = NULL;
struct got_object *obj = NULL;
struct got_commit_object *commit = NULL;
- char hex[SHA1_DIGEST_STRING_LENGTH];
+ char hex[GOT_HASH_DIGEST_STRING_MAXLEN];
const struct got_object_id_queue *parent_ids;
struct got_object_id_queue ids;
struct got_object_qid *pid, *qid;
@@ -525,7 +534,7 @@ protect_require_yca(struct got_object_id *tip_id,
goto done;
err = got_object_parse_commit(&commit, buf, len,
- GOT_HASH_SHA1);
+ got_repo_get_object_format(repo_write.repo));
if (err)
goto done;
@@ -619,7 +628,7 @@ protect_branch(const char *refname, struct got_pack *p
static const struct got_error *
recv_ref_update(struct imsg *imsg)
{
- static const char zero_id[SHA1_DIGEST_LENGTH];
+ static const char zero_id[GOT_OBJECT_ID_MAXLEN];
const struct got_error *err = NULL;
struct repo_write_client *client = &repo_write_client;
struct gotd_imsg_ref_update iref;
@@ -629,6 +638,8 @@ recv_ref_update(struct imsg *imsg)
struct got_object_id *id = NULL;
struct imsgbuf ibuf;
struct gotd_ref_update *ref_update = NULL;
+ int algo = got_repo_get_object_format(repo_write.repo);
+ int digest_length = got_hash_digest_length(algo);
log_debug("ref-update received");
@@ -638,6 +649,8 @@ recv_ref_update(struct imsg *imsg)
memcpy(&iref, imsg->data, sizeof(iref));
if (datalen != sizeof(iref) + iref.name_len)
return got_error(GOT_ERR_PRIVSEP_LEN);
+ if (iref.algo != algo)
+ return got_error(GOT_ERR_OBJECT_FORMAT);
if (imsgbuf_init(&ibuf, client->fd))
return got_error_from_errno("imsgbuf_init");
@@ -655,15 +668,17 @@ recv_ref_update(struct imsg *imsg)
goto done;
}
- memcpy(ref_update->old_id.hash, iref.old_id, SHA1_DIGEST_LENGTH);
- memcpy(ref_update->new_id.hash, iref.new_id, SHA1_DIGEST_LENGTH);
+ memcpy(ref_update->old_id.hash, iref.old_id, GOT_HASH_DIGEST_MAXLEN);
+ ref_update->old_id.algo = algo;
+ memcpy(ref_update->new_id.hash, iref.new_id, GOT_HASH_DIGEST_MAXLEN);
+ ref_update->new_id.algo = algo;
err = got_ref_open(&ref, repo_write.repo, refname, 0);
if (err) {
if (err->code != GOT_ERR_NOT_REF)
goto done;
if (memcmp(ref_update->new_id.hash,
- zero_id, sizeof(zero_id)) == 0) {
+ zero_id, digest_length) == 0) {
err = got_error_fmt(GOT_ERR_BAD_OBJ_ID,
"%s", refname);
goto done;
@@ -826,25 +841,26 @@ copy_object_type_and_size(uint8_t *type, uint64_t *siz
static const struct got_error *
copy_ref_delta(int infd, int outfd, off_t *outsize, BUF *buf, size_t *buf_pos,
- struct got_hash *ctx)
+ struct got_hash *ctx, int algo)
{
const struct got_error *err = NULL;
size_t remain = buf_len(buf) - *buf_pos;
+ int digest_length = got_hash_digest_length(algo);
- if (remain < SHA1_DIGEST_LENGTH) {
+ if (remain < digest_length) {
err = read_more_pack_stream(infd, buf,
- SHA1_DIGEST_LENGTH - remain);
+ digest_length - remain);
if (err)
return err;
}
err = got_pack_hwrite(outfd, buf_get(buf) + *buf_pos,
- SHA1_DIGEST_LENGTH, ctx);
+ digest_length, ctx);
if (err)
return err;
- *buf_pos += SHA1_DIGEST_LENGTH;
- *outsize += SHA1_DIGEST_LENGTH;
+ *buf_pos += digest_length;
+ *outsize += digest_length;
return NULL;
}
@@ -1011,8 +1027,8 @@ ensure_all_objects_exist_locally(struct gotd_ref_updat
}
static const struct got_error *
-recv_packdata(off_t *outsize, uint32_t *nobj, uint8_t *sha1,
- int infd, int outfd)
+recv_packdata(off_t *outsize, uint32_t *nobj, uint8_t *hash,
+ int infd, int outfd, int algo)
{
const struct got_error *err;
struct repo_write_client *client = &repo_write_client;
@@ -1020,11 +1036,12 @@ recv_packdata(off_t *outsize, uint32_t *nobj, uint8_t
size_t have;
uint32_t nhave = 0;
struct got_hash ctx;
- uint8_t expected_sha1[SHA1_DIGEST_LENGTH];
- char hex[SHA1_DIGEST_STRING_LENGTH];
+ uint8_t expected_hash[GOT_HASH_DIGEST_MAXLEN];
+ char hex[GOT_HASH_DIGEST_STRING_MAXLEN];
BUF *buf = NULL;
size_t buf_pos = 0, remain;
ssize_t w;
+ int digest_length = got_hash_digest_length(algo);
*outsize = 0;
*nobj = 0;
@@ -1033,7 +1050,7 @@ recv_packdata(off_t *outsize, uint32_t *nobj, uint8_t
if (client->nref_updates == client->nref_del)
return NULL;
- got_hash_init(&ctx, GOT_HASH_SHA1);
+ got_hash_init(&ctx, algo);
err = got_poll_read_full(infd, &have, &hdr, sizeof(hdr), sizeof(hdr));
if (err)
@@ -1100,7 +1117,7 @@ recv_packdata(off_t *outsize, uint32_t *nobj, uint8_t
if (obj_type == GOT_OBJ_TYPE_REF_DELTA) {
err = copy_ref_delta(infd, outfd, outsize,
- buf, &buf_pos, &ctx);
+ buf, &buf_pos, &ctx, algo);
if (err)
goto done;
} else if (obj_type == GOT_OBJ_TYPE_OFFSET_DELTA) {
@@ -1119,40 +1136,40 @@ recv_packdata(off_t *outsize, uint32_t *nobj, uint8_t
log_debug("received %u objects", *nobj);
- got_hash_final(&ctx, expected_sha1);
+ got_hash_final(&ctx, expected_hash);
remain = buf_len(buf) - buf_pos;
- if (remain < SHA1_DIGEST_LENGTH) {
+ if (remain < digest_length) {
err = read_more_pack_stream(infd, buf,
- SHA1_DIGEST_LENGTH - remain);
+ digest_length - remain);
if (err)
return err;
}
- got_sha1_digest_to_str(expected_sha1, hex, sizeof(hex));
- log_debug("expect SHA1: %s", hex);
- got_sha1_digest_to_str(buf_get(buf) + buf_pos, hex, sizeof(hex));
- log_debug("actual SHA1: %s", hex);
+ got_hash_digest_to_str(expected_hash, hex, sizeof(hex), algo);
+ log_debug("expect hash: %s", hex);
+ got_hash_digest_to_str(buf_get(buf) + buf_pos, hex, sizeof(hex), algo);
+ log_debug("actual hash: %s", hex);
- if (memcmp(buf_get(buf) + buf_pos, expected_sha1,
- SHA1_DIGEST_LENGTH) != 0) {
+ if (memcmp(buf_get(buf) + buf_pos, expected_hash,
+ digest_length) != 0) {
err = got_error(GOT_ERR_PACKFILE_CSUM);
goto done;
}
- memcpy(sha1, expected_sha1, SHA1_DIGEST_LENGTH);
+ memcpy(hash, expected_hash, digest_length);
- w = write(outfd, expected_sha1, SHA1_DIGEST_LENGTH);
+ w = write(outfd, expected_hash, digest_length);
if (w == -1) {
err = got_error_from_errno("write");
goto done;
}
- if (w != SHA1_DIGEST_LENGTH) {
+ if (w != digest_length) {
err = got_error(GOT_ERR_IO);
goto done;
}
- *outsize += SHA1_DIGEST_LENGTH;
+ *outsize += digest_length;
if (fsync(outfd) == -1) {
err = got_error_from_errno("fsync");
@@ -1232,6 +1249,7 @@ recv_packfile(int *have_packfile, struct imsg *imsg)
struct got_pack *pack = NULL;
off_t pack_filesize = 0;
uint32_t nobj = 0;
+ int algo = got_repo_get_object_format(repo_write.repo);
log_debug("packfile request received");
@@ -1253,6 +1271,7 @@ recv_packfile(int *have_packfile, struct imsg *imsg)
err = got_error(GOT_ERR_PRIVSEP_NO_FD);
goto done;
}
+ pack->algo = got_repo_get_object_format(repo_write.repo);
err = got_delta_cache_alloc(&pack->delta_cache);
if (err)
@@ -1285,7 +1304,8 @@ recv_packfile(int *have_packfile, struct imsg *imsg)
log_debug("receiving pack data");
unpack_err = recv_packdata(&pack_filesize, &nobj,
- client->pack_sha1, client->pack_pipe, pack->fd);
+ client->pack_hash, client->pack_pipe, pack->fd,
+ got_repo_get_object_format(repo_write.repo));
if (ireq.report_status) {
err = report_pack_status(unpack_err);
if (err) {
@@ -1332,10 +1352,11 @@ recv_packfile(int *have_packfile, struct imsg *imsg)
pack->filesize = pack_filesize;
*have_packfile = 1;
+ pack->algo = algo;
memset(&id, 0, sizeof(id));
- memcpy(&id.hash, client->pack_sha1, SHA1_DIGEST_LENGTH);
- id.algo = GOT_HASH_SHA1;
+ memcpy(&id.hash, client->pack_hash, GOT_HASH_DIGEST_MAXLEN);
+ id.algo = algo;
log_debug("begin indexing pack (%lld bytes in size)",
(long long)pack->filesize);
@@ -1380,7 +1401,7 @@ verify_packfile(void)
char *id_str = NULL;
struct got_object *obj = NULL;
struct got_pathlist_entry *pe;
- char hex[SHA1_DIGEST_STRING_LENGTH];
+ char hex[GOT_HASH_DIGEST_STRING_MAXLEN];
if (STAILQ_EMPTY(&client->ref_updates)) {
return got_error_msg(GOT_ERR_BAD_REQUEST,
@@ -1409,6 +1430,7 @@ verify_packfile(void)
client->packidx->fd = client->packidx_fd;
client->packidx_fd = -1;
client->packidx->len = sb.st_size;
+ client->packidx->algo = got_repo_get_object_format(repo_write.repo);
err = got_packidx_init_hdr(client->packidx, 1, client->pack.filesize);
if (err)
@@ -1577,7 +1599,8 @@ install_packfile(struct gotd_imsgev *iev)
int ret;
memset(&inst, 0, sizeof(inst));
- memcpy(inst.pack_sha1, client->pack_sha1, SHA1_DIGEST_LENGTH);
+ memcpy(inst.pack_hash, client->pack_hash, GOT_HASH_DIGEST_MAXLEN);
+ inst.algo = got_repo_get_object_format(repo_write.repo);
ret = gotd_imsg_compose_event(iev, GOTD_IMSG_PACKFILE_INSTALL,
GOTD_PROC_REPO_WRITE, -1, &inst, sizeof(inst));
@@ -1614,8 +1637,9 @@ send_ref_update(struct gotd_ref_update *ref_update, st
size_t len;
memset(&iref, 0, sizeof(iref));
- memcpy(iref.old_id, ref_update->old_id.hash, SHA1_DIGEST_LENGTH);
- memcpy(iref.new_id, ref_update->new_id.hash, SHA1_DIGEST_LENGTH);
+ memcpy(iref.old_id, ref_update->old_id.hash, GOT_HASH_DIGEST_MAXLEN);
+ memcpy(iref.new_id, ref_update->new_id.hash, GOT_HASH_DIGEST_MAXLEN);
+ iref.algo = got_repo_get_object_format(repo_write.repo);
iref.ref_is_new = ref_update->ref_is_new;
iref.delete_ref = ref_update->delete_ref;
iref.name_len = strlen(refname);
@@ -2313,7 +2337,7 @@ open_tree(struct got_tree_object **tree, struct got_pa
goto done;
err = got_object_parse_tree(&entries, &nentries, &nentries_alloc,
- buf, len, GOT_HASH_SHA1);
+ buf, len, pack->algo);
if (err)
goto done;
@@ -2340,7 +2364,7 @@ open_tree(struct got_tree_object **tree, struct got_pa
goto done;
}
memcpy(te->id.hash, pe->id, pe->digest_len);
- te->id.algo = GOT_HASH_SHA1;
+ te->id.algo = te->id.algo;
te->mode = pe->mode;
te->idx = i;
}
@@ -2544,7 +2568,8 @@ get_content_from_packfile(struct gotd_imsgev *iev, str
got_object_close(obj);
obj = NULL;
- err = got_object_parse_commit(&commit, buf, len, GOT_HASH_SHA1);
+ err = got_object_parse_commit(&commit, buf, len,
+ got_repo_get_object_format(repo_write.repo));
if (err)
goto done;
}
@@ -2982,11 +3007,6 @@ repo_write_main(const char *title, const char *repo_pa
"bare git repository required");
goto done;
}
- if (got_repo_get_object_format(repo_write.repo) != GOT_HASH_SHA1) {
- err = got_error_msg(GOT_ERR_NOT_IMPL,
- "sha256 object IDs unsupported in network protocol");
- goto done;
- }
got_repo_temp_fds_set(repo_write.repo, temp_fds);
blob - 228f82969a66d68f440abc9aaa7585e26f2fe4ef
blob + f46395cc38f9b4b89ee7dd569060ea62cd47ba90
--- gotd/session_read.c
+++ gotd/session_read.c
@@ -352,7 +352,8 @@ forward_want(struct gotd_session_client *client, struc
memcpy(&ireq, imsg->data, datalen);
memset(&iwant, 0, sizeof(iwant));
- memcpy(iwant.object_id, ireq.object_id, SHA1_DIGEST_LENGTH);
+ memcpy(iwant.object_id, ireq.object_id, GOT_OBJECT_ID_MAXLEN);
+ iwant.algo = got_repo_get_object_format(gotd_session.repo);
if (gotd_imsg_compose_event(&gotd_session.repo_child_iev,
GOTD_IMSG_WANT, GOTD_PROC_SESSION_READ, -1,
@@ -376,7 +377,8 @@ forward_have(struct gotd_session_client *client, struc
memcpy(&ireq, imsg->data, datalen);
memset(&ihave, 0, sizeof(ihave));
- memcpy(ihave.object_id, ireq.object_id, SHA1_DIGEST_LENGTH);
+ memcpy(ihave.object_id, ireq.object_id, GOT_OBJECT_ID_MAXLEN);
+ ihave.algo = got_repo_get_object_format(gotd_session.repo);
if (gotd_imsg_compose_event(&gotd_session.repo_child_iev,
GOTD_IMSG_HAVE, GOTD_PROC_SESSION_READ, -1,
@@ -514,6 +516,11 @@ session_dispatch_client(int fd, short events, void *ar
log_debug("receiving capabilities from uid %d",
client->euid);
err = recv_capabilities(client, &imsg);
+ if (client->ncapa_alloc != 0)
+ break;
+ gotd_session.state = GOTD_STATE_EXPECT_WANT;
+ client->accept_flush_pkt = 1;
+ log_debug("uid %d: expecting want-lines", client->euid);
break;
case GOTD_IMSG_CAPABILITY:
if (gotd_session.state != GOTD_STATE_EXPECT_CAPABILITIES) {
@@ -877,11 +884,6 @@ session_read_main(const char *title, const char *repo_
"bare git repository required");
goto done;
}
- if (got_repo_get_object_format(gotd_session.repo) != GOT_HASH_SHA1) {
- err = got_error_msg(GOT_ERR_NOT_IMPL,
- "sha256 object IDs unsupported in network protocol");
- goto done;
- }
got_repo_temp_fds_set(gotd_session.repo, temp_fds);
blob - 0d66baf23206ed2470f63f77db17d06a5ee81c43
blob + 2e5aaaed7a9bb521719ad604a4121a1531d88d73
--- gotd/session_write.c
+++ gotd/session_write.c
@@ -348,6 +348,9 @@ recv_packfile_install(struct imsg *imsg)
return got_error(GOT_ERR_PRIVSEP_LEN);
memcpy(&inst, imsg->data, sizeof(inst));
+ if (inst.algo != got_repo_get_object_format(gotd_session.repo))
+ return got_error(GOT_ERR_OBJECT_FORMAT);
+
return NULL;
}
@@ -380,6 +383,9 @@ recv_ref_update(struct imsg *imsg)
return got_error(GOT_ERR_PRIVSEP_LEN);
memcpy(&iref, imsg->data, sizeof(iref));
+ if (iref.algo != got_repo_get_object_format(gotd_session.repo))
+ return got_error(GOT_ERR_OBJECT_FORMAT);
+
return NULL;
}
@@ -393,8 +399,9 @@ send_ref_update_ok(struct gotd_session_client *client,
size_t len;
memset(&iok, 0, sizeof(iok));
- memcpy(iok.old_id, iref->old_id, SHA1_DIGEST_LENGTH);
- memcpy(iok.new_id, iref->new_id, SHA1_DIGEST_LENGTH);
+ memcpy(iok.old_id, iref->old_id, GOT_OBJECT_ID_MAXLEN);
+ memcpy(iok.new_id, iref->new_id, GOT_OBJECT_ID_MAXLEN);
+ iok.algo = got_repo_get_object_format(gotd_session.repo);
iok.name_len = strlen(refname);
len = sizeof(iok) + iok.name_len;
@@ -435,8 +442,9 @@ send_ref_update_ng(struct gotd_session_client *client,
size_t len;
memset(&ing, 0, sizeof(ing));
- memcpy(ing.old_id, iref->old_id, SHA1_DIGEST_LENGTH);
- memcpy(ing.new_id, iref->new_id, SHA1_DIGEST_LENGTH);
+ memcpy(ing.old_id, iref->old_id, GOT_OBJECT_ID_MAXLEN);
+ memcpy(ing.new_id, iref->new_id, GOT_OBJECT_ID_MAXLEN);
+ ing.algo = got_repo_get_object_format(gotd_session.repo);
ing.name_len = strlen(refname);
ng_err = got_error_fmt(GOT_ERR_REF_BUSY, "%s", reason);
@@ -466,9 +474,10 @@ install_pack(struct gotd_session_client *client, const
{
const struct got_error *err = NULL;
struct gotd_imsg_packfile_install inst;
- char hex[SHA1_DIGEST_STRING_LENGTH];
+ char hex[GOT_HASH_DIGEST_STRING_MAXLEN];
size_t datalen;
char *packfile_path = NULL, *packidx_path = NULL;
+ int algo = got_repo_get_object_format(gotd_session.repo);
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
if (datalen != sizeof(inst))
@@ -482,9 +491,13 @@ install_pack(struct gotd_session_client *client, const
return got_error_msg(GOT_ERR_BAD_REQUEST,
"client has no pack file index");
- if (got_sha1_digest_to_str(inst.pack_sha1, hex, sizeof(hex)) == NULL)
+ if (inst.algo != algo)
+ return got_error(GOT_ERR_OBJECT_FORMAT);
+
+ if (got_hash_digest_to_str(inst.pack_hash,
+ hex, sizeof(hex), algo) == NULL)
return got_error_msg(GOT_ERR_NO_SPACE,
- "could not convert pack file SHA1 to hex");
+ "could not convert pack file hash to hex");
if (asprintf(&packfile_path, "/%s/%s/pack-%s.pack",
repo_path, GOT_OBJECTS_PACK_DIR, hex) == -1) {
@@ -819,8 +832,9 @@ update_ref(int *shut, struct gotd_session_client *clie
char *refname = NULL;
size_t datalen;
int locked = 0;
- char hex1[SHA1_DIGEST_STRING_LENGTH];
- char hex2[SHA1_DIGEST_STRING_LENGTH];
+ char hex1[GOT_HASH_DIGEST_STRING_MAXLEN];
+ char hex2[GOT_HASH_DIGEST_STRING_MAXLEN];
+ int algo = got_repo_get_object_format(gotd_session.repo);
log_debug("update-ref from uid %d", client->euid);
@@ -840,9 +854,12 @@ update_ref(int *shut, struct gotd_session_client *clie
log_debug("updating ref %s for uid %d", refname, client->euid);
memset(&old_id, 0, sizeof(old_id));
- memcpy(old_id.hash, iref.old_id, SHA1_DIGEST_LENGTH);
+ memcpy(old_id.hash, iref.old_id, GOT_OBJECT_ID_MAXLEN);
+ old_id.algo = algo;
memset(&new_id, 0, sizeof(new_id));
- memcpy(new_id.hash, iref.new_id, SHA1_DIGEST_LENGTH);
+ memcpy(new_id.hash, iref.new_id, GOT_OBJECT_ID_MAXLEN);
+ new_id.algo = algo;
+ iref.algo = algo;
err = got_repo_find_object_id(iref.delete_ref ? &old_id : &new_id,
repo);
if (err)
@@ -2049,11 +2066,6 @@ session_write_main(const char *title, const char *repo
"bare git repository required");
goto done;
}
- if (got_repo_get_object_format(gotd_session.repo) != GOT_HASH_SHA1) {
- err = got_error_msg(GOT_ERR_NOT_IMPL,
- "sha256 object IDs unsupported in network protocol");
- goto done;
- }
got_repo_temp_fds_set(gotd_session.repo, temp_fds);
blob - 0816d33084cd3fb7e16eefb43b32e22dcd16fb4f
blob + 54b7d4cb783e699892aaaf86f4d0d37dd6bb1872
--- include/got_object.h
+++ include/got_object.h
@@ -17,6 +17,9 @@
#define GOT_OBJECT_ID_MAXLEN SHA256_DIGEST_LENGTH
#define GOT_OBJECT_ID_HEX_MAXLEN SHA256_DIGEST_STRING_LENGTH
+#define GOT_HASH_DIGEST_MAXLEN SHA256_DIGEST_LENGTH
+#define GOT_HASH_DIGEST_STRING_MAXLEN SHA256_DIGEST_STRING_LENGTH
+
enum got_hash_algorithm {
GOT_HASH_SHA1,
GOT_HASH_SHA256,
blob - c5559d5bed5c228ed83c16badfd579abe11a3c05
blob + 4b5e11a8b1451e7d898491db0bd4ed5d466806c6
--- lib/gitproto.c
+++ lib/gitproto.c
@@ -146,8 +146,15 @@ got_gitproto_parse_want_line(char **id_str,
}
free(tokens[0]);
- if (tokens[1])
+ if (tokens[1]) {
+ char *lf;
+
*id_str = tokens[1];
+ lf = strchr(*id_str, '\n');
+ if (lf)
+ *lf = '\0';
+ }
+
if (tokens[2]) {
if (tokens[2][0] != '\0' && *capabilities == NULL) {
char *p;
@@ -185,9 +192,16 @@ got_gitproto_parse_have_line(char **id_str, char *line
}
free(tokens[0]);
- if (tokens[1])
+ if (tokens[1]) {
+ char *lf;
+
*id_str = tokens[1];
+ lf = strchr(*id_str, '\n');
+ if (lf)
+ *lf = '\0';
+ }
+
return NULL;
}
blob - 37b902e172faee0d19cafb57ef7739a0e7153dbd
blob + 08300ac63252d1b275a096f9ef73b4dbd8296d5b
--- lib/got_lib_hash.h
+++ lib/got_lib_hash.h
@@ -17,9 +17,6 @@
#define GOT_SHA1_STRING_ZERO "0000000000000000000000000000000000000000"
#define GOT_SHA256_STRING_ZERO "0000000000000000000000000000000000000000000000000000000000000000"
-#define GOT_HASH_DIGEST_MAXLEN SHA256_DIGEST_LENGTH
-#define GOT_HASH_DIGEST_STRING_MAXLEN SHA256_DIGEST_STRING_LENGTH
-
int got_parse_xdigit(uint8_t *, const char *);
char *got_sha1_digest_to_str(const uint8_t *, char *, size_t);
@@ -87,3 +84,6 @@ void got_hash_final_object_id(struct got_hash *, struc
* Compare two hash digest; similar to memcmp().
*/
int got_hash_cmp(enum got_hash_algorithm, uint8_t *, uint8_t *);
+
+/* Return a human-readable name of the hash algorithm. */
+const char *got_hash_algo_name(enum got_hash_algorithm);
blob - 5911bacfda535885152cd7e9f16c9481094c581c
blob + b61756d9f105ede5caba24a642c952d527f0cae8
--- lib/hash.c
+++ lib/hash.c
@@ -248,3 +248,17 @@ got_hash_cmp(enum got_hash_algorithm algo, uint8_t *b1
abort();
return -1;
}
+
+const char *
+got_hash_algo_name(enum got_hash_algorithm algo)
+{
+ switch (algo) {
+ case GOT_HASH_SHA1:
+ return "sha1";
+ case GOT_HASH_SHA256:
+ return "sha256";
+ default:
+ abort();
+ return NULL;
+ }
+}
blob - f3790b51d47dc806017f73f9ecdf46021131aed8
blob + 418676c10c8a264d9436e8a89375c414d80eca8b
--- lib/serve.c
+++ lib/serve.c
@@ -73,33 +73,57 @@ static const struct got_capability write_capabilities[
static const struct got_error *
append_read_capabilities(size_t *capalen, size_t len, const char *symrefstr,
- uint8_t *buf, size_t bufsize)
+ uint8_t *buf, size_t bufsize, int algo)
{
- struct got_capability capa[nitems(read_capabilities) + 1];
+ struct got_capability capa[nitems(read_capabilities) + 2];
size_t ncapa;
memcpy(&capa, read_capabilities, sizeof(read_capabilities));
+ ncapa = nitems(read_capabilities);
if (symrefstr) {
- capa[nitems(read_capabilities)].key = "symref";
- capa[nitems(read_capabilities)].value = symrefstr;
- ncapa = nitems(capa);
- } else
- ncapa = nitems(read_capabilities);
+ capa[ncapa].key = "symref";
+ capa[ncapa].value = symrefstr;
+ ncapa++;
+ }
+ if (algo == GOT_HASH_SHA256) {
+ capa[ncapa].key = GOT_CAPA_OBJECT_FORMAT;
+ capa[ncapa].value = "sha256";
+ ncapa++;
+ }
return got_gitproto_append_capabilities(capalen, buf, len,
bufsize, capa, ncapa);
}
static const struct got_error *
+append_write_capabilities(size_t *capalen, size_t len, const char *symrefstr,
+ uint8_t *buf, size_t bufsize, int algo)
+{
+ struct got_capability capa[nitems(write_capabilities) + 1];
+ size_t ncapa;
+
+ memcpy(&capa, write_capabilities, sizeof(write_capabilities));
+ ncapa = nitems(write_capabilities);
+ if (algo == GOT_HASH_SHA256) {
+ capa[ncapa].key = GOT_CAPA_OBJECT_FORMAT;
+ capa[ncapa].value = "sha256";
+ ncapa++;
+ }
+
+ return got_gitproto_append_capabilities(capalen, buf, len,
+ bufsize, capa, ncapa);
+}
+
+static const struct got_error *
send_ref(int outfd, uint8_t *id, const char *refname, int send_capabilities,
- int client_is_reading, const char *symrefstr, int chattygot)
+ int client_is_reading, const char *symrefstr, int chattygot, int algo)
{
const struct got_error *err = NULL;
- char hex[SHA1_DIGEST_STRING_LENGTH];
+ char hex[GOT_HASH_DIGEST_STRING_MAXLEN];
char buf[GOT_PKT_MAX];
size_t len, capalen = 0;
-
- if (got_sha1_digest_to_str(id, hex, sizeof(hex)) == NULL)
+
+ if (got_hash_digest_to_str(id, hex, sizeof(hex), algo) == NULL)
return got_error(GOT_ERR_BAD_OBJ_ID);
len = snprintf(buf, sizeof(buf), "%s %s", hex, refname);
@@ -109,11 +133,10 @@ send_ref(int outfd, uint8_t *id, const char *refname,
if (send_capabilities) {
if (client_is_reading) {
err = append_read_capabilities(&capalen, len,
- symrefstr, buf, sizeof(buf));
+ symrefstr, buf, sizeof(buf), algo);
} else {
- err = got_gitproto_append_capabilities(&capalen,
- buf, len, sizeof(buf), write_capabilities,
- nitems(write_capabilities));
+ err = append_write_capabilities(&capalen, len,
+ symrefstr, buf, sizeof(buf), algo);
}
if (err)
return err;
@@ -130,26 +153,32 @@ send_ref(int outfd, uint8_t *id, const char *refname,
}
static const struct got_error *
-send_zero_refs(int outfd, int client_is_reading, int chattygot)
+send_zero_refs(int outfd, int client_is_reading, int chattygot, int algo)
{
const struct got_error *err = NULL;
- const char *line = GOT_SHA1_STRING_ZERO " capabilities^{}";
+ const char *line;
char buf[GOT_PKT_MAX];
size_t len, capalen = 0;
+ if (algo == GOT_HASH_SHA1)
+ line = GOT_SHA1_STRING_ZERO " capabilities^{}";
+ else if (algo == GOT_HASH_SHA256)
+ line = GOT_SHA256_STRING_ZERO " capabilities^{}";
+ else
+ return got_error(GOT_ERR_OBJECT_FORMAT);
+
len = strlcpy(buf, line, sizeof(buf));
if (len >= sizeof(buf))
return got_error(GOT_ERR_NO_SPACE);
if (client_is_reading) {
- err = got_gitproto_append_capabilities(&capalen, buf, len,
- sizeof(buf), read_capabilities, nitems(read_capabilities));
+ err = append_read_capabilities(&capalen, len,
+ NULL, buf, sizeof(buf), algo);
if (err)
return err;
} else {
- err = got_gitproto_append_capabilities(&capalen, buf, len,
- sizeof(buf), write_capabilities,
- nitems(write_capabilities));
+ err = append_write_capabilities(&capalen, len,
+ NULL, buf, sizeof(buf), algo);
if (err)
return err;
}
@@ -173,8 +202,8 @@ echo_error(const struct got_error *err, int outfd, int
}
static const struct got_error *
-announce_refs(int outfd, struct imsgbuf *ibuf, int client_is_reading,
- const char *repo_path, int chattygot)
+announce_refs(int outfd, int *algo, struct imsgbuf *ibuf,
+ int client_is_reading, const char *repo_path, int chattygot)
{
const struct got_error *err = NULL;
struct imsg imsg;
@@ -188,6 +217,8 @@ announce_refs(int outfd, struct imsgbuf *ibuf, int cli
char *symrefname = NULL, *symreftarget = NULL, *symrefstr = NULL;
char *refname = NULL;
+ *algo = GOT_NUM_HASH_ALGOS;
+
memset(&imsg, 0, sizeof(imsg));
memset(&lsref, 0, sizeof(lsref));
@@ -226,7 +257,8 @@ announce_refs(int outfd, struct imsgbuf *ibuf, int cli
err = gotd_imsg_recv_error(NULL, &imsg);
goto done;
case GOTD_IMSG_REFLIST:
- if (have_nrefs || nrefs > 0) {
+ if (have_nrefs || nrefs > 0 ||
+ *algo != GOT_NUM_HASH_ALGOS) {
err = got_error(GOT_ERR_PRIVSEP_MSG);
goto done;
}
@@ -236,13 +268,24 @@ announce_refs(int outfd, struct imsgbuf *ibuf, int cli
}
memcpy(&ireflist, imsg.data, sizeof(ireflist));
nrefs = ireflist.nrefs;
+ if (ireflist.algo != GOT_HASH_SHA1 &&
+ ireflist.algo != GOT_HASH_SHA256) {
+ err = got_error(GOT_ERR_OBJECT_FORMAT);
+ goto done;
+ }
+ *algo = ireflist.algo;
have_nrefs = 1;
- if (nrefs == 0)
+ if (nrefs == 0) {
err = send_zero_refs(outfd, client_is_reading,
- chattygot);
+ chattygot, *algo);
+ if (err)
+ goto done;
+ sent_capabilities = 1;
+ }
break;
case GOTD_IMSG_REF:
- if (!have_nrefs || nrefs == 0) {
+ if (!have_nrefs || nrefs == 0 ||
+ *algo == GOT_NUM_HASH_ALGOS) {
err = got_error(GOT_ERR_PRIVSEP_MSG);
goto done;
}
@@ -261,9 +304,13 @@ announce_refs(int outfd, struct imsgbuf *ibuf, int cli
err = got_error_from_errno("strndup");
goto done;
}
+ if (iref.algo != *algo) {
+ err = got_error(GOT_ERR_OBJECT_FORMAT);
+ goto done;
+ }
err = send_ref(outfd, iref.id, refname,
!sent_capabilities, client_is_reading,
- NULL, chattygot);
+ NULL, chattygot, *algo);
free(refname);
refname = NULL;
if (err)
@@ -273,7 +320,8 @@ announce_refs(int outfd, struct imsgbuf *ibuf, int cli
nrefs--;
break;
case GOTD_IMSG_SYMREF:
- if (!have_nrefs || nrefs == 0) {
+ if (!have_nrefs || nrefs == 0 ||
+ *algo == GOT_NUM_HASH_ALGOS) {
err = got_error(GOT_ERR_PRIVSEP_MSG);
goto done;
}
@@ -316,9 +364,13 @@ announce_refs(int outfd, struct imsgbuf *ibuf, int cli
err = got_error_from_errno("asprintf");
goto done;
}
+ if (isymref.algo != *algo) {
+ err = got_error(GOT_ERR_OBJECT_FORMAT);
+ goto done;
+ }
err = send_ref(outfd, isymref.target_id, symrefname,
!sent_capabilities, client_is_reading, symrefstr,
- chattygot);
+ chattygot, *algo);
free(refname);
refname = NULL;
if (err)
@@ -346,9 +398,64 @@ done:
}
static const struct got_error *
-parse_want_line(char **common_capabilities, uint8_t *id, char *buf, size_t len)
+negotiate_hash_algorithm(const char *client_capabilities,
+ enum got_hash_algorithm server_algo, int require_client_algo)
{
const struct got_error *err;
+ char *s = NULL;
+ struct got_capability *capa = NULL;
+ size_t ncapa = 0;
+ const char *object_format;
+ enum got_hash_algorithm client_algo = GOT_NUM_HASH_ALGOS;
+
+ s = strdup(client_capabilities);
+ if (s == NULL)
+ return got_error_from_errno("strdup");
+
+ err = got_gitproto_split_capabilities_str(&capa, &ncapa, s);
+ if (err)
+ goto done;
+
+ if (got_gitproto_find_capability(&object_format,
+ capa, ncapa, GOT_CAPA_OBJECT_FORMAT)) {
+ if (strcmp(object_format,
+ GOT_CAPA_OBJECT_FORMAT_SHA256) == 0) {
+ client_algo = GOT_HASH_SHA256;
+ } else if (strcmp(object_format,
+ GOT_CAPA_OBJECT_FORMAT_SHA1) == 0) {
+ client_algo = GOT_HASH_SHA1;
+ } else {
+ err = got_error_fmt(GOT_ERR_OBJECT_FORMAT,
+ "unknown hash algorithm %s", object_format);
+ goto done;
+ }
+ }
+
+ /*
+ * Some Git clients do not send an object-format capability
+ * when fetching, in which case we must trust that they do
+ * support our hash algorithm.
+ */
+ if (require_client_algo && client_algo != server_algo) {
+ err = got_error_fmt(GOT_ERR_OBJECT_FORMAT,
+ "your Git client uses hash algorithm %s "
+ "which is incompatible with the hash "
+ "algorithm %s used by this repository",
+ got_hash_algo_name(client_algo),
+ got_hash_algo_name(server_algo));
+ goto done;
+ }
+done:
+ free(s);
+ free(capa);
+ return err;
+}
+
+static const struct got_error *
+parse_want_line(char **common_capabilities, uint8_t *id, char *buf, size_t len,
+ int algo, int expect_capabilities)
+{
+ const struct got_error *err;
char *id_str = NULL, *client_capabilities = NULL;
err = got_gitproto_parse_want_line(&id_str,
@@ -356,19 +463,43 @@ parse_want_line(char **common_capabilities, uint8_t *i
if (err)
return err;
- if (!got_parse_hash_digest(id, id_str, GOT_HASH_SHA1)) {
- err = got_error_msg(GOT_ERR_BAD_PACKET,
- "want-line with bad object ID");
+ if (strlen(id_str) != got_hash_digest_string_length(algo) - 1 ||
+ !got_parse_hash_digest(id, id_str, algo)) {
+ err = got_error_fmt(GOT_ERR_BAD_PACKET,
+ "want-line with bad object ID: '%s'", id_str);
goto done;
}
- if (client_capabilities) {
+ if (client_capabilities && expect_capabilities) {
err = got_gitproto_match_capabilities(common_capabilities,
NULL, client_capabilities, read_capabilities,
nitems(read_capabilities));
if (err)
goto done;
+
+ err = negotiate_hash_algorithm(client_capabilities, algo, 0);
+ if (err)
+ goto done;
+
+ if (algo == GOT_HASH_SHA256) {
+ char *s;
+
+ if (asprintf(&s, "%s%s%s=%s", *common_capabilities,
+ (*common_capabilities)[0] != '\0' ? " " : "",
+ GOT_CAPA_OBJECT_FORMAT,
+ GOT_CAPA_OBJECT_FORMAT_SHA256) == -1) {
+ err = got_error_from_errno("asprintf");
+ goto done;
+ }
+ free(*common_capabilities);
+ *common_capabilities = s;
+ }
+ } else if (client_capabilities) {
+ err = got_error_msg(GOT_ERR_BAD_PACKET,
+ "unexpected capability announcement received");
+ goto done;
}
+
done:
free(id_str);
free(client_capabilities);
@@ -376,7 +507,7 @@ done:
}
static const struct got_error *
-parse_have_line(uint8_t *id, char *buf, size_t len)
+parse_have_line(uint8_t *id, char *buf, size_t len, int algo)
{
const struct got_error *err;
char *id_str = NULL;
@@ -385,9 +516,10 @@ parse_have_line(uint8_t *id, char *buf, size_t len)
if (err)
return err;
- if (!got_parse_hash_digest(id, id_str, GOT_HASH_SHA1)) {
- err = got_error_msg(GOT_ERR_BAD_PACKET,
- "have-line with bad object ID");
+ if (strlen(id_str) != got_hash_digest_string_length(algo) - 1 ||
+ !got_parse_hash_digest(id, id_str, algo)) {
+ err = got_error_fmt(GOT_ERR_BAD_PACKET,
+ "have-line with bad object ID: '%s'", id_str);
goto done;
}
done:
@@ -479,7 +611,7 @@ forward_flushpkt(struct imsgbuf *ibuf)
}
static const struct got_error *
-recv_ack(struct imsg *imsg, uint8_t *expected_id)
+recv_ack(struct imsg *imsg, uint8_t *expected_id, int algo)
{
struct gotd_imsg_ack iack;
size_t datalen;
@@ -489,16 +621,18 @@ recv_ack(struct imsg *imsg, uint8_t *expected_id)
return got_error(GOT_ERR_PRIVSEP_LEN);
memcpy(&iack, imsg->data, sizeof(iack));
- if (memcmp(iack.object_id, expected_id, SHA1_DIGEST_LENGTH) != 0)
+ if (iack.algo != algo ||
+ memcmp(iack.object_id, expected_id,
+ got_hash_digest_length(algo)) != 0)
return got_error(GOT_ERR_BAD_OBJ_ID);
return NULL;
}
static const struct got_error *
-recv_nak(struct imsg *imsg, uint8_t *expected_id)
+recv_nak(struct imsg *imsg, uint8_t *expected_id, int algo)
{
- struct gotd_imsg_ack inak;
+ struct gotd_imsg_nak inak;
size_t datalen;
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
@@ -506,7 +640,9 @@ recv_nak(struct imsg *imsg, uint8_t *expected_id)
return got_error(GOT_ERR_PRIVSEP_LEN);
memcpy(&inak, imsg->data, sizeof(inak));
- if (memcmp(inak.object_id, expected_id, SHA1_DIGEST_LENGTH) != 0)
+ if (inak.algo != algo ||
+ memcmp(inak.object_id, expected_id,
+ got_hash_digest_length(algo)) != 0)
return got_error(GOT_ERR_BAD_OBJ_ID);
return NULL;
@@ -515,7 +651,7 @@ recv_nak(struct imsg *imsg, uint8_t *expected_id)
static const struct got_error *
recv_want(int *use_sidebands, int outfd, struct imsgbuf *ibuf,
- char *buf, size_t len, int expect_capabilities, int chattygot)
+ char *buf, size_t len, int expect_capabilities, int chattygot, int algo)
{
const struct got_error *err;
struct gotd_imsg_want iwant;
@@ -526,16 +662,13 @@ recv_want(int *use_sidebands, int outfd, struct imsgbu
memset(&iwant, 0, sizeof(iwant));
memset(&imsg, 0, sizeof(imsg));
- err = parse_want_line(&capabilities_str, iwant.object_id, buf, len);
+ iwant.algo = algo;
+ err = parse_want_line(&capabilities_str, iwant.object_id, buf, len,
+ algo, expect_capabilities);
if (err)
return err;
if (capabilities_str) {
- if (!expect_capabilities) {
- err = got_error_msg(GOT_ERR_BAD_PACKET,
- "unexpected capability announcement received");
- goto done;
- }
err = send_capabilities(use_sidebands, NULL, capabilities_str,
ibuf);
if (err)
@@ -566,7 +699,7 @@ recv_want(int *use_sidebands, int outfd, struct imsgbu
err = gotd_imsg_recv_error(NULL, &imsg);
break;
case GOTD_IMSG_ACK:
- err = recv_ack(&imsg, iwant.object_id);
+ err = recv_ack(&imsg, iwant.object_id, algo);
if (err)
break;
done = 1;
@@ -584,13 +717,13 @@ done:
}
static const struct got_error *
-send_ack(int outfd, uint8_t *id, int chattygot)
+send_ack(int outfd, uint8_t *id, int chattygot, int algo)
{
- char hex[SHA1_DIGEST_STRING_LENGTH];
+ char hex[GOT_HASH_DIGEST_STRING_MAXLEN];
char buf[GOT_PKT_MAX];
int len;
- if (got_sha1_digest_to_str(id, hex, sizeof(hex)) == NULL)
+ if (got_hash_digest_to_str(id, hex, sizeof(hex), algo) == NULL)
return got_error(GOT_ERR_BAD_OBJ_ID);
len = snprintf(buf, sizeof(buf), "ACK %s\n", hex);
@@ -615,7 +748,7 @@ send_nak(int outfd, int chattygot)
static const struct got_error *
recv_have(int *have_ack, int outfd, struct imsgbuf *ibuf, char *buf,
- size_t len, int chattygot)
+ size_t len, int chattygot, int algo)
{
const struct got_error *err;
struct gotd_imsg_have ihave;
@@ -625,7 +758,8 @@ recv_have(int *have_ack, int outfd, struct imsgbuf *ib
memset(&ihave, 0, sizeof(ihave));
memset(&imsg, 0, sizeof(imsg));
- err = parse_have_line(ihave.object_id, buf, len);
+ ihave.algo = algo;
+ err = parse_have_line(ihave.object_id, buf, len, algo);
if (err)
return err;
@@ -650,12 +784,12 @@ recv_have(int *have_ack, int outfd, struct imsgbuf *ib
err = gotd_imsg_recv_error(NULL, &imsg);
break;
case GOTD_IMSG_ACK:
- err = recv_ack(&imsg, ihave.object_id);
+ err = recv_ack(&imsg, ihave.object_id, algo);
if (err)
break;
if (!*have_ack) {
err = send_ack(outfd, ihave.object_id,
- chattygot);
+ chattygot, algo);
if (err)
return err;
*have_ack = 1;
@@ -663,7 +797,7 @@ recv_have(int *have_ack, int outfd, struct imsgbuf *ib
done = 1;
break;
case GOTD_IMSG_NAK:
- err = recv_nak(&imsg, ihave.object_id);
+ err = recv_nak(&imsg, ihave.object_id, algo);
if (err)
break;
done = 1;
@@ -804,14 +938,14 @@ serve_read(int infd, int outfd, int gotd_sock, const c
};
enum protostate curstate = STATE_EXPECT_WANT;
int have_ack = 0, use_sidebands = 0, seen_have = 0, sent_nak = 0;
- int packfd = -1;
+ int packfd = -1, algo = GOT_NUM_HASH_ALGOS;
size_t pack_chunksize;
if (imsgbuf_init(&ibuf, gotd_sock) == -1)
return got_error_from_errno("imsgbuf_init");
imsgbuf_allow_fdpass(&ibuf);
- err = announce_refs(outfd, &ibuf, 1, repo_path, chattygot);
+ err = announce_refs(outfd, &algo, &ibuf, 1, repo_path, chattygot);
if (err)
goto done;
@@ -876,7 +1010,8 @@ serve_read(int infd, int outfd, int gotd_sock, const c
goto done;
}
err = recv_want(&use_sidebands, outfd, &ibuf, buf, n,
- curstate == STATE_EXPECT_WANT ? 1 : 0, chattygot);
+ curstate == STATE_EXPECT_WANT ? 1 : 0, chattygot,
+ algo);
if (err)
goto done;
if (curstate == STATE_EXPECT_WANT)
@@ -888,7 +1023,7 @@ serve_read(int infd, int outfd, int gotd_sock, const c
goto done;
}
err = recv_have(&have_ack, outfd, &ibuf,
- buf, n, chattygot);
+ buf, n, chattygot, algo);
if (err)
goto done;
seen_have = 1;
@@ -961,12 +1096,14 @@ done:
static const struct got_error *
parse_ref_update_line(char **common_capabilities, char **refname,
- uint8_t *old_id, uint8_t *new_id, char *buf, size_t len)
+ uint8_t *old_id, uint8_t *new_id, char *buf, size_t len,
+ int algo, int expect_capabilities)
{
const struct got_error *err;
char *old_id_str = NULL, *new_id_str = NULL;
char *client_capabilities = NULL;
+ *common_capabilities = NULL;
*refname = NULL;
err = got_gitproto_parse_ref_update_line(&old_id_str, &new_id_str,
@@ -974,9 +1111,42 @@ parse_ref_update_line(char **common_capabilities, char
if (err)
return err;
- if (!got_parse_hash_digest(old_id, old_id_str, GOT_HASH_SHA1) ||
- !got_parse_hash_digest(new_id, new_id_str, GOT_HASH_SHA1)) {
+ if (client_capabilities && expect_capabilities) {
+ err = got_gitproto_match_capabilities(common_capabilities,
+ NULL, client_capabilities, write_capabilities,
+ nitems(write_capabilities));
+ if (err)
+ goto done;
+
+ err = negotiate_hash_algorithm(client_capabilities, algo,
+ algo == GOT_HASH_SHA1 ? 0 : 1);
+ if (err)
+ goto done;
+
+ if (algo == GOT_HASH_SHA256) {
+ char *s;
+
+ if (asprintf(&s, "%s%s%s=%s", *common_capabilities,
+ (*common_capabilities)[0] != '\0' ? " " : "",
+ GOT_CAPA_OBJECT_FORMAT,
+ GOT_CAPA_OBJECT_FORMAT_SHA256) == -1) {
+ err = got_error_from_errno("asprintf");
+ goto done;
+ }
+ free(*common_capabilities);
+ *common_capabilities = s;
+ }
+ } else if (client_capabilities) {
err = got_error_msg(GOT_ERR_BAD_PACKET,
+ "unexpected capability announcement received");
+ goto done;
+ }
+
+ if (strlen(old_id_str) != got_hash_digest_string_length(algo) - 1 ||
+ strlen(new_id_str) != got_hash_digest_string_length(algo) - 1 ||
+ !got_parse_hash_digest(old_id, old_id_str, algo) ||
+ !got_parse_hash_digest(new_id, new_id_str, algo)) {
+ err = got_error_msg(GOT_ERR_BAD_PACKET,
"ref-update with bad object ID");
goto done;
}
@@ -985,14 +1155,6 @@ parse_ref_update_line(char **common_capabilities, char
"ref-update with bad reference name");
goto done;
}
-
- if (client_capabilities) {
- err = got_gitproto_match_capabilities(common_capabilities,
- NULL, client_capabilities, write_capabilities,
- nitems(write_capabilities));
- if (err)
- goto done;
- }
done:
free(old_id_str);
free(new_id_str);
@@ -1006,7 +1168,7 @@ done:
static const struct got_error *
recv_ref_update(int *report_status, int outfd, struct imsgbuf *ibuf,
- char *buf, size_t len, int expect_capabilities, int chattygot)
+ char *buf, size_t len, int expect_capabilities, int chattygot, int algo)
{
const struct got_error *err;
struct gotd_imsg_ref_update iref;
@@ -1018,17 +1180,13 @@ recv_ref_update(int *report_status, int outfd, struct
memset(&iref, 0, sizeof(iref));
memset(&imsg, 0, sizeof(imsg));
+ iref.algo = algo;
err = parse_ref_update_line(&capabilities_str, &refname,
- iref.old_id, iref.new_id, buf, len);
+ iref.old_id, iref.new_id, buf, len, algo, expect_capabilities);
if (err)
return err;
if (capabilities_str) {
- if (!expect_capabilities) {
- err = got_error_msg(GOT_ERR_BAD_PACKET,
- "unexpected capability announcement received");
- goto done;
- }
err = send_capabilities(NULL, report_status, capabilities_str,
ibuf);
if (err)
@@ -1063,7 +1221,7 @@ recv_ref_update(int *report_status, int outfd, struct
err = gotd_imsg_recv_error(NULL, &imsg);
break;
case GOTD_IMSG_ACK:
- err = recv_ack(&imsg, iref.new_id);
+ err = recv_ack(&imsg, iref.new_id, algo);
if (err)
break;
done = 1;
@@ -1195,7 +1353,7 @@ done:
}
static const struct got_error *
-recv_ref_update_ok(struct imsg *imsg, int outfd, int chattygot)
+recv_ref_update_ok(struct imsg *imsg, int outfd, int chattygot, int algo)
{
const struct got_error *err = NULL;
struct gotd_imsg_ref_update_ok iok;
@@ -1212,6 +1370,9 @@ recv_ref_update_ok(struct imsg *imsg, int outfd, int c
memcpy(&iok, imsg->data, sizeof(iok));
+ if (iok.algo != algo)
+ return got_error(GOT_ERR_OBJECT_FORMAT);
+
refname = strndup(imsg->data + sizeof(iok), iok.name_len);
if (refname == NULL)
return got_error_from_errno("strndup");
@@ -1229,7 +1390,7 @@ done:
}
static const struct got_error *
-recv_ref_update_ng(struct imsg *imsg, int outfd, int chattygot)
+recv_ref_update_ng(struct imsg *imsg, int outfd, int chattygot, int algo)
{
const struct got_error *err = NULL;
struct gotd_imsg_ref_update_ng ing;
@@ -1246,6 +1407,9 @@ recv_ref_update_ng(struct imsg *imsg, int outfd, int c
memcpy(&ing, imsg->data, sizeof(ing));
+ if (ing.algo != algo)
+ return got_error(GOT_ERR_OBJECT_FORMAT);
+
refname = strndup(imsg->data + sizeof(ing), ing.name_len);
if (refname == NULL)
return got_error_from_errno("strndup");
@@ -1287,6 +1451,8 @@ serve_write(int infd, int outfd, int gotd_sock, const
enum protostate curstate = STATE_EXPECT_REF_UPDATE;
struct imsg imsg;
int report_status = 0;
+ int algo = GOT_NUM_HASH_ALGOS;
+ int digest_string_length;
if (imsgbuf_init(&ibuf, gotd_sock) == -1)
return got_error_from_errno("imsgbuf_init");
@@ -1294,10 +1460,12 @@ serve_write(int infd, int outfd, int gotd_sock, const
memset(&imsg, 0, sizeof(imsg));
- err = announce_refs(outfd, &ibuf, 0, repo_path, chattygot);
+ err = announce_refs(outfd, &algo, &ibuf, 0, repo_path, chattygot);
if (err)
goto done;
+ digest_string_length = got_hash_digest_string_length(algo) - 1;
+
while (curstate != STATE_EXPECT_PACKFILE) {
int n;
@@ -1318,7 +1486,7 @@ serve_write(int infd, int outfd, int gotd_sock, const
if (err)
goto done;
curstate = STATE_EXPECT_PACKFILE;
- } else if (n >= (SHA1_DIGEST_STRING_LENGTH * 2) + 2) {
+ } else if (n >= (digest_string_length * 2) + 1 + 2) {
if (curstate != STATE_EXPECT_REF_UPDATE &&
curstate != STATE_EXPECT_MORE_REF_UPDATES) {
err = got_error_msg(GOT_ERR_BAD_PACKET,
@@ -1327,10 +1495,10 @@ serve_write(int infd, int outfd, int gotd_sock, const
}
if (curstate == STATE_EXPECT_REF_UPDATE) {
err = recv_ref_update(&report_status,
- outfd, &ibuf, buf, n, 1, chattygot);
+ outfd, &ibuf, buf, n, 1, chattygot, algo);
} else {
err = recv_ref_update(NULL, outfd, &ibuf,
- buf, n, 0, chattygot);
+ buf, n, 0, chattygot, algo);
}
if (err)
goto done;
@@ -1390,12 +1558,12 @@ serve_write(int infd, int outfd, int gotd_sock, const
case GOTD_IMSG_REF_UPDATE_OK:
if (!report_status)
break;
- err = recv_ref_update_ok(&imsg, outfd, chattygot);
+ err = recv_ref_update_ok(&imsg, outfd, chattygot, algo);
break;
case GOTD_IMSG_REF_UPDATE_NG:
if (!report_status)
break;
- err = recv_ref_update_ng(&imsg, outfd, chattygot);
+ err = recv_ref_update_ng(&imsg, outfd, chattygot, algo);
break;
case GOTD_IMSG_REFS_UPDATED:
curstate = STATE_REFS_UPDATED;
blob - 19405752bdd0434de7f199e1bf626cfec39abb98
blob + b2bad267ae6d76255c4dcad445bf1c70376cc475
--- regress/gotd/Makefile
+++ regress/gotd/Makefile
@@ -23,6 +23,7 @@ GOTD_TEST_REPO_URL=ssh://${GOTD_DEVUSER}@127.0.0.1/$(G
GOTD_TEST_SMTP_PORT=2525
GOTD_TEST_HTTP_PORT=8000
GOTD_TEST_HMAC_SECRET!=openssl rand -base64 32
+GOT_TEST_ALGO=sha1
GOTD_TEST_USER?=${DOAS_USER}
.if empty(GOTD_TEST_USER)
@@ -62,6 +63,7 @@ GOTD_TEST_ENV=GOTD_TEST_ROOT=$(GOTD_TEST_ROOT) \
GOTD_TEST_SMTP_PORT=$(GOTD_TEST_SMTP_PORT) \
GOTD_TEST_HTTP_PORT=$(GOTD_TEST_HTTP_PORT) \
GOTD_TEST_HMAC_SECRET=$(GOTD_TEST_HMAC_SECRET) \
+ GOT_TEST_ALGO=${GOT_TEST_ALGO} \
HOME=$(GOTD_TEST_USER_HOME) \
PATH=$(GOTD_TEST_USER_HOME)/bin:$(PATH)
blob - faa5431af74cec9f5cfa7792534d3554f94b6ad5
blob + 54dab670fc435e5275587fdd7ec98d70c160ad6a
--- regress/gotd/README
+++ regress/gotd/README
@@ -57,6 +57,11 @@ The server test suite can now be run from the top-leve
The suite must be started as root in order to be able to start and stop gotd.
The test suite switches to non-root users as appropriate.
+By default the test suite uses repositories with the SHA1 hash algorithm.:
+The test suite can also be run with SHA256 repositories:
+
+ $ doas make server-regress GOT_TEST_ALGO=sha256
+
The test suite uses netcat on port 2525 to test SMTP notifications.
If this port is already in use then affected tests might fail.
If needed the port can be overridden on the make command line:
blob - 3fe3744d90fb5f9a963339227ba308d8236361be
blob + d1da9f17831a2667b02c56dff081a9f2257ac8cf
--- regress/gotd/common.sh
+++ regress/gotd/common.sh
@@ -25,7 +25,7 @@ test_init()
local testroot=`mktemp -d \
"$GOTD_TEST_ROOT/gotd-test-$testname-XXXXXXXXXX"`
mkdir $testroot/repo
- git_init $testroot/repo
+ git init -q --object-format=${GOT_TEST_ALGO} $testroot/repo
if [ -z "$no_tree" ]; then
make_test_tree $testroot/repo
(cd $repo && git add .)
blob - 79fd816a3d8d965fa50236f65eb132af7ec334b3
blob + bd9be80a1588e6fe265225e270b94662488367dc
--- regress/gotd/repo_write.sh
+++ regress/gotd/repo_write.sh
@@ -134,7 +134,15 @@ EOF
test_done "$testroot" "$ret"
return 1
fi
- egrep -q '\+pack-[a-f0-9]{40}.pack' $testroot/repo-list.newlines
+
+ if [ "$GOT_TEST_ALGO" = "sha256" ]; then
+ digest_len=64
+ else
+ digest_len=40
+ fi
+
+ egrep -q "\+pack-[a-f0-9]{$digest_len}.pack" \
+ $testroot/repo-list.newlines
ret=$?
if [ $ret -ne 0 ]; then
echo "new pack file not found in ${GOTD_TEST_REPO}"
@@ -142,7 +150,8 @@ EOF
test_done "$testroot" "$ret"
return 1
fi
- egrep -q '\+pack-[a-f0-9]{40}.idx' $testroot/repo-list.newlines
+ egrep -q "\+pack-[a-f0-9]{$digest_len}.idx" \
+ $testroot/repo-list.newlines
ret=$?
if [ $ret -ne 0 ]; then
echo "new pack index not found in ${GOTD_TEST_REPO}"
blob - 2133f4df31306dd4e747e43ec877a41cce3d4b7b
blob + cb4687bd43f00535634e3b44d8569226e7ba45be
--- regress/gotd/repo_write_empty.sh
+++ regress/gotd/repo_write_empty.sh
@@ -111,7 +111,15 @@ EOF
test_done "$testroot" 1
return 1
fi
- egrep -q '\+\./objects/pack/pack-[a-f0-9]{40}\.pack' $testroot/repo-list.newlines
+
+ if [ "$GOT_TEST_ALGO" = "sha256" ]; then
+ digest_len=64
+ else
+ digest_len=40
+ fi
+
+ egrep -q "\+\./objects/pack/pack-[a-f0-9]{$digest_len}\.pack" \
+ $testroot/repo-list.newlines
ret=$?
if [ $ret -ne 0 ]; then
echo "new pack file not found in ${GOTD_TEST_REPO}"
@@ -119,7 +127,8 @@ EOF
test_done "$testroot" "$ret"
return 1
fi
- egrep -q '\+\./objects/pack/pack-[a-f0-9]{40}\.idx' $testroot/repo-list.newlines
+ egrep -q "\+\./objects/pack/pack-[a-f0-9]{$digest_len}\.idx" \
+ $testroot/repo-list.newlines
ret=$?
if [ $ret -ne 0 ]; then
echo "new pack index not found in ${GOTD_TEST_REPO}"
blob - 6d269d7afa9a0a02007a1ba9240895562cd4737b
blob + f7b237ef80382025171c3cd96e87b321acd67abd
--- regress/gotd/request_bad.sh
+++ regress/gotd/request_bad.sh
@@ -18,12 +18,20 @@
. ./common.sh
dummy_commit="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+capabilities="multi_ack side-band-64k ofs-delta"
+server_capabilities="ofs-delta side-band-64k"
+if [ "$GOT_TEST_ALGO" = "sha256" ]; then
+ dummy_commit="${dummy_commit}aaaaaaaaaaaaaaaaaaaaaaaa"
+ capabilities="${capabilities} object-format=sha256"
+ server_capabilities="${server_capabilities} object-format=sha256"
+fi
+
# Non-existent commit
test_request_bad_commit() {
local testroot=`test_init request_bad_commit`
- echo "0054want $dummy_commit multi_ack side-band-64k ofs-delta" \
+ echo "0054want $dummy_commit $capabilities" \
| ssh ${GOTD_DEVUSER}@127.0.0.1 git-upload-pack '/test-repo' \
> $testroot/stdout 2>$testroot/stderr
@@ -31,9 +39,14 @@ test_request_bad_commit() {
# off the initial capabilities advertisement header.
tr '\0' '\n' < $testroot/stdout | tail -n 1 > $testroot/stdout.filtered
- echo -n " agent=got/${GOT_VERSION_STR} ofs-delta side-band-64k0000" \
+ echo -n " agent=got/${GOT_VERSION_STR} ${server_capabilities}0000" \
> $testroot/stdout.expected
- echo -n "0041ERR object $dummy_commit not found" \
+ if [ "$GOT_TEST_ALGO" = "sha256" ]; then
+ echo -n "0059" >> $testroot/stdout.expected
+ else
+ echo -n "0041" >> $testroot/stdout.expected
+ fi
+ echo -n "ERR object $dummy_commit not found" \
>> $testroot/stdout.expected
echo "gotsh: object $dummy_commit not found" \
@@ -62,13 +75,13 @@ test_request_bad_commit() {
test_request_bad_length_zero() {
local testroot=`test_init request_bad_length_zero`
- echo "0000want $dummy_commit multi_ack side-band-64k ofs-delta" \
+ echo "0000want $dummy_commit $capabilities" \
| ssh ${GOTD_DEVUSER}@127.0.0.1 git-upload-pack '/test-repo' \
> $testroot/stdout 2>$testroot/stderr
tr '\0' '\n' < $testroot/stdout | tail -n 1 > $testroot/stdout.filtered
- echo -n " agent=got/${GOT_VERSION_STR} ofs-delta side-band-64k0000" \
+ echo -n " agent=got/${GOT_VERSION_STR} ${server_capabilities}0000" \
> $testroot/stdout.expected
echo -n "0028ERR unexpected flush packet received" \
>> $testroot/stdout.expected
@@ -99,13 +112,13 @@ test_request_bad_length_zero() {
test_request_bad_length_empty() {
local testroot=`test_init request_bad_length_empty`
- echo "0004want $dummy_commit multi_ack side-band-64k ofs-delta" \
+ echo "0004want $dummy_commit $capabilities" \
| ssh ${GOTD_DEVUSER}@127.0.0.1 git-upload-pack '/test-repo' \
> $testroot/stdout 2>$testroot/stderr
tr '\0' '\n' < $testroot/stdout | tail -n 1 > $testroot/stdout.filtered
- echo -n " agent=got/${GOT_VERSION_STR} ofs-delta side-band-64k0000" \
+ echo -n " agent=got/${GOT_VERSION_STR} ${server_capabilities}0000" \
> $testroot/stdout.expected
echo -n '0018ERR packet too short' >> $testroot/stdout.expected
@@ -134,13 +147,13 @@ test_request_bad_length_empty() {
test_request_bad_length_small() {
local testroot=`test_init request_bad_length_small`
- echo "0002want $dummy_commit multi_ack side-band-64k ofs-delta" \
+ echo "0002want $dummy_commit $capabilities" \
| ssh ${GOTD_DEVUSER}@127.0.0.1 git-upload-pack '/test-repo' \
> $testroot/stdout 2>$testroot/stderr
tr '\0' '\n' < $testroot/stdout | tail -n 1 > $testroot/stdout.filtered
- echo -n " agent=got/${GOT_VERSION_STR} ofs-delta side-band-64k0000" \
+ echo -n " agent=got/${GOT_VERSION_STR} ${server_capabilities}0000" \
> $testroot/stdout.expected
echo -n '0018ERR packet too short' >> $testroot/stdout.expected
@@ -169,16 +182,15 @@ test_request_bad_length_small() {
test_request_bad_length_large() {
local testroot=`test_init request_bad_length_large`
- echo "ffffwant $dummy_commit multi_ack side-band-64k ofs-delta" \
+ echo "ffffwant $dummy_commit $capabilities" \
| ssh ${GOTD_DEVUSER}@127.0.0.1 git-upload-pack '/test-repo' \
> $testroot/stdout 2>$testroot/stderr
tr '\0' '\n' < $testroot/stdout | tail -n 1 > $testroot/stdout.filtered
- echo -n " agent=got/${GOT_VERSION_STR} ofs-delta side-band-64k0000" \
+ echo -n " agent=got/${GOT_VERSION_STR} ${server_capabilities}0000" \
> $testroot/stdout.expected
- echo -n '001eERR unexpected end of file' \
- >> $testroot/stdout.expected
+ echo -n '001eERR unexpected end of file' >> $testroot/stdout.expected
echo "gotsh: unexpected end of file" > $testroot/stderr.expected
@@ -211,12 +223,18 @@ test_request_bad_capabilities() {
tr '\0' '\n' < $testroot/stdout | tail -n 1 > $testroot/stdout.filtered
- echo -n " agent=got/${GOT_VERSION_STR} ofs-delta side-band-64k0000" \
+ echo -n " agent=got/${GOT_VERSION_STR} ${server_capabilities}0000" \
> $testroot/stdout.expected
- echo -n "0025ERR unexpected want-line received" \
+ if [ "$GOT_TEST_ALGO" = "sha256" ]; then
+ echo -n "0059" >> $testroot/stdout.expected
+ else
+ echo -n "0041" >> $testroot/stdout.expected
+ fi
+ echo -n "ERR object $dummy_commit not found" \
>> $testroot/stdout.expected
- echo "gotsh: unexpected want-line received" > $testroot/stderr.expected
+ echo "gotsh: object $dummy_commit not found" \
+ > $testroot/stderr.expected
cmp -s $testroot/stdout.expected $testroot/stdout.filtered
ret=$?
add SHA256 support to gotd