Commit 3eba9181cf74693d5906c799e08aba15b5745355

Edward Thomson 2022-01-26T13:02:49

odb: add git_odb_options Users will need to be able to specify the object id type for the given object database; add a new `git_odb_options` with that option.

diff --git a/fuzzers/packfile_fuzzer.c b/fuzzers/packfile_fuzzer.c
index 3d6d9a3..5e9b9cd 100644
--- a/fuzzers/packfile_fuzzer.c
+++ b/fuzzers/packfile_fuzzer.c
@@ -36,7 +36,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv)
 		fprintf(stderr, "Failed to limit maximum pack object count\n");
 		abort();
 	}
-	if (git_odb_new(&odb) < 0) {
+	if (git_odb_new(&odb, NULL) < 0) {
 		fprintf(stderr, "Failed to create the odb\n");
 		abort();
 	}
diff --git a/include/git2/odb.h b/include/git2/odb.h
index 61e04d1..12b5fc7 100644
--- a/include/git2/odb.h
+++ b/include/git2/odb.h
@@ -38,6 +38,19 @@ typedef enum {
  */
 typedef int GIT_CALLBACK(git_odb_foreach_cb)(const git_oid *id, void *payload);
 
+/** Options for configuring a loose object backend. */
+typedef struct {
+	unsigned int version; /**< version for the struct */
+} git_odb_options;
+
+/* The current version of the diff options structure */
+#define GIT_ODB_OPTIONS_VERSION 1
+
+/* Stack initializer for odb options.  Alternatively use
+ * `git_odb_options_init` programmatic initialization.
+ */
+#define GIT_ODB_OPTIONS_INIT { GIT_ODB_OPTIONS_VERSION }
+
 /**
  * Create a new object database with no backends.
  *
@@ -46,9 +59,10 @@ typedef int GIT_CALLBACK(git_odb_foreach_cb)(const git_oid *id, void *payload);
  *
  * @param out location to store the database pointer, if opened.
  *			Set to NULL if the open failed.
+ * @param opts the options for this object database or NULL for defaults
  * @return 0 or an error code
  */
-GIT_EXTERN(int) git_odb_new(git_odb **out);
+GIT_EXTERN(int) git_odb_new(git_odb **out, const git_odb_options *opts);
 
 /**
  * Create a new object database and automatically add
@@ -64,9 +78,13 @@ GIT_EXTERN(int) git_odb_new(git_odb **out);
  * @param out location to store the database pointer, if opened.
  *			Set to NULL if the open failed.
  * @param objects_dir path of the backends' "objects" directory.
+ * @param opts the options for this object database or NULL for defaults
  * @return 0 or an error code
  */
-GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir);
+GIT_EXTERN(int) git_odb_open(
+	git_odb **out,
+	const char *objects_dir,
+	const git_odb_options *opts);
 
 /**
  * Add an on-disk alternate to an existing Object DB.
diff --git a/src/libgit2/odb.c b/src/libgit2/odb.c
index 787189b..f979859 100644
--- a/src/libgit2/odb.c
+++ b/src/libgit2/odb.c
@@ -475,11 +475,25 @@ static int backend_sort_cmp(const void *a, const void *b)
 	return (backend_b->priority - backend_a->priority);
 }
 
-int git_odb_new(git_odb **out)
+static void normalize_options(
+	git_odb_options *opts,
+	const git_odb_options *given_opts)
+{
+	git_odb_options init = GIT_ODB_OPTIONS_INIT;
+
+	if (given_opts)
+		memcpy(opts, given_opts, sizeof(git_odb_options));
+	else
+		memcpy(opts, &init, sizeof(git_odb_options));
+}
+
+int git_odb_new(git_odb **out, const git_odb_options *opts)
 {
 	git_odb *db = git__calloc(1, sizeof(*db));
 	GIT_ERROR_CHECK_ALLOC(db);
 
+	normalize_options(&db->options, opts);
+
 	if (git_mutex_init(&db->lock) < 0) {
 		git__free(db);
 		return -1;
@@ -740,7 +754,10 @@ int git_odb_set_commit_graph(git_odb *odb, git_commit_graph *cgraph)
 	return error;
 }
 
-int git_odb_open(git_odb **out, const char *objects_dir)
+int git_odb_open(
+	git_odb **out,
+	const char *objects_dir,
+	const git_odb_options *opts)
 {
 	git_odb *db;
 
@@ -749,7 +766,7 @@ int git_odb_open(git_odb **out, const char *objects_dir)
 
 	*out = NULL;
 
-	if (git_odb_new(&db) < 0)
+	if (git_odb_new(&db, opts) < 0)
 		return -1;
 
 	if (git_odb__add_default_backends(db, objects_dir, 0, 0) < 0) {
diff --git a/src/libgit2/odb.h b/src/libgit2/odb.h
index c85fa67..6baa45b 100644
--- a/src/libgit2/odb.h
+++ b/src/libgit2/odb.h
@@ -46,6 +46,7 @@ struct git_odb_object {
 struct git_odb {
 	git_refcount rc;
 	git_mutex lock;  /* protects backends */
+	git_odb_options options;
 	git_vector backends;
 	git_cache own_cache;
 	git_commit_graph *cgraph;
diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c
index adff425..f831355 100644
--- a/src/libgit2/repository.c
+++ b/src/libgit2/repository.c
@@ -790,7 +790,7 @@ static int _git_repository_open_ext_from_env(
 	else if (error < 0)
 		goto error;
 	else {
-		error = git_odb_open(&odb, git_str_cstr(&object_dir_buf));
+		error = git_odb_open(&odb, git_str_cstr(&object_dir_buf), NULL);
 		if (error < 0)
 			goto error;
 	}
@@ -1217,7 +1217,7 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
 
 		if ((error = git_repository__item_path(&odb_path, repo,
 				GIT_REPOSITORY_ITEM_OBJECTS)) < 0 ||
-			(error = git_odb_new(&odb)) < 0)
+			(error = git_odb_new(&odb, NULL)) < 0)
 			return error;
 
 		GIT_REFCOUNT_OWN(odb, repo);
diff --git a/tests/libgit2/object/raw/write.c b/tests/libgit2/object/raw/write.c
index 4da2264..17e3e21 100644
--- a/tests/libgit2/object/raw/write.c
+++ b/tests/libgit2/object/raw/write.c
@@ -66,7 +66,7 @@ void test_body(object_data *d, git_rawobj *o)
    git_rawobj tmp;
 
    make_odb_dir();
-   cl_git_pass(git_odb_open(&db, odb_dir));
+   cl_git_pass(git_odb_open(&db, odb_dir, NULL));
    cl_git_pass(git_oid_fromstr(&id1, d->id, GIT_OID_SHA1));
 
    streaming_write(&id2, db, o);
diff --git a/tests/libgit2/odb/backend/mempack.c b/tests/libgit2/odb/backend/mempack.c
index 7e0da3f..e86c9b7 100644
--- a/tests/libgit2/odb/backend/mempack.c
+++ b/tests/libgit2/odb/backend/mempack.c
@@ -13,7 +13,7 @@ void test_odb_backend_mempack__initialize(void)
 	git_odb_backend *backend;
 
 	cl_git_pass(git_mempack_new(&backend));
-	cl_git_pass(git_odb_new(&_odb));
+	cl_git_pass(git_odb_new(&_odb, NULL));
 	cl_git_pass(git_odb_add_backend(_odb, backend, 10));
 	cl_git_pass(git_repository_wrap_odb(&_repo, _odb));
 }
diff --git a/tests/libgit2/odb/backend/nobackend.c b/tests/libgit2/odb/backend/nobackend.c
index 7484d42..2812a5a 100644
--- a/tests/libgit2/odb/backend/nobackend.c
+++ b/tests/libgit2/odb/backend/nobackend.c
@@ -12,7 +12,7 @@ void test_odb_backend_nobackend__initialize(void)
 
 	cl_git_pass(git_repository_new(&_repo));
 	cl_git_pass(git_config_new(&config));
-	cl_git_pass(git_odb_new(&odb));
+	cl_git_pass(git_odb_new(&odb, NULL));
 	cl_git_pass(git_refdb_new(&refdb, _repo));
 
 	git_repository_set_config(_repo, config);
diff --git a/tests/libgit2/odb/foreach.c b/tests/libgit2/odb/foreach.c
index c2a4483..98b5d80 100644
--- a/tests/libgit2/odb/foreach.c
+++ b/tests/libgit2/odb/foreach.c
@@ -51,7 +51,7 @@ void test_odb_foreach__one_pack(void)
 	git_odb_backend *backend = NULL;
 	int nobj = 0;
 
-	cl_git_pass(git_odb_new(&_odb));
+	cl_git_pass(git_odb_new(&_odb, NULL));
 	cl_git_pass(git_odb_backend_one_pack(&backend, cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx")));
 	cl_git_pass(git_odb_add_backend(_odb, backend, 1));
 	_repo = NULL;
diff --git a/tests/libgit2/odb/loose.c b/tests/libgit2/odb/loose.c
index 7fea9a6..5da1f09 100644
--- a/tests/libgit2/odb/loose.c
+++ b/tests/libgit2/odb/loose.c
@@ -41,7 +41,7 @@ static void test_read_object(object_data *data)
 
     write_object_files(data);
 
-    cl_git_pass(git_odb_open(&odb, "test-objects"));
+    cl_git_pass(git_odb_open(&odb, "test-objects", NULL));
     cl_git_pass(git_oid_fromstr(&id, data->id, GIT_OID_SHA1));
     cl_git_pass(git_odb_read(&obj, odb, &id));
 
@@ -64,7 +64,7 @@ static void test_read_header(object_data *data)
 
 	write_object_files(data);
 
-	cl_git_pass(git_odb_open(&odb, "test-objects"));
+	cl_git_pass(git_odb_open(&odb, "test-objects", NULL));
 	cl_git_pass(git_oid_fromstr(&id, data->id, GIT_OID_SHA1));
 	cl_git_pass(git_odb_read_header(&len, &type, odb, &id));
 
@@ -86,7 +86,7 @@ static void test_readstream_object(object_data *data, size_t blocksize)
 
 	write_object_files(data);
 
-	cl_git_pass(git_odb_open(&odb, "test-objects"));
+	cl_git_pass(git_odb_open(&odb, "test-objects", NULL));
 	cl_git_pass(git_oid_fromstr(&id, data->id, GIT_OID_SHA1));
 	cl_git_pass(git_odb_open_rstream(&stream, &tmp.len, &tmp.type, odb, &id));
 
@@ -130,7 +130,7 @@ void test_odb_loose__exists(void)
 	git_odb *odb;
 
 	write_object_files(&one);
-	cl_git_pass(git_odb_open(&odb, "test-objects"));
+	cl_git_pass(git_odb_open(&odb, "test-objects", NULL));
 
 	cl_git_pass(git_oid_fromstr(&id, one.id, GIT_OID_SHA1));
 	cl_assert(git_odb_exists(odb, &id));
@@ -209,7 +209,7 @@ static void test_write_object_permission(
 	mask = p_umask(0);
 	p_umask(mask);
 
-	cl_git_pass(git_odb_new(&odb));
+	cl_git_pass(git_odb_new(&odb, NULL));
 	cl_git_pass(git_odb_backend_loose(&backend, "test-objects", -1, 0, dir_mode, file_mode));
 	cl_git_pass(git_odb_add_backend(odb, backend, 1));
 	cl_git_pass(git_odb_write(&oid, odb, "Test data\n", 10, GIT_OBJECT_BLOB));
@@ -244,7 +244,7 @@ static void write_object_to_loose_odb(int fsync)
 	git_odb_backend *backend;
 	git_oid oid;
 
-	cl_git_pass(git_odb_new(&odb));
+	cl_git_pass(git_odb_new(&odb, NULL));
 	cl_git_pass(git_odb_backend_loose(&backend, "test-objects", -1, fsync, 0777, 0666));
 	cl_git_pass(git_odb_add_backend(odb, backend, 1));
 	cl_git_pass(git_odb_write(&oid, odb, "Test data\n", 10, GIT_OBJECT_BLOB));
diff --git a/tests/libgit2/odb/mixed.c b/tests/libgit2/odb/mixed.c
index e9869fe..a482383 100644
--- a/tests/libgit2/odb/mixed.c
+++ b/tests/libgit2/odb/mixed.c
@@ -5,7 +5,7 @@ static git_odb *_odb;
 
 void test_odb_mixed__initialize(void)
 {
-	cl_git_pass(git_odb_open(&_odb, cl_fixture("duplicate.git/objects")));
+	cl_git_pass(git_odb_open(&_odb, cl_fixture("duplicate.git/objects"), NULL));
 }
 
 void test_odb_mixed__cleanup(void)
diff --git a/tests/libgit2/odb/packed.c b/tests/libgit2/odb/packed.c
index 2f5a8a2..469489a 100644
--- a/tests/libgit2/odb/packed.c
+++ b/tests/libgit2/odb/packed.c
@@ -6,7 +6,7 @@ static git_odb *_odb;
 
 void test_odb_packed__initialize(void)
 {
-    cl_git_pass(git_odb_open(&_odb, cl_fixture("testrepo.git/objects")));
+    cl_git_pass(git_odb_open(&_odb, cl_fixture("testrepo.git/objects"), NULL));
 }
 
 void test_odb_packed__cleanup(void)
diff --git a/tests/libgit2/odb/packed_one.c b/tests/libgit2/odb/packed_one.c
index a708839..777b54b 100644
--- a/tests/libgit2/odb/packed_one.c
+++ b/tests/libgit2/odb/packed_one.c
@@ -10,7 +10,7 @@ void test_odb_packed_one__initialize(void)
 {
 	git_odb_backend *backend = NULL;
 
-	cl_git_pass(git_odb_new(&_odb));
+	cl_git_pass(git_odb_new(&_odb, NULL));
 	cl_git_pass(git_odb_backend_one_pack(&backend, cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx")));
 	cl_git_pass(git_odb_add_backend(_odb, backend, 1));
 }
diff --git a/tests/libgit2/odb/sorting.c b/tests/libgit2/odb/sorting.c
index e027230..36c4507 100644
--- a/tests/libgit2/odb/sorting.c
+++ b/tests/libgit2/odb/sorting.c
@@ -37,7 +37,7 @@ static git_odb *_odb;
 
 void test_odb_sorting__initialize(void)
 {
-	cl_git_pass(git_odb_new(&_odb));
+	cl_git_pass(git_odb_new(&_odb, NULL));
 }
 
 void test_odb_sorting__cleanup(void)
@@ -84,7 +84,7 @@ void test_odb_sorting__override_default_backend_priority(void)
 	git_odb_backend_pack(&packed, "./testrepo.git/objects");
 	git_odb_backend_loose(&loose, "./testrepo.git/objects", -1, 0, 0, 0);
 
-	cl_git_pass(git_odb_open(&new_odb, cl_fixture("testrepo.git/objects")));
+	cl_git_pass(git_odb_open(&new_odb, cl_fixture("testrepo.git/objects"), NULL));
 	cl_assert_equal_sz(2, git_odb_num_backends(new_odb));
 
 	cl_git_pass(git_odb_get_backend(&backend, new_odb, 0));
diff --git a/tests/libgit2/refs/iterator.c b/tests/libgit2/refs/iterator.c
index a4f9e62..b7454ee 100644
--- a/tests/libgit2/refs/iterator.c
+++ b/tests/libgit2/refs/iterator.c
@@ -126,7 +126,7 @@ void test_refs_iterator__empty(void)
 	git_reference *ref;
 	git_repository *empty;
 
-	cl_git_pass(git_odb_new(&odb));
+	cl_git_pass(git_odb_new(&odb, NULL));
 	cl_git_pass(git_repository_wrap_odb(&empty, odb));
 
 	cl_git_pass(git_reference_iterator_new(&iter, empty));
diff --git a/tests/libgit2/repo/setters.c b/tests/libgit2/repo/setters.c
index 9a965de..469c56a 100644
--- a/tests/libgit2/repo/setters.c
+++ b/tests/libgit2/repo/setters.c
@@ -90,7 +90,7 @@ void test_repo_setters__setting_a_new_odb_on_a_repo_which_already_loaded_one_pro
 {
 	git_odb *new_odb;
 
-	cl_git_pass(git_odb_open(&new_odb, "./testrepo.git/objects"));
+	cl_git_pass(git_odb_open(&new_odb, "./testrepo.git/objects", NULL));
 	cl_assert(((git_refcount *)new_odb)->refcount.val == 1);
 
 	git_repository_set_odb(repo, new_odb);