diff --git a/include/git2/errors.h b/include/git2/errors.h index 2032a436a..0f0bddf07 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -32,6 +32,7 @@ typedef enum { GIT_ENONFASTFORWARD = -11, GIT_EINVALIDSPEC = -12, GIT_EMERGECONFLICT = -13, + GIT_ELOCKED = -14, GIT_PASSTHROUGH = -30, GIT_ITEROVER = -31, diff --git a/src/filebuf.c b/src/filebuf.c index 246ae34e7..714a32395 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -53,7 +53,7 @@ static int lock_file(git_filebuf *file, int flags) giterr_clear(); /* actual OS error code just confuses */ giterr_set(GITERR_OS, "Failed to lock file '%s' for writing", file->path_lock); - return -1; + return GIT_ELOCKED; } } @@ -66,7 +66,7 @@ static int lock_file(git_filebuf *file, int flags) } if (file->fd < 0) - return -1; + return file->fd; file->fd_is_open = true; @@ -197,7 +197,7 @@ static int write_deflate(git_filebuf *file, void *source, size_t len) int git_filebuf_open(git_filebuf *file, const char *path, int flags) { - int compression; + int compression, error = -1; size_t path_len; /* opening an already open buffer is a programming error; @@ -282,7 +282,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags) memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH); /* open the file for locking */ - if (lock_file(file, flags) < 0) + if ((error = lock_file(file, flags)) < 0) goto cleanup; } @@ -290,7 +290,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags) cleanup: git_filebuf_cleanup(file); - return -1; + return error; } int git_filebuf_hash(git_oid *oid, git_filebuf *file) diff --git a/src/fileops.c b/src/fileops.c index 3a5a53074..76119e02e 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -70,7 +70,7 @@ int git_futils_creat_locked(const char *path, const mode_t mode) if (fd < 0) { giterr_set(GITERR_OS, "Failed to create locked file '%s'", path); - return -1; + return errno == EEXIST ? GIT_ELOCKED : -1; } return fd; diff --git a/src/index.c b/src/index.c index 5f53f1e2f..17e43903f 100644 --- a/src/index.c +++ b/src/index.c @@ -498,8 +498,12 @@ int git_index_write(git_index *index) git_vector_sort(&index->reuc); if ((error = git_filebuf_open( - &file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < 0) + &file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < 0) { + if (error == GIT_ELOCKED) + giterr_set(GITERR_INDEX, "The index is locked. This might be due to a concurrrent or crashed process"); + return error; + } if ((error = write_index(index, &file)) < 0) { git_filebuf_cleanup(&file); diff --git a/tests-clar/index/tests.c b/tests-clar/index/tests.c index 1bc5e6a07..9090d4d8a 100644 --- a/tests-clar/index/tests.c +++ b/tests-clar/index/tests.c @@ -459,3 +459,28 @@ void test_index_tests__preserves_case(void) git_repository_free(repo); } +void test_index_tests__elocked(void) +{ + git_repository *repo; + git_index *index; + git_filebuf file = GIT_FILEBUF_INIT; + const git_error *err; + int error; + + cl_set_cleanup(&cleanup_myrepo, NULL); + + cl_git_pass(git_repository_init(&repo, "./myrepo", 0)); + cl_git_pass(git_repository_index(&index, repo)); + + /* Lock the index file so we fail to lock it */ + cl_git_pass(git_filebuf_open(&file, index->index_file_path, 0)); + error = git_index_write(index); + cl_assert_equal_i(GIT_ELOCKED, error); + + err = giterr_last(); + cl_assert_equal_i(err->klass, GITERR_INDEX); + + git_filebuf_cleanup(&file); + git_index_free(index); + git_repository_free(repo); +}