Skip to content

Commit dc27772

Browse files
authored
Merge pull request libgit2#4378 from cjhoward92/fix/submodule-add-check-index
submodule: check index for path and prefix before adding submodule
2 parents b3c3415 + 69a282d commit dc27772

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

src/submodule.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,51 @@ static int find_by_path(const git_config_entry *entry, void *payload)
149149
return 0;
150150
}
151151

152+
/*
153+
* Checks to see if the submodule shares its name with a file or directory that
154+
* already exists on the index. If so, the submodule cannot be added.
155+
*/
156+
static int is_path_occupied(bool *occupied, git_repository *repo, const char *path)
157+
{
158+
int error = 0;
159+
git_index *index;
160+
git_buf dir = GIT_BUF_INIT;
161+
*occupied = false;
162+
163+
if ((error = git_repository_index__weakptr(&index, repo)) < 0)
164+
goto out;
165+
166+
if ((error = git_index_find(NULL, index, path)) != GIT_ENOTFOUND) {
167+
if (!error) {
168+
giterr_set(GITERR_SUBMODULE,
169+
"File '%s' already exists in the index", path);
170+
*occupied = true;
171+
}
172+
goto out;
173+
}
174+
175+
if ((error = git_buf_sets(&dir, path)) < 0)
176+
goto out;
177+
178+
if ((error = git_path_to_dir(&dir)) < 0)
179+
goto out;
180+
181+
if ((error = git_index_find_prefix(NULL, index, dir.ptr)) != GIT_ENOTFOUND) {
182+
if (!error) {
183+
giterr_set(GITERR_SUBMODULE,
184+
"Directory '%s' already exists in the index", path);
185+
*occupied = true;
186+
}
187+
goto out;
188+
}
189+
190+
error = 0;
191+
192+
out:
193+
git_buf_free(&dir);
194+
return error;
195+
}
196+
152197
/**
153198
* Release the name map returned by 'load_submodule_names'.
154199
*/
@@ -664,6 +709,7 @@ int git_submodule_add_setup(
664709
git_submodule *sm = NULL;
665710
git_buf name = GIT_BUF_INIT, real_url = GIT_BUF_INIT;
666711
git_repository *subrepo = NULL;
712+
bool path_occupied;
667713

668714
assert(repo && url && path);
669715

@@ -688,6 +734,14 @@ int git_submodule_add_setup(
688734
goto cleanup;
689735
}
690736

737+
if ((error = is_path_occupied(&path_occupied, repo, path)) < 0)
738+
goto cleanup;
739+
740+
if (path_occupied) {
741+
error = GIT_EEXISTS;
742+
goto cleanup;
743+
}
744+
691745
/* update .gitmodules */
692746

693747
if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) {

tests/submodule/add.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "repository.h"
88

99
static git_repository *g_repo = NULL;
10+
static const char *valid_blob_id = "fa49b077972391ad58037050f2a75f74e3671e92";
1011

1112
void test_submodule_add__cleanup(void)
1213
{
@@ -128,3 +129,57 @@ void test_submodule_add__url_relative_to_workdir(void)
128129

129130
assert_submodule_url("TestGitRepository", git_repository_workdir(g_repo));
130131
}
132+
133+
static void test_add_entry(
134+
git_index *index,
135+
const char *idstr,
136+
const char *path,
137+
git_filemode_t mode)
138+
{
139+
git_index_entry entry = {{0}};
140+
141+
cl_git_pass(git_oid_fromstr(&entry.id, idstr));
142+
143+
entry.path = path;
144+
entry.mode = mode;
145+
146+
cl_git_pass(git_index_add(index, &entry));
147+
}
148+
149+
void test_submodule_add__path_exists_in_index(void)
150+
{
151+
git_index *index;
152+
git_submodule *sm;
153+
git_buf filename = GIT_BUF_INIT;
154+
155+
g_repo = cl_git_sandbox_init("testrepo");
156+
157+
cl_git_pass(git_buf_joinpath(&filename, "subdirectory", "test.txt"));
158+
159+
cl_git_pass(git_repository_index__weakptr(&index, g_repo));
160+
161+
test_add_entry(index, valid_blob_id, filename.ptr, GIT_FILEMODE_BLOB);
162+
163+
cl_git_fail_with(git_submodule_add_setup(&sm, g_repo, "./", "subdirectory", 1), GIT_EEXISTS);
164+
165+
git_submodule_free(sm);
166+
git_buf_free(&filename);
167+
}
168+
169+
void test_submodule_add__file_exists_in_index(void)
170+
{
171+
git_index *index;
172+
git_submodule *sm;
173+
git_buf name = GIT_BUF_INIT;
174+
175+
g_repo = cl_git_sandbox_init("testrepo");
176+
177+
cl_git_pass(git_repository_index__weakptr(&index, g_repo));
178+
179+
test_add_entry(index, valid_blob_id, "subdirectory", GIT_FILEMODE_BLOB);
180+
181+
cl_git_fail_with(git_submodule_add_setup(&sm, g_repo, "./", "subdirectory", 1), GIT_EEXISTS);
182+
183+
git_submodule_free(sm);
184+
git_buf_free(&name);
185+
}

0 commit comments

Comments
 (0)