From: Stefan Sperling Subject: Re: initial sha256 support in the network protocol To: Omar Polo Cc: gameoftrees@openbsd.org Date: Mon, 9 Feb 2026 18:00:20 +0100 On Sat, Feb 07, 2026 at 06:04:18PM +0100, Omar Polo wrote: > The "big" diff finally! > > In the end I haven't managed to split it in smaller pieces since both > fetch and send changes depends on the changes I'm doing to gitproto. > Hopefully, it's not too big to review ;-) > > There's some leftovers/spoilers on how I was planning to handle clone. > The idea would be to pass -1 for the protocol, and have fetch tell us > what the server supports. It's still a bit tricky because we have to > change the fetch_progress callback and reinitialize some state after > the capabilities are parsed. This is left for later. This makes 'got clone' work for me on top of your diff. I am running out of time for today so I cannot tidy this up right now. I hope this allows you to make progress towards getting tests to pass. M cvg/cvg.c | 19+ 2- M got/got.c | 17+ 2- M include/got_fetch.h | 5+ 2- M include/got_repository.h | 9+ 0- M lib/fetch.c | 28+ 19- M lib/gitproto.c | 11+ 11- M lib/got_lib_gitproto.h | 3+ 0- M lib/got_lib_privsep.h | 1+ 0- M lib/got_lib_repository.h | 1+ 0- M lib/privsep.c | 8+ 2- M lib/repository.c | 19+ 11- M lib/repository_init.c | 65+ 17- M lib/worktree_cvg.c | 2+ 0- M libexec/got-fetch-pack/got-fetch-pack.c | 32+ 1- 14 files changed, 220 insertions(+), 67 deletions(-) commit - 3a30796e10c8ba3088bedf613d9e911264cebfad commit + db093745dd4861787944b61f3dca257620255914 blob - 8bc47fb2cbcc88f89ff5dc2e9eb2cf7445f26c88 blob + db25d3304e991eac1c7422383a0559ca74c1a134 --- cvg/cvg.c +++ cvg/cvg.c @@ -1009,6 +1009,7 @@ struct got_fetch_progress_arg { const char *git_url; int fetch_all_branches; int mirror_references; + int expected_algo; } config_info; }; @@ -1022,6 +1023,7 @@ create_config_files(const char *proto, const char *hos static const struct got_error * fetch_progress(void *arg, const char *message, off_t packfile_size, + struct got_object_id *pack_hash, int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved) { const struct got_error *err = NULL; @@ -1038,6 +1040,14 @@ fetch_progress(void *arg, const char *message, off_t p */ if (a->create_configs && !a->configs_created && !RB_EMPTY(a->config_info.symrefs)) { + if (a->config_info.expected_algo == -1 && + pack_hash->algo == GOT_HASH_SHA256) { + err = got_repo_init_gitconfig(a->repo, + pack_hash->algo); + if (err) + return err; + } + err = create_config_files(a->config_info.proto, a->config_info.host, a->config_info.port, a->config_info.remote_repo_path, @@ -1049,6 +1059,7 @@ fetch_progress(void *arg, const char *message, off_t p a->config_info.wanted_refs, a->repo); if (err) return err; + a->configs_created = 1; } @@ -1721,10 +1732,11 @@ cmd_clone(int argc, char *argv[]) fpa.config_info.git_url = git_url; fpa.config_info.fetch_all_branches = fetch_all_branches; fpa.config_info.mirror_references = mirror_references; + fpa.config_info.expected_algo = -1; error = got_fetch_pack(&pack_hash, &refs, &symrefs, GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references, fetch_all_branches, &wanted_branches, &wanted_refs, - list_refs_only, verbosity, fetchfd, repo, NULL, NULL, bflag, + list_refs_only, verbosity, -1, fetchfd, repo, NULL, NULL, bflag, fetch_progress, &fpa); if (error) goto done; @@ -2678,6 +2690,7 @@ cmd_update(int argc, char *argv[]) int delete_remote = 0; int replace_tags = 0; int *pack_fds = NULL; + int expected_algo; const char *remote_head = NULL, *worktree_branch = NULL; struct got_object_id *commit_id = NULL; char *commit_id_str = NULL; @@ -2902,6 +2915,8 @@ cmd_update(int argc, char *argv[]) if (strncmp(refname, "refs/heads/", 11) == 0) worktree_branch = refname; + expected_algo = got_repo_get_object_format(repo); + fpa.last_scaled_size[0] = '\0'; fpa.last_p_indexed = -1; fpa.last_p_resolved = -1; @@ -2910,10 +2925,12 @@ cmd_update(int argc, char *argv[]) fpa.create_configs = 0; fpa.configs_created = 0; memset(&fpa.config_info, 0, sizeof(fpa.config_info)); + fpa.config_info.expected_algo = expected_algo; error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name, remote->mirror_references, 0, &wanted_branches, &wanted_refs, - 0, verbosity, fetchfd, repo, worktree_branch, remote_head, + 0, verbosity, expected_algo, + fetchfd, repo, worktree_branch, remote_head, 0, fetch_progress, &fpa); if (error) goto done; blob - 487b4865e729be9a32fd1157ab96adf4e609986e blob + a53709f8fc2cca37ac4090e5a082fdad48899dcf --- got/got.c +++ got/got.c @@ -1098,6 +1098,7 @@ struct got_fetch_progress_arg { const char *git_url; int fetch_all_branches; int mirror_references; + int expected_algo; } config_info; }; @@ -1111,6 +1112,7 @@ create_config_files(const char *proto, const char *hos static const struct got_error * fetch_progress(void *arg, const char *message, off_t packfile_size, + struct got_object_id *pack_hash, int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved) { const struct got_error *err = NULL; @@ -1127,6 +1129,14 @@ fetch_progress(void *arg, const char *message, off_t p */ if (a->create_configs && !a->configs_created && !RB_EMPTY(a->config_info.symrefs)) { + if (a->config_info.expected_algo == -1 && + pack_hash->algo == GOT_HASH_SHA256) { + err = got_repo_init_gitconfig(a->repo, + pack_hash->algo); + if (err) + return err; + } + err = create_config_files(a->config_info.proto, a->config_info.host, a->config_info.port, a->config_info.remote_repo_path, @@ -1138,6 +1148,7 @@ fetch_progress(void *arg, const char *message, off_t p a->config_info.wanted_refs, a->repo); if (err) return err; + a->configs_created = 1; } @@ -1820,10 +1831,11 @@ cmd_clone(int argc, char *argv[]) fpa.config_info.git_url = git_url; fpa.config_info.fetch_all_branches = fetch_all_branches; fpa.config_info.mirror_references = mirror_references; + fpa.config_info.expected_algo = -1; error = got_fetch_pack(&pack_hash, &refs, &symrefs, GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references, fetch_all_branches, &wanted_branches, &wanted_refs, - list_refs_only, verbosity, fetchfd, repo, NULL, NULL, bflag, + list_refs_only, verbosity, -1, fetchfd, repo, NULL, NULL, bflag, fetch_progress, &fpa); if (error) goto done; @@ -2762,11 +2774,14 @@ cmd_fetch(int argc, char *argv[]) fpa.repo = repo; fpa.create_configs = 0; fpa.configs_created = 0; + fpa.config_info.expected_algo = got_repo_get_object_format(repo); memset(&fpa.config_info, 0, sizeof(fpa.config_info)); + error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name, remote->mirror_references, fetch_all_branches, &wanted_branches, - &wanted_refs, list_refs_only, verbosity, fetchfd, repo, + &wanted_refs, list_refs_only, verbosity, + got_repo_get_object_format(repo), fetchfd, repo, worktree_branch, remote_head, have_bflag, fetch_progress, &fpa); if (error) goto done; blob - 4e7f538f523c582bd0b2b8be1e97182731a9ec7e blob + 514769c17e48227a0ef18ab5759fca1cde588c37 --- include/got_fetch.h +++ include/got_fetch.h @@ -37,16 +37,19 @@ const struct got_error *got_fetch_connect(pid_t *, int /* A callback function which gets invoked with progress information to print. */ typedef const struct got_error *(*got_fetch_progress_cb)(void *, - const char *, off_t, int, int, int, int); + const char *, off_t, struct got_object_id *, int, int, int, int); /* * Attempt to fetch a packfile from a server. This pack file will contain * objects which that are not yet contained in the provided repository. * Return the hash of the packfile (in form of an object ID) and lists of * references and symbolic references learned from the server. + * The expected object ID format is either from got_repo_get_object_format(), + * or can be passed as -1 to discover the server's object iD hash format + * when cloning a fresh repository. */ const struct got_error *got_fetch_pack(struct got_object_id **, struct got_pathlist_head *, struct got_pathlist_head *, const char *, int, int, struct got_pathlist_head *, struct got_pathlist_head *, - int, int, int, struct got_repository *, const char *, const char *, + int, int, int, int, struct got_repository *, const char *, const char *, int, got_fetch_progress_cb, void *); blob - 89dabf01804eecca3d8273fcc04ca27c031c0f5e blob + 7703401a56a83065fab1b59a58a52079860f8bff --- include/got_repository.h +++ include/got_repository.h @@ -158,6 +158,15 @@ const struct got_error *got_repo_map_path(char **, str const struct got_error *got_repo_init(const char *, const char *, enum got_hash_algorithm); +/* + * Create a new config file for git in the specified repository, + * resetting parameters such as the object Id hash algorithm. + * Should only be used if the repository is freshly cloned and has + * wrong setings in the existing configuration file. + */ +const struct got_error *got_repo_init_gitconfig(struct got_repository *, + enum got_hash_algorithm); + /* Attempt to find a unique object ID for a given ID string prefix. */ const struct got_error *got_repo_match_object_id_prefix(struct got_object_id **, const char *, int, struct got_repository *); blob - b78727982872932c8a61d31ef72455d7c93c4b63 blob + ef20ad90080e0a5bfb77b37b0d2dd3144a0d28c5 --- lib/fetch.c +++ lib/fetch.c @@ -111,7 +111,8 @@ got_fetch_pack(struct got_object_id **pack_hash, struc int mirror_references, int fetch_all_branches, struct got_pathlist_head *wanted_branches, struct got_pathlist_head *wanted_refs, int list_refs_only, int verbosity, - int fetchfd, struct got_repository *repo, const char *worktree_refname, + int expected_algo, int fetchfd, struct got_repository *repo, + const char *worktree_refname, const char *remote_head, int no_head, got_fetch_progress_cb progress_cb, void *progress_arg) { @@ -135,8 +136,7 @@ got_fetch_pack(struct got_object_id **pack_hash, struc uint32_t nobj = 0; char *path; char *progress = NULL; - enum got_hash_algorithm algo = GOT_HASH_SHA1; - size_t idlen; + size_t idlen = 0; *pack_hash = NULL; memset(&fetchibuf, 0, sizeof(fetchibuf)); @@ -155,13 +155,7 @@ got_fetch_pack(struct got_object_id **pack_hash, struc return got_error_path(refname, GOT_ERR_FETCH_BAD_REF); } - /* for listing refs we don't actually care about the algorithm */ if (!list_refs_only) - algo = got_repo_get_object_format(repo); - - idlen = got_hash_digest_length(algo); - - if (!list_refs_only) repo_path = got_repo_get_path_git_dir(repo); for (i = 0; i < nitems(tmpfds); i++) @@ -285,8 +279,8 @@ got_fetch_pack(struct got_object_id **pack_hash, struc err = got_error_from_errno("dup"); goto done; } - err = got_privsep_send_fetch_req(&fetchibuf, nfetchfd, algo, &have_refs, - fetch_all_branches, wanted_branches, wanted_refs, + err = got_privsep_send_fetch_req(&fetchibuf, nfetchfd, expected_algo, + &have_refs, fetch_all_branches, wanted_branches, wanted_refs, list_refs_only, worktree_refname, remote_head, no_head, verbosity); if (err != NULL) goto done; @@ -325,6 +319,26 @@ got_fetch_pack(struct got_object_id **pack_hash, struc &packfile_size_cur, *pack_hash, &fetchibuf); if (err != NULL) goto done; + + /* Hash algorithm must now be known. */ + switch ((*pack_hash)->algo) { + case GOT_HASH_SHA1: + case GOT_HASH_SHA256: + idlen = got_hash_digest_length((*pack_hash)->algo); + break; + default: + err = got_error_fmt(GOT_ERR_OBJECT_FORMAT, + "could not determine object hash algorithm " + "used by server"); + goto done; + } + + if (expected_algo != -1 && + (*pack_hash)->algo != expected_algo) { + err = got_error(GOT_ERR_OBJECT_FORMAT); + goto done; + } + /* Don't report size progress for an empty pack file. */ if (packfile_size_cur <= ssizeof(pack_hdr) + idlen) packfile_size_cur = 0; @@ -361,7 +375,7 @@ got_fetch_pack(struct got_object_id **pack_hash, struc goto done; } err = progress_cb(progress_arg, s, - packfile_size_cur, 0, 0, 0, 0); + packfile_size_cur, *pack_hash, 0, 0, 0, 0); free(s); if (err) break; @@ -377,7 +391,7 @@ got_fetch_pack(struct got_object_id **pack_hash, struc goto done; } else if (!done && packfile_size_cur != packfile_size) { err = progress_cb(progress_arg, NULL, - packfile_size_cur, 0, 0, 0, 0); + packfile_size_cur, *pack_hash, 0, 0, 0, 0); if (err) break; packfile_size = packfile_size_cur; @@ -397,11 +411,6 @@ got_fetch_pack(struct got_object_id **pack_hash, struc goto done; } - if ((*pack_hash)->algo != algo) { - err = got_error(GOT_ERR_OBJECT_FORMAT); - goto done; - } - /* If zero data was fetched without error we are already up-to-date. */ if (packfile_size == 0) { free(*pack_hash); @@ -513,7 +522,7 @@ got_fetch_pack(struct got_object_id **pack_hash, struc goto done; if (nobj_indexed != 0) { err = progress_cb(progress_arg, NULL, - packfile_size, nobj_total, + packfile_size, *pack_hash, nobj_total, nobj_indexed, nobj_loose, nobj_resolved); if (err) break; blob - f63af5151c343acd415e881e2ef503a4471825b0 blob + 7fae1f6aa9fecd6d20e4425f3c5e98240cc8e904 --- lib/gitproto.c +++ lib/gitproto.c @@ -232,7 +232,7 @@ got_gitproto_parse_ref_update_line(char **old_id_str, static const struct got_error * match_capability(char **my_capabilities, const char *capa, - const struct got_capability *mycapa, enum got_hash_algorithm *algo) + const struct got_capability *mycapa) { char *equalsign; char *s; @@ -241,15 +241,6 @@ match_capability(char **my_capabilities, const char *c if (equalsign) { if (strncmp(capa, mycapa->key, equalsign - capa) != 0) return NULL; - - if (strcmp(mycapa->key, "object-format") == 0) { - /* require an exact match on object-format value */ - if (strcmp(equalsign + 1, mycapa->value) != 0) - return NULL; - - if (strcmp(mycapa->value, "sha256") == 0) - *algo = GOT_HASH_SHA256; - } } else { if (strcmp(capa, mycapa->key) != 0) return NULL; @@ -331,9 +322,18 @@ got_gitproto_match_capabilities(char **common_capabili continue; } + if (equalsign != NULL && + strncmp(capa, GOT_CAPA_OBJECT_FORMAT, + equalsign - capa) == 0) { + if (strcmp(equalsign + 1, + GOT_CAPA_OBJECT_FORMAT_SHA256) == 0) + *algo = GOT_HASH_SHA256; + continue; + } + for (i = 0; i < ncapa; i++) { err = match_capability(common_capabilities, - capa, &my_capabilities[i], algo); + capa, &my_capabilities[i]); if (err) break; } blob - 6128c320387d0fc02ee3b1edf54f6d59de13bb86 blob + a1521e5e216928e5fa0a439146c9a9aed8187231 --- lib/got_lib_gitproto.h +++ lib/got_lib_gitproto.h @@ -23,6 +23,9 @@ #define GOT_CAPA_NO_THIN "no-thin" #define GOT_CAPA_OBJECT_FORMAT "object-format" +#define GOT_CAPA_OBJECT_FORMAT_SHA1 "sha1" +#define GOT_CAPA_OBJECT_FORMAT_SHA256 "sha256" + #define GOT_SIDEBAND_PACKFILE_DATA 1 #define GOT_SIDEBAND_PROGRESS_INFO 2 #define GOT_SIDEBAND_ERROR_INFO 3 blob - 6d1e35b9cd6137e782e25a9f4f3a66450cb77a7e blob + 7af185dfaa8a64ffa50fb31b054197de566cdc2c --- lib/got_lib_privsep.h +++ lib/got_lib_privsep.h @@ -120,6 +120,7 @@ enum got_imsg_type { GOT_IMSG_FETCH_SYMREFS, GOT_IMSG_FETCH_REF, GOT_IMSG_FETCH_SERVER_PROGRESS, + GOT_IMSG_FETCH_OBJECT_FORMAT, GOT_IMSG_FETCH_DOWNLOAD_PROGRESS, GOT_IMSG_FETCH_DONE, GOT_IMSG_IDXPACK_REQUEST, blob - 825c284a4e4d1d2d2a5c1a4d62d6ba968820390a blob + acd75ae28f46fb7fc4e959f7e6e146cb84cadfde --- lib/got_lib_repository.h +++ lib/got_lib_repository.h @@ -187,3 +187,4 @@ void got_repo_temp_fds_put(int, struct got_repository const struct got_error *got_repo_find_object_id(struct got_object_id *, struct got_repository *); +void got_repo_free_gitconfig(struct got_repository *); blob - 8f1d693232a9d8b268ee215889b827c3ea255cce blob + 4a1a7a694b548d7263ffc7c0a9a288c158de4ff5 --- lib/privsep.c +++ lib/privsep.c @@ -714,7 +714,8 @@ got_privsep_send_fetch_outfd(struct imsgbuf *ibuf, int const struct got_error * got_privsep_recv_fetch_progress(int *done, struct got_object_id **id, char **refname, struct got_pathlist_head *symrefs, char **server_progress, - off_t *packfile_size, struct got_object_id *pack_hash, struct imsgbuf *ibuf) + off_t *packfile_size, struct got_object_id *pack_hash, + struct imsgbuf *ibuf) { const struct got_error *err = NULL; struct imsg imsg; @@ -730,7 +731,6 @@ got_privsep_recv_fetch_progress(int *done, struct got_ *refname = NULL; *server_progress = NULL; *packfile_size = 0; - memset(pack_hash, 0, sizeof(*pack_hash)); err = got_privsep_recv_imsg(&imsg, ibuf, 0); if (err) @@ -838,6 +838,12 @@ got_privsep_recv_fetch_progress(int *done, struct got_ } memcpy(packfile_size, imsg.data, sizeof(*packfile_size)); break; + case GOT_IMSG_FETCH_OBJECT_FORMAT: + if (imsg_get_data(&imsg, pack_hash, sizeof(*pack_hash)) == -1) { + err = got_error(GOT_ERR_PRIVSEP_MSG); + break; + } + break; case GOT_IMSG_FETCH_DONE: if (imsg_get_data(&imsg, pack_hash, sizeof(*pack_hash)) == -1) { err = got_error(GOT_ERR_PRIVSEP_MSG); blob - 14731673ee55811e65071b506239d1af5c93077a blob + 5d954c5b18dc87b456b4f3fb1e85a55226c82c41 --- lib/repository.c +++ lib/repository.c @@ -844,6 +844,24 @@ done: return err; } +void +got_repo_free_gitconfig(struct got_repository *repo) +{ + size_t i; + + free(repo->gitconfig_author_name); + free(repo->gitconfig_author_email); + for (i = 0; i < repo->ngitconfig_remotes; i++) + got_repo_free_remote_repo_data(&repo->gitconfig_remotes[i]); + free(repo->gitconfig_remotes); + for (i = 0; i < repo->nextensions; i++) { + free(repo->extnames[i]); + free(repo->extvals[i]); + } + free(repo->extnames); + free(repo->extvals); +} + const struct got_error * got_repo_close(struct got_repository *repo) { @@ -903,17 +921,7 @@ got_repo_close(struct got_repository *repo) if (repo->gotconfig) got_gotconfig_free(repo->gotconfig); - free(repo->gitconfig_author_name); - free(repo->gitconfig_author_email); - for (i = 0; i < repo->ngitconfig_remotes; i++) - got_repo_free_remote_repo_data(&repo->gitconfig_remotes[i]); - free(repo->gitconfig_remotes); - for (i = 0; i < repo->nextensions; i++) { - free(repo->extnames[i]); - free(repo->extvals[i]); - } - free(repo->extnames); - free(repo->extvals); + got_repo_free_gitconfig(repo); got_pathlist_free(&repo->packidx_paths, GOT_PATHLIST_FREE_PATH); free(repo); blob - 226d9754daca5178d153ef58e08e9cb96d5b157a blob + 398f19626c435567029d24b7cee6ce595fe25920 --- lib/repository_init.c +++ lib/repository_init.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "got_error.h" #include "got_path.h" @@ -42,6 +43,28 @@ #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif +static const struct got_error * +init_gitconfig(const char *gitconfig_path, enum got_hash_algorithm algo) +{ + const char *gitconfig_sha1 = "[core]\n" + "\trepositoryformatversion = 0\n" + "\tfilemode = true\n" + "\tbare = true\n"; + const char *gitconfig_sha256 = "[core]\n" + "\trepositoryformatversion = 1\n" + "\tfilemode = true\n" + "\tbare = true\n" + "[extensions]\n" + "\tobjectformat = sha256\n"; + const char *gitconfig = gitconfig_sha1; + + if (algo == GOT_HASH_SHA256) + gitconfig = gitconfig_sha256; + + return got_path_create_file(gitconfig_path, gitconfig); +} + + const struct got_error * got_repo_init(const char *repo_path, const char *head_name, enum got_hash_algorithm algo) @@ -55,23 +78,9 @@ got_repo_init(const char *repo_path, const char *head_ const char *description_str = "Unnamed repository; " "edit this file 'description' to name the repository."; const char *headref = "ref: refs/heads/"; - const char *gitconfig_sha1 = "[core]\n" - "\trepositoryformatversion = 0\n" - "\tfilemode = true\n" - "\tbare = true\n"; - const char *gitconfig_sha256 = "[core]\n" - "\trepositoryformatversion = 1\n" - "\tfilemode = true\n" - "\tbare = true\n" - "[extensions]\n" - "\tobjectformat = sha256\n"; - const char *gitconfig = gitconfig_sha1; char *headref_str, *path; size_t i; - if (algo == GOT_HASH_SHA256) - gitconfig = gitconfig_sha256; - if (!got_path_dir_is_empty(repo_path)) return got_error(GOT_ERR_DIR_NOT_EMPTY); @@ -107,10 +116,49 @@ got_repo_init(const char *repo_path, const char *head_ if (asprintf(&path, "%s/%s", repo_path, "config") == -1) return got_error_from_errno("asprintf"); - err = got_path_create_file(path, gitconfig); + + err = init_gitconfig(path, algo); free(path); + return err; +} + +const struct got_error * +got_repo_init_gitconfig(struct got_repository *repo, + enum got_hash_algorithm algo) +{ + const struct got_error *err; + char *path; + + path = got_repo_get_path_gitconfig(repo); + if (path == NULL) + return got_error_from_errno("got_repo_get_path_gitconfig"); + + if (unlink(path) == -1) { + err = got_error_from_errno2("unlink", path); + goto done; + } + + err = init_gitconfig(path, algo); if (err) - return err; + goto done; + + got_repo_free_gitconfig(repo); - return NULL; + repo->algo = algo; + + if (getenv("GOT_IGNORE_GITCONFIG") != NULL) { + err = got_repo_read_gitconfig( + &repo->gitconfig_repository_format_version, + &repo->gitconfig_author_name, &repo->gitconfig_author_email, + &repo->gitconfig_remotes, &repo->ngitconfig_remotes, + &repo->gitconfig_owner, &repo->extnames, &repo->extvals, + &repo->nextensions, path); + if (err) + goto done; + } else if (algo == GOT_HASH_SHA256) + repo->gitconfig_repository_format_version = 1; +done: + free(path); + return err; + } blob - 5b9b1c532c0d687ea6a7630ba195c953fd2add73 blob + 04ac785139414457c03c21d8bbedf5c7df84c027 --- lib/worktree_cvg.c +++ lib/worktree_cvg.c @@ -2596,6 +2596,7 @@ struct got_fetch_progress_arg { static const struct got_error * fetch_progress(void *arg, const char *message, off_t packfile_size, + struct got_object_id *pack_hash, int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved) { struct got_fetch_progress_arg *a = arg; @@ -2805,6 +2806,7 @@ fetch_updated_remote(const char *proto, const char *ho err = got_fetch_pack(&pack_hash, &learned_refs, &symrefs, remote->name, 1, 0, &wanted_branches, &wanted_refs, 0, verbosity, + got_repo_get_object_format(repo), fetchfd, repo, head_refname, NULL, 0, fetch_progress, &fpa); if (err) goto done; blob - ef7f20aedafd9c0d532e4b464943c35f2f88b582 blob + cb16d011377640803090d492c6e35ff56a102a15 --- libexec/got-fetch-pack/got-fetch-pack.c +++ libexec/got-fetch-pack/got-fetch-pack.c @@ -274,6 +274,15 @@ send_fetch_symrefs(struct imsgbuf *ibuf, struct got_pa } static const struct got_error * +send_object_format(struct imsgbuf *ibuf, struct got_object_id *pack_hash) +{ + if (imsg_compose(ibuf, GOT_IMSG_FETCH_OBJECT_FORMAT, 0, 0, -1, + pack_hash, sizeof(*pack_hash)) == -1) + return got_error_from_errno("imsg_compose FETCH_OBJECT_FORMAT"); + return got_privsep_flush_imsg(ibuf); +} + +static const struct got_error * send_fetch_ref(struct imsgbuf *ibuf, struct got_object_id *refid, const char *refname) { @@ -420,13 +429,29 @@ fetch_pack(int fd, int packfd, int expected_algo, getprogname(), server_capabilities); err = got_gitproto_match_capabilities(&my_capabilities, &symrefs, server_capabilities, - got_capabilities, nitems(got_capabilities), &algo); + got_capabilities, nitems(got_capabilities), + &algo); if (err) goto done; if (expected_algo != -1 && algo != expected_algo) { err = got_error(GOT_ERR_OBJECT_FORMAT); goto done; } + + if (algo == GOT_HASH_SHA256) { + char *s; + + if (asprintf(&s, "%s%s%s=%s", my_capabilities, + my_capabilities[0] != '\0' ? " " : "", + GOT_CAPA_OBJECT_FORMAT, + GOT_CAPA_OBJECT_FORMAT_SHA256) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + free(my_capabilities); + my_capabilities = s; + } + if (chattygot) fprintf(stderr, "%s: my capabilities:%s\n", getprogname(), my_capabilities != NULL ? @@ -434,6 +459,12 @@ fetch_pack(int fd, int packfd, int expected_algo, err = send_fetch_symrefs(ibuf, &symrefs); if (err) goto done; + + pack_hash->algo = algo; + err = send_object_format(ibuf, pack_hash); + if (err) + goto done; + is_firstpkt = 0; if (!fetch_all_branches) { RB_FOREACH(pe, got_pathlist_head, &symrefs) {