Commit Diff


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;