commit a5a5a156a91a17c59934179af8eca099a95b6c2d from: Omar Polo date: Tue Jul 16 12:24:34 2024 UTC load: support bundle v3 The counterpart of generating v3 bundles is to load them. commit - 5f3e316cffd649c7f4164a0c825f4847082a2875 commit + a5a5a156a91a17c59934179af8eca099a95b6c2d blob - 8b52a98aa8b52fe2d3775b7f19516cb967ebdec3 blob + cc02089bfcb70faf1775da8b8a38eb7bfd903018 --- include/got_error.h +++ include/got_error.h @@ -187,6 +187,7 @@ #define GOT_ERR_MERGE_COMMIT_OUT_OF_DATE 170 #define GOT_ERR_BUNDLE_FORMAT 171 #define GOT_ERR_BAD_KEYWORD 172 +#define GOT_ERR_UNKNOWN_CAPA 173 struct got_error { int code; blob - 2897f7222b41cd87986de117e09ca594c4bef16f blob + 8872bef06f42c654a7f90d728cc11aadb624cf2e --- lib/error.c +++ lib/error.c @@ -237,7 +237,8 @@ static const struct got_error got_errors[] = { "the work tree is no longer up-to-date; merge must be aborted " "and retried" }, { GOT_ERR_BUNDLE_FORMAT, "unknown git bundle version" }, - { GOT_ERR_BAD_KEYWORD, "invalid commit keyword" } + { GOT_ERR_BAD_KEYWORD, "invalid commit keyword" }, + { GOT_ERR_UNKNOWN_CAPA, "unknown capability" }, }; static struct got_custom_error { blob - 410b0e9b2cbce22df12461bda7f7e9b4cdff10aa blob + cbb7371e15508f1be9b366e0a087a88cf080a64a --- lib/load.c +++ lib/load.c @@ -53,6 +53,7 @@ #include "got_lib_privsep.h" #define GIT_BUNDLE_SIGNATURE_V2 "# v2 git bundle\n" +#define GIT_BUNDLE_SIGNATURE_V3 "# v3 git bundle\n" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) @@ -231,24 +232,75 @@ got_repo_load(FILE *in, struct got_pathlist_head *refs int imsg_idxfds[2] = {-1, -1}; int ch, done, nobj, idxstatus; pid_t idxpid; - enum got_hash_algorithm algo; + enum got_hash_algorithm repo_algo, bundle_algo; got_ratelimit_init(&rl, 0, 500); - algo = got_repo_get_object_format(repo); - digest_len = got_hash_digest_length(algo); + repo_algo = got_repo_get_object_format(repo); + digest_len = got_hash_digest_length(repo_algo); repo_path = got_repo_get_path_git_dir(repo); + /* bundles will use v3 and a capability to advertise sha256 */ + bundle_algo = GOT_HASH_SHA1; + linelen = getline(&line, &linesize, in); if (linelen == -1) { err = got_ferror(in, GOT_ERR_IO); goto done; } - if (strcmp(line, GIT_BUNDLE_SIGNATURE_V2) != 0) { + if (strcmp(line, GIT_BUNDLE_SIGNATURE_V2) != 0 && + strcmp(line, GIT_BUNDLE_SIGNATURE_V3) != 0) { err = got_error(GOT_ERR_BUNDLE_FORMAT); + goto done; + } + + /* Parse the capabilities */ + for (;;) { + char *key, *val; + + ch = fgetc(in); + if (ch != '@') { + if (ch != EOF) + ungetc(ch, in); + break; + } + + linelen = getline(&line, &linesize, in); + if (linelen == -1) { + err = got_ferror(in, GOT_ERR_IO); + goto done; + } + + if (line[linelen - 1] == '\n') + line[linelen - 1] = '\0'; + + key = line; + val = strchr(key, '='); + if (val == NULL) { + err = got_error_path(key, GOT_ERR_UNKNOWN_CAPA); + goto done; + } + *val++ = '\0'; + if (!strcmp(key, "object-format")) { + if (!strcmp(val, "sha1")) { + bundle_algo = GOT_HASH_SHA1; + continue; + } + if (!strcmp(val, "sha256")) { + bundle_algo = GOT_HASH_SHA256; + continue; + } + } + err = got_error_path(key, GOT_ERR_UNKNOWN_CAPA); goto done; } + if (bundle_algo != repo_algo) { + fprintf(stderr, "%d vs %d\n", bundle_algo, repo_algo); + err = got_error(GOT_ERR_OBJECT_FORMAT); + goto done; + } + /* Parse the prerequisite */ for (;;) { ch = fgetc(in); @@ -267,7 +319,7 @@ got_repo_load(FILE *in, struct got_pathlist_head *refs if (line[linelen - 1] == '\n') line[linelen - 1] = '\0'; - if (!got_parse_object_id(&id, line, algo)) { + if (!got_parse_object_id(&id, line, repo_algo)) { err = got_error_path(line, GOT_ERR_BAD_OBJ_ID_STR); goto done; } @@ -312,7 +364,7 @@ got_repo_load(FILE *in, struct got_pathlist_head *refs goto done; } - if (!got_parse_object_id(id, line, algo)) { + if (!got_parse_object_id(id, line, repo_algo)) { free(id); err = got_error(GOT_ERR_BAD_OBJ_ID_STR); goto done; @@ -344,7 +396,7 @@ got_repo_load(FILE *in, struct got_pathlist_head *refs if (err) goto done; - err = copypack(in, packfd, &packsiz, &id, algo, &rl, + err = copypack(in, packfd, &packsiz, &id, repo_algo, &rl, progress_cb, progress_arg, cancel_cb, cancel_arg); if (err) goto done;