diff --git a/src/reflog.c b/src/reflog.c index ef0aa7eca..f841b2174 100644 --- a/src/reflog.c +++ b/src/reflog.c @@ -183,6 +183,18 @@ static int retrieve_reflog_path(git_buf *path, git_reference *ref) git_reference_owner(ref)->path_repository, GIT_REFLOG_DIR, ref->name); } +int create_new_reflog_file(const char *filepath) +{ + int fd; + + if ((fd = p_open(filepath, + O_WRONLY | O_CREAT | O_TRUNC, + GIT_REFLOG_FILE_MODE)) < 0) + return -1; + + return p_close(fd); +} + int git_reflog_read(git_reflog **reflog, git_reference *ref) { int error; @@ -204,6 +216,10 @@ int git_reflog_read(git_reflog **reflog, git_reference *ref) if (error < 0 && error != GIT_ENOTFOUND) goto cleanup; + if ((error == GIT_ENOTFOUND) && + ((error = create_new_reflog_file(git_buf_cstr(&log_path))) < 0)) + goto cleanup; + if ((error = reflog_parse(log, git_buf_cstr(&log_file), git_buf_len(&log_file))) < 0) goto cleanup; @@ -237,6 +253,12 @@ int git_reflog_write(git_reflog *reflog) git_repository_path(reflog->owner), GIT_REFLOG_DIR, reflog->ref_name) < 0) return -1; + if (!git_path_isfile(git_buf_cstr(&log_path))) { + giterr_set(GITERR_INVALID, + "Log file for reference '%s' doesn't exist.", reflog->ref_name); + goto cleanup; + } + if ((error = git_filebuf_open(&fbuf, git_buf_cstr(&log_path), 0)) < 0) goto cleanup; diff --git a/tests-clar/refs/reflog/reflog.c b/tests-clar/refs/reflog/reflog.c index ed3b31563..20f08f523 100644 --- a/tests-clar/refs/reflog/reflog.c +++ b/tests-clar/refs/reflog/reflog.c @@ -149,3 +149,24 @@ void test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_re git_reference_free(subtrees); git_buf_free(&subtrees_log_path); } + +void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void) +{ + git_reference *master; + git_buf master_log_path = GIT_BUF_INIT, moved_log_path = GIT_BUF_INIT; + git_reflog *reflog; + + cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master")); + cl_git_pass(git_reflog_read(&reflog, master)); + + cl_git_pass(git_reflog_write(reflog)); + + cl_git_pass(git_reference_rename(master, "refs/moved", 0)); + + cl_git_fail(git_reflog_write(reflog)); + + git_reflog_free(reflog); + git_reference_free(master); + git_buf_free(&moved_log_path); + git_buf_free(&master_log_path); +}