From 0a700ee368818da526981b09c1c5bbef8c9b5fb8 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 3 Nov 2015 17:34:54 -0500 Subject: [PATCH] reflog: error when a directory is at reflog path When a non-empty directory exists and prevents the creation of a reflog, provide a more informative error message. --- src/refdb_fs.c | 15 ++++++++--- tests/refs/reflog/reflog.c | 53 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/refdb_fs.c b/src/refdb_fs.c index c550ee92a..85b5034d6 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -1788,10 +1788,17 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co /* If the new branch matches part of the namespace of a previously deleted branch, * there maybe an obsolete/unused directory (or directory hierarchy) in the way. */ - if (git_path_isdir(git_buf_cstr(&path)) && - (git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) { - error = -1; - goto cleanup; + if (git_path_isdir(git_buf_cstr(&path))) { + if ((git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0)) + error = -1; + else if (git_path_isdir(git_buf_cstr(&path))) { + giterr_set(GITERR_REFERENCE, "cannot create reflog at '%s', there are reflogs beneath that folder", + ref->name); + error = GIT_EDIRECTORY; + } + + if (error != 0) + goto cleanup; } error = git_futils_writebuffer(&buf, git_buf_cstr(&path), O_WRONLY|O_CREAT|O_APPEND, GIT_REFLOG_FILE_MODE); diff --git a/tests/refs/reflog/reflog.c b/tests/refs/reflog/reflog.c index ba40c76b8..fdb15502c 100644 --- a/tests/refs/reflog/reflog.c +++ b/tests/refs/reflog/reflog.c @@ -143,6 +143,59 @@ void test_refs_reflog_reflog__deleting_the_reference_deletes_the_reflog(void) git_buf_free(&master_log_path); } +void test_refs_reflog_reflog__removes_empty_reflog_dir(void) +{ + git_reference *ref; + git_buf log_path = GIT_BUF_INIT; + git_oid id; + + /* Create a new branch pointing at the HEAD */ + git_oid_fromstr(&id, current_master_tip); + cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir/new-head", &id, 0, NULL)); + + git_buf_joinpath(&log_path, git_repository_path(g_repo), GIT_REFLOG_DIR); + git_buf_joinpath(&log_path, git_buf_cstr(&log_path), "refs/heads/new-dir/new-head"); + + cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&log_path))); + + cl_git_pass(git_reference_delete(ref)); + git_reference_free(ref); + + /* new ref creation should succeed since new-dir is empty */ + git_oid_fromstr(&id, current_master_tip); + cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir", &id, 0, NULL)); + git_reference_free(ref); + + git_buf_free(&log_path); +} + +void test_refs_reflog_reflog__fails_gracefully_on_nonempty_reflog_dir(void) +{ + git_reference *ref; + git_buf log_path = GIT_BUF_INIT; + git_oid id; + + /* Create a new branch pointing at the HEAD */ + git_oid_fromstr(&id, current_master_tip); + cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/new-dir/new-head", &id, 0, NULL)); + git_reference_free(ref); + + git_buf_joinpath(&log_path, git_repository_path(g_repo), GIT_REFLOG_DIR); + git_buf_joinpath(&log_path, git_buf_cstr(&log_path), "refs/heads/new-dir/new-head"); + + cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&log_path))); + + /* delete the ref manually, leave the reflog */ + cl_must_pass(p_unlink("testrepo.git/refs/heads/new-dir/new-head")); + + /* new ref creation should fail since new-dir contains reflogs still */ + git_oid_fromstr(&id, current_master_tip); + cl_git_fail_with(GIT_EDIRECTORY, git_reference_create(&ref, g_repo, "refs/heads/new-dir", &id, 0, NULL)); + git_reference_free(ref); + + git_buf_free(&log_path); +} + static void assert_has_reflog(bool expected_result, const char *name) { cl_assert_equal_i(expected_result, git_reference_has_log(g_repo, name));