Skip to content

Commit 06f0230

Browse files
committed
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.
1 parent ee3307a commit 06f0230

File tree

2 files changed

+84
-9
lines changed

2 files changed

+84
-9
lines changed

src/repository.c

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ static const struct {
6262
{ GIT_REPOSITORY_ITEM_COMMONDIR, GIT_REPOSITORY_ITEM_GITDIR, "worktrees", true }
6363
};
6464

65-
static int check_repositoryformatversion(git_config *config);
65+
static int check_repositoryformatversion(int *version, git_config *config);
66+
static int check_extensions(git_config *config, int version);
6667

6768
#define GIT_COMMONDIR_FILE "commondir"
6869
#define GIT_GITDIR_FILE "gitdir"
@@ -72,6 +73,7 @@ static int check_repositoryformatversion(git_config *config);
7273
#define GIT_BRANCH_MASTER "master"
7374

7475
#define GIT_REPO_VERSION 0
76+
#define GIT_REPO_MAX_VERSION 1
7577

7678
git_buf git_repository__reserved_names_win32[] = {
7779
{ DOT_GIT, 0, CONST_STRLEN(DOT_GIT) },
@@ -804,6 +806,7 @@ int git_repository_open_ext(
804806
gitlink = GIT_BUF_INIT, commondir = GIT_BUF_INIT;
805807
git_repository *repo = NULL;
806808
git_config *config = NULL;
809+
int version = 0;
807810

808811
if (flags & GIT_REPOSITORY_OPEN_FROM_ENV)
809812
return _git_repository_open_ext_from_env(repo_ptr, start_path);
@@ -845,7 +848,10 @@ int git_repository_open_ext(
845848
if (error < 0 && error != GIT_ENOTFOUND)
846849
goto cleanup;
847850

848-
if (config && (error = check_repositoryformatversion(config)) < 0)
851+
if (config && (error = check_repositoryformatversion(&version, config)) < 0)
852+
goto cleanup;
853+
854+
if ((error = check_extensions(config, version) < 0))
849855
goto cleanup;
850856

851857
if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0)
@@ -1341,28 +1347,47 @@ bool git_repository__reserved_names(
13411347
}
13421348
#endif
13431349

1344-
static int check_repositoryformatversion(git_config *config)
1350+
static int check_repositoryformatversion(int *version, git_config *config)
13451351
{
1346-
int version, error;
1352+
int error;
13471353

1348-
error = git_config_get_int32(&version, config, "core.repositoryformatversion");
1354+
error = git_config_get_int32(version, config, "core.repositoryformatversion");
13491355
/* git ignores this if the config variable isn't there */
13501356
if (error == GIT_ENOTFOUND)
13511357
return 0;
13521358

13531359
if (error < 0)
13541360
return -1;
13551361

1356-
if (GIT_REPO_VERSION < version) {
1362+
if (GIT_REPO_MAX_VERSION < *version) {
13571363
git_error_set(GIT_ERROR_REPOSITORY,
1358-
"unsupported repository version %d. Only versions up to %d are supported.",
1359-
version, GIT_REPO_VERSION);
1364+
"unsupported repository version %d; only versions up to %d are supported",
1365+
*version, GIT_REPO_MAX_VERSION);
13601366
return -1;
13611367
}
13621368

13631369
return 0;
13641370
}
13651371

1372+
static int check_valid_extension(const git_config_entry *entry, void *payload)
1373+
{
1374+
GIT_UNUSED(payload);
1375+
1376+
if (!strcmp(entry->name, "extensions.noop"))
1377+
return 0;
1378+
1379+
git_error_set(GIT_ERROR_REPOSITORY, "unsupported extension name %s", entry->name);
1380+
return -1;
1381+
}
1382+
1383+
static int check_extensions(git_config *config, int version)
1384+
{
1385+
if (version < 1)
1386+
return 0;
1387+
1388+
return git_config_foreach_match(config, "^extensions\\.", check_valid_extension, NULL);
1389+
}
1390+
13661391
int git_repository_create_head(const char *git_dir, const char *ref_name)
13671392
{
13681393
git_buf ref_path = GIT_BUF_INIT;
@@ -1574,11 +1599,15 @@ static int repo_init_config(
15741599
git_config *config = NULL;
15751600
bool is_bare = ((flags & GIT_REPOSITORY_INIT_BARE) != 0);
15761601
bool is_reinit = ((flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0);
1602+
int version = 0;
15771603

15781604
if ((error = repo_local_config(&config, &cfg_path, NULL, repo_dir)) < 0)
15791605
goto cleanup;
15801606

1581-
if (is_reinit && (error = check_repositoryformatversion(config)) < 0)
1607+
if (is_reinit && (error = check_repositoryformatversion(&version, config)) < 0)
1608+
goto cleanup;
1609+
1610+
if ((error = check_extensions(config, version) < 0))
15821611
goto cleanup;
15831612

15841613
#define SET_REPO_CONFIG(TYPE, NAME, VAL) do { \

tests/repo/open.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,53 @@ void test_repo_open__format_version_1(void)
3535

3636
git_config_free(config);
3737
git_repository_free(repo);
38+
39+
git_repository_open(&repo, "empty_bare.git");
40+
cl_assert(git_repository_path(repo) != NULL);
41+
cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0);
42+
git_repository_free(repo);
43+
}
44+
45+
void test_repo_open__format_version_1_with_valid_extension(void)
46+
{
47+
git_repository *repo;
48+
git_config *config;
49+
50+
repo = cl_git_sandbox_init("empty_bare.git");
51+
52+
cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
53+
cl_git_pass(git_repository_config(&config, repo));
54+
55+
cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 1));
56+
cl_git_pass(git_config_set_int32(config, "extensions.noop", 1));
57+
58+
git_config_free(config);
59+
git_repository_free(repo);
60+
61+
git_repository_open(&repo, "empty_bare.git");
62+
cl_assert(git_repository_path(repo) != NULL);
63+
cl_assert(git__suffixcmp(git_repository_path(repo), "/") == 0);
64+
git_repository_free(repo);
65+
}
66+
67+
void test_repo_open__format_version_1_with_invalid_extension(void)
68+
{
69+
git_repository *repo;
70+
git_config *config;
71+
72+
repo = cl_git_sandbox_init("empty_bare.git");
73+
74+
cl_git_pass(git_repository_open(&repo, "empty_bare.git"));
75+
cl_git_pass(git_repository_config(&config, repo));
76+
77+
cl_git_pass(git_config_set_int32(config, "core.repositoryformatversion", 1));
78+
cl_git_pass(git_config_set_int32(config, "extensions.invalid", 1));
79+
80+
git_config_free(config);
81+
git_repository_free(repo);
82+
3883
cl_git_fail(git_repository_open(&repo, "empty_bare.git"));
84+
git_repository_free(repo);
3985
}
4086

4187
void test_repo_open__standard_empty_repo_through_gitdir(void)

0 commit comments

Comments
 (0)