Commit 3d2768747548ec24b58ebdaa012a6b757e65f5a0

Carlos Martín Nieto 2013-08-19T10:30:44

index: report when it's locked Report the index being locked with its own error code in order to be able to differentiate, as a locked index is typically the result of a crashed process or concurrent access, both of which often require user intervention to fix.

diff --git a/include/git2/errors.h b/include/git2/errors.h
index 2032a43..0f0bddf 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 246ae34..714a323 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 3a5a530..76119e0 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 5f53f1e..17e4390 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 1bc5e6a..9090d4d 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);
+}