Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2c26c86

Browse files
committed
Merge pull request libgit2#3499 from ethomson/ref_dir_errmsgs
Improve error messages when dirs prevent ref/reflog creation
2 parents ecdc042 + 0a700ee commit 2c26c86

File tree

5 files changed

+118
-5
lines changed

5 files changed

+118
-5
lines changed

src/filebuf.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,12 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode
357357
memcpy(file->path_lock, file->path_original, path_len);
358358
memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH);
359359

360+
if (git_path_isdir(file->path_original)) {
361+
giterr_set(GITERR_FILESYSTEM, "path '%s' is a directory", file->path_original);
362+
error = GIT_EDIRECTORY;
363+
goto cleanup;
364+
}
365+
360366
/* open the file for locking */
361367
if ((error = lock_file(file, flags, mode)) < 0)
362368
goto cleanup;

src/refdb_fs.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -733,8 +733,11 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
733733

734734
error = git_filebuf_open(file, ref_path.ptr, GIT_FILEBUF_FORCE, GIT_REFS_FILE_MODE);
735735

736+
if (error == GIT_EDIRECTORY)
737+
giterr_set(GITERR_REFERENCE, "cannot lock ref '%s', there are refs beneath that folder", name);
738+
736739
git_buf_free(&ref_path);
737-
return error;
740+
return error;
738741
}
739742

740743
static int loose_commit(git_filebuf *file, const git_reference *ref)
@@ -1785,10 +1788,17 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co
17851788
/* If the new branch matches part of the namespace of a previously deleted branch,
17861789
* there maybe an obsolete/unused directory (or directory hierarchy) in the way.
17871790
*/
1788-
if (git_path_isdir(git_buf_cstr(&path)) &&
1789-
(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) {
1790-
error = -1;
1791-
goto cleanup;
1791+
if (git_path_isdir(git_buf_cstr(&path))) {
1792+
if ((git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0))
1793+
error = -1;
1794+
else if (git_path_isdir(git_buf_cstr(&path))) {
1795+
giterr_set(GITERR_REFERENCE, "cannot create reflog at '%s', there are reflogs beneath that folder",
1796+
ref->name);
1797+
error = GIT_EDIRECTORY;
1798+
}
1799+
1800+
if (error != 0)
1801+
goto cleanup;
17921802
}
17931803

17941804
error = git_futils_writebuffer(&buf, git_buf_cstr(&path), O_WRONLY|O_CREAT|O_APPEND, GIT_REFLOG_FILE_MODE);

tests/core/filebuf.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,12 @@ void test_core_filebuf__hidden_file(void)
230230
git_filebuf_cleanup(&file);
231231
#endif
232232
}
233+
234+
void test_core_filebuf__detects_directory(void)
235+
{
236+
git_filebuf file = GIT_FILEBUF_INIT, fail = GIT_FILEBUF_INIT;
237+
238+
cl_must_pass(p_mkdir("foo", 0777));
239+
cl_git_fail_with(GIT_EDIRECTORY, git_filebuf_open(&file, "foo", 0, 0666));
240+
cl_must_pass(p_rmdir("foo"));
241+
}

tests/refs/create.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,23 @@ void test_refs_create__propagate_eexists(void)
151151
cl_assert(error == GIT_EEXISTS);
152152
}
153153

154+
void test_refs_create__existing_dir_propagates_edirectory(void)
155+
{
156+
git_reference *new_reference, *fail_reference;
157+
git_oid id;
158+
const char *dir_head = "refs/heads/new-dir/new-head",
159+
*fail_head = "refs/heads/new-dir";
160+
161+
git_oid_fromstr(&id, current_master_tip);
162+
163+
/* Create and write the new object id reference */
164+
cl_git_pass(git_reference_create(&new_reference, g_repo, dir_head, &id, 1, NULL));
165+
cl_git_fail_with(GIT_EDIRECTORY,
166+
git_reference_create(&fail_reference, g_repo, fail_head, &id, false, NULL));
167+
168+
git_reference_free(new_reference);
169+
}
170+
154171
static void test_invalid_name(const char *name)
155172
{
156173
git_reference *new_reference;

tests/refs/reflog/reflog.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,77 @@ void test_refs_reflog_reflog__renaming_the_reference_moves_the_reflog(void)
125125
git_buf_free(&master_log_path);
126126
}
127127

128+
void test_refs_reflog_reflog__deleting_the_reference_deletes_the_reflog(void)
129+
{
130+
git_reference *master;
131+
git_buf master_log_path = GIT_BUF_INIT;
132+
133+
git_buf_joinpath(&master_log_path, git_repository_path(g_repo), GIT_REFLOG_DIR);
134+
git_buf_joinpath(&master_log_path, git_buf_cstr(&master_log_path), "refs/heads/master");
135+
136+
cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&master_log_path)));
137+
138+
cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master"));
139+
cl_git_pass(git_reference_delete(master));
140+
git_reference_free(master);
141+
142+
cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&master_log_path)));
143+
git_buf_free(&master_log_path);
144+
}
145+
146+
void test_refs_reflog_reflog__removes_empty_reflog_dir(void)
147+
{
148+
git_reference *ref;
149+
git_buf log_path = GIT_BUF_INIT;
150+
git_oid id;
151+
152+
/* Create a new branch pointing at the HEAD */
153+
git_oid_fromstr(&id, current_master_tip);
154+
cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir/new-head", &id, 0, NULL));
155+
156+
git_buf_joinpath(&log_path, git_repository_path(g_repo), GIT_REFLOG_DIR);
157+
git_buf_joinpath(&log_path, git_buf_cstr(&log_path), "refs/heads/new-dir/new-head");
158+
159+
cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&log_path)));
160+
161+
cl_git_pass(git_reference_delete(ref));
162+
git_reference_free(ref);
163+
164+
/* new ref creation should succeed since new-dir is empty */
165+
git_oid_fromstr(&id, current_master_tip);
166+
cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir", &id, 0, NULL));
167+
git_reference_free(ref);
168+
169+
git_buf_free(&log_path);
170+
}
171+
172+
void test_refs_reflog_reflog__fails_gracefully_on_nonempty_reflog_dir(void)
173+
{
174+
git_reference *ref;
175+
git_buf log_path = GIT_BUF_INIT;
176+
git_oid id;
177+
178+
/* Create a new branch pointing at the HEAD */
179+
git_oid_fromstr(&id, current_master_tip);
180+
cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir/new-head", &id, 0, NULL));
181+
git_reference_free(ref);
182+
183+
git_buf_joinpath(&log_path, git_repository_path(g_repo), GIT_REFLOG_DIR);
184+
git_buf_joinpath(&log_path, git_buf_cstr(&log_path), "refs/heads/new-dir/new-head");
185+
186+
cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&log_path)));
187+
188+
/* delete the ref manually, leave the reflog */
189+
cl_must_pass(p_unlink("testrepo.git/refs/heads/new-dir/new-head"));
190+
191+
/* new ref creation should fail since new-dir contains reflogs still */
192+
git_oid_fromstr(&id, current_master_tip);
193+
cl_git_fail_with(GIT_EDIRECTORY, git_reference_create(&ref, g_repo, "refs/heads/new-dir", &id, 0, NULL));
194+
git_reference_free(ref);
195+
196+
git_buf_free(&log_path);
197+
}
198+
128199
static void assert_has_reflog(bool expected_result, const char *name)
129200
{
130201
cl_assert_equal_i(expected_result, git_reference_has_log(g_repo, name));

0 commit comments

Comments
 (0)