summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrian m. carlson <sandals@crustytoothpaste.net>2020-02-07 00:33:52 +0000
committerbrian m. carlson <sandals@crustytoothpaste.net>2020-02-11 00:41:31 +0000
commit06f0230073e0159933aa19d97fce0cbe3b9a3231 (patch)
tree9977ad86fa05688aec4de9f6de675a0494352f1c
parentee3307a183e39d602b25fa94831c6fc09e7c1b61 (diff)
downloadlibgit2-06f0230073e0159933aa19d97fce0cbe3b9a3231.tar.gz
repository: handle format v1
Git has supported repository format version 1 for some time. This format is just like version 0, but it supports extensions. Implementations must reject extensions that they don't support. Add support for this format version and reject any extensions but extensions.noop, which is the only extension we currently support. While we're at it, also clean up an error message.
-rw-r--r--src/repository.c47
-rw-r--r--tests/repo/open.c46
2 files changed, 84 insertions, 9 deletions
diff --git a/src/repository.c b/src/repository.c
index 2469e13e6..721ce5e90 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -62,7 +62,8 @@ static const struct {
{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "worktrees", true }
};
-static int check_repositoryformatversion(git_config *config);
+static int check_repositoryformatversion(int *version, git_config *config);
+static int check_extensions(git_config *config, int version);
#define GIT_COMMONDIR_FILE "commondir"
#define GIT_GITDIR_FILE "gitdir"
@@ -72,6 +73,7 @@ static int check_repositoryformatversion(git_config *config);
#define GIT_BRANCH_MASTER "master"
#define GIT_REPO_VERSION 0
+#define GIT_REPO_MAX_VERSION 1
git_buf git_repository__reserved_names_win32[] = {
{ DOT_GIT, 0, CONST_STRLEN(DOT_GIT) },
@@ -804,6 +806,7 @@ int git_repository_open_ext(
gitlink = GIT_BUF_INIT, commondir = GIT_BUF_INIT;
git_repository *repo = NULL;
git_config *config = NULL;
+ int version = 0;
if (flags & GIT_REPOSITORY_OPEN_FROM_ENV)
return _git_repository_open_ext_from_env(repo_ptr, start_path);
@@ -845,7 +848,10 @@ int git_repository_open_ext(
if (error < 0 && error != GIT_ENOTFOUND)
goto cleanup;
- if (config && (error = check_repositoryformatversion(config)) < 0)
+ if (config && (error = check_repositoryformatversion(&version, config)) < 0)
+ goto cleanup;
+
+ if ((error = check_extensions(config, version) < 0))
goto cleanup;
if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0)
@@ -1341,11 +1347,11 @@ bool git_repository__reserved_names(
}
#endif
-static int check_repositoryformatversion(git_config *config)
+static int check_repositoryformatversion(int *version, git_config *config)
{
- int version, error;
+ int error;
- error = git_config_get_int32(&version, config, "core.repositoryformatversion");
+ error = git_config_get_int32(version, config, "core.repositoryformatversion");
/* git ignores this if the config variable isn't there */
if (error == GIT_ENOTFOUND)
return 0;
@@ -1353,16 +1359,35 @@ static int check_repositoryformatversion(git_config *config)
if (error < 0)
return -1;
- if (GIT_REPO_VERSION < version) {
+ if (GIT_REPO_MAX_VERSION < *version) {
git_error_set(GIT_ERROR_REPOSITORY,
- "unsupported repository version %d. Only versions up to %d are supported.",
- version, GIT_REPO_VERSION);
+ "unsupported repository version %d; only versions up to %d are supported",
+ *version, GIT_REPO_MAX_VERSION);
return -1;
}
return 0;
}
+static int check_valid_extension(const git_config_entry *entry, void *payload)
+{
+ GIT_UNUSED(payload);
+
+ if (!strcmp(entry->name, "extensions.noop"))
+ return 0;
+
+ git_error_set(GIT_ERROR_REPOSITORY, "unsupported extension name %s", entry->name);
+ return -1;
+}
+
+static int check_extensions(git_config *config, int version)
+{
+ if (version < 1)
+ return 0;
+
+ return git_config_foreach_match(config, "^extensions\\.", check_valid_extension, NULL);
+}
+
int git_repository_create_head(const char *git_dir, const char *ref_name)
{
git_buf ref_path = GIT_BUF_INIT;
@@ -1574,11 +1599,15 @@ static int repo_init_config(
git_config *config = NULL;
bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
+ int version = 0;
if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0)
goto cleanup;
- if (is_reinit && (error = check_repositoryformatversion(config)) < 0)
+ if (is_reinit && (error = check_repositoryformatversion(&version, config)) < 0)
+ goto cleanup;
+
+ if ((error = check_extensions(config, version) < 0))
goto cleanup;
#define SET_REPO_CONFIG(TYPE, NAME, VAL) do { \
diff --git a/tests/repo/open.c b/tests/repo/open.c
index 448ccdc87..0f4ecf5eb 100644
--- a/tests/repo/open.c
+++ b/tests/repo/open.c
@@ -35,7 +35,53 @@ void test_repo_open__format_version_1(void)
git_config_free(config);
git_repository_free(repo);
+
+ git_repository_open(&repo, "empty_bare.git");
+ cl_assert(git_repository_path(repo) != NULL);
+ cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0);
+ git_repository_free(repo);
+}
+
+void test_repo_open__format_version_1_with_valid_extension(void)
+{
+ git_repository *repo;
+ git_config *config;
+
+ repo = cl_git_sandbox_init("empty_bare.git");
+
+ cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
+ cl_git_pass(git_repository_config(&config, repo));
+
+ cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 1));
+ cl_git_pass(git_config_set_int32(config, "extensions.noop", 1));
+
+ git_config_free(config);
+ git_repository_free(repo);
+
+ git_repository_open(&repo, "empty_bare.git");
+ cl_assert(git_repository_path(repo) != NULL);
+ cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0);
+ git_repository_free(repo);
+}
+
+void test_repo_open__format_version_1_with_invalid_extension(void)
+{
+ git_repository *repo;
+ git_config *config;
+
+ repo = cl_git_sandbox_init("empty_bare.git");
+
+ cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
+ cl_git_pass(git_repository_config(&config, repo));
+
+ cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 1));
+ cl_git_pass(git_config_set_int32(config, "extensions.invalid", 1));
+
+ git_config_free(config);
+ git_repository_free(repo);
+
cl_git_fail(git_repository_open(&repo, "empty_bare.git"));
+ git_repository_free(repo);
}
void test_repo_open__standard_empty_repo_through_gitdir(void)