Merge pull request #3349 from libgit2/cmn/for-v23

A second round of 0.23 maint updates
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5c55ddd..4747818 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,7 +12,7 @@
 # > cmake --build . --target install
 
 PROJECT(libgit2 C)
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
 CMAKE_POLICY(SET CMP0015 NEW)
 
 # Add find modules to the path
@@ -412,6 +412,7 @@
 		SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
 	ENDIF ()
 
+	ADD_C_FLAG_IF_SUPPORTED(-Wdocumentation)
 	ADD_C_FLAG_IF_SUPPORTED(-Wno-missing-field-initializers)
 	ADD_C_FLAG_IF_SUPPORTED(-Wstrict-aliasing=2)
 	ADD_C_FLAG_IF_SUPPORTED(-Wstrict-prototypes)
diff --git a/README.md b/README.md
index 4ee1fdc..3191aee 100644
--- a/README.md
+++ b/README.md
@@ -88,7 +88,7 @@
 they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API
 for threading.
 
-The `libgit2` library is built using [CMake](<http://www.cmake.org>) (version 2.6 or newer) on all platforms.
+The `libgit2` library is built using [CMake](<http://www.cmake.org>) (version 2.8 or newer) on all platforms.
 
 On most systems you can build the library using the following commands
 
diff --git a/include/git2/repository.h b/include/git2/repository.h
index ce56fef..cf268ef 100644
--- a/include/git2/repository.h
+++ b/include/git2/repository.h
@@ -745,7 +745,7 @@
  *
  * @param repo the repository to configure
  * @param name the name to use for the reflog entries
- * @param name the email to use for the reflog entries
+ * @param email the email to use for the reflog entries
  */
 GIT_EXTERN(int) git_repository_set_ident(git_repository *repo, const char *name, const char *email);
 
diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h
index b5b7df1..044e344 100644
--- a/include/git2/sys/config.h
+++ b/include/git2/sys/config.h
@@ -76,7 +76,7 @@
  * Initializes a `git_config_backend` with default values. Equivalent to
  * creating an instance with GIT_CONFIG_BACKEND_INIT.
  *
- * @param opts the `git_config_backend` struct to initialize.
+ * @param backend the `git_config_backend` struct to initialize.
  * @param version Version of struct; pass `GIT_CONFIG_BACKEND_VERSION`
  * @return Zero on success; -1 on failure.
  */
diff --git a/include/git2/sys/diff.h b/include/git2/sys/diff.h
index 034d5c4..aefd7b9 100644
--- a/include/git2/sys/diff.h
+++ b/include/git2/sys/diff.h
@@ -38,7 +38,7 @@
 	const git_diff_delta *delta,
 	const git_diff_hunk *hunk,
 	const git_diff_line *line,
-	void *payload); /*< payload must be a `git_buf *` */
+	void *payload); /**< payload must be a `git_buf *` */
 
 /**
  * Diff print callback that writes to stdio FILE handle.
@@ -58,7 +58,7 @@
 	const git_diff_delta *delta,
 	const git_diff_hunk *hunk,
 	const git_diff_line *line,
-	void *payload); /*< payload must be a `FILE *` */
+	void *payload); /**< payload must be a `FILE *` */
 
 
 /**
@@ -66,8 +66,8 @@
  */
 typedef struct {
 	unsigned int version;
-	size_t stat_calls; /*< Number of stat() calls performed */
-	size_t oid_calculations; /*< Number of ID calculations */
+	size_t stat_calls; /**< Number of stat() calls performed */
+	size_t oid_calculations; /**< Number of ID calculations */
 } git_diff_perfdata;
 
 #define GIT_DIFF_PERFDATA_VERSION 1
diff --git a/include/git2/sys/odb_backend.h b/include/git2/sys/odb_backend.h
index 0a51c6d..fe102ff 100644
--- a/include/git2/sys/odb_backend.h
+++ b/include/git2/sys/odb_backend.h
@@ -93,7 +93,7 @@
  * Initializes a `git_odb_backend` with default values. Equivalent to
  * creating an instance with GIT_ODB_BACKEND_INIT.
  *
- * @param opts the `git_odb_backend` struct to initialize.
+ * @param backend the `git_odb_backend` struct to initialize.
  * @param version Version the struct; pass `GIT_ODB_BACKEND_VERSION`
  * @return Zero on success; -1 on failure.
  */
diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h
index d943e55..8b004a7 100644
--- a/include/git2/sys/refdb_backend.h
+++ b/include/git2/sys/refdb_backend.h
@@ -175,7 +175,7 @@
  * Initializes a `git_refdb_backend` with default values. Equivalent to
  * creating an instance with GIT_REFDB_BACKEND_INIT.
  *
- * @param opts the `git_refdb_backend` struct to initialize
+ * @param backend the `git_refdb_backend` struct to initialize
  * @param version Version of struct; pass `GIT_REFDB_BACKEND_VERSION`
  * @return Zero on success; -1 on failure.
  */
diff --git a/src/describe.c b/src/describe.c
index 5aea927..48f04e8 100644
--- a/src/describe.c
+++ b/src/describe.c
@@ -19,7 +19,7 @@
 #include "vector.h"
 #include "repository.h"
 
-GIT__USE_OIDMAP;
+GIT__USE_OIDMAP
 
 /* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */
 
diff --git a/src/filebuf.c b/src/filebuf.c
index 848ac34..838f4b4 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -101,7 +101,7 @@
 	if (file->fd_is_open && file->fd >= 0)
 		p_close(file->fd);
 
-	if (file->fd_is_open && file->path_lock && git_path_exists(file->path_lock))
+	if (file->created_lock && !file->did_rename && file->path_lock && git_path_exists(file->path_lock))
 		p_unlink(file->path_lock);
 
 	if (file->compute_digest) {
@@ -258,6 +258,7 @@
 			goto cleanup;
 		}
 		file->fd_is_open = true;
+		file->created_lock = true;
 
 		/* No original path */
 		file->path_original = NULL;
@@ -281,6 +282,8 @@
 		/* open the file for locking */
 		if ((error = lock_file(file, flags, mode)) < 0)
 			goto cleanup;
+
+		file->created_lock = true;
 	}
 
 	return 0;
@@ -340,6 +343,8 @@
 		goto on_error;
 	}
 
+	file->did_rename = true;
+
 	git_filebuf_cleanup(file);
 	return 0;
 
diff --git a/src/filebuf.h b/src/filebuf.h
index 2bd18dc..f4d255b 100644
--- a/src/filebuf.h
+++ b/src/filebuf.h
@@ -44,6 +44,8 @@
 	size_t buf_size, buf_pos;
 	git_file fd;
 	bool fd_is_open;
+	bool created_lock;
+	bool did_rename;
 	bool do_not_buffer;
 	int last_error;
 };
diff --git a/src/index.c b/src/index.c
index 501498e..73f0b3d 100644
--- a/src/index.c
+++ b/src/index.c
@@ -1228,6 +1228,45 @@
 	return 0;
 }
 
+static int add_repo_as_submodule(git_index_entry **out, git_index *index, const char *path)
+{
+	git_repository *sub;
+	git_buf abspath = GIT_BUF_INIT;
+	git_repository *repo = INDEX_OWNER(index);
+	git_reference *head;
+	git_index_entry *entry;
+	struct stat st;
+	int error;
+
+	if (index_entry_create(&entry, INDEX_OWNER(index), path) < 0)
+		return -1;
+
+	if ((error = git_buf_joinpath(&abspath, git_repository_workdir(repo), path)) < 0)
+		return error;
+
+	if ((error = p_stat(abspath.ptr, &st)) < 0) {
+		giterr_set(GITERR_OS, "failed to stat repository dir");
+		return -1;
+	}
+
+	git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
+
+	if ((error = git_repository_open(&sub, abspath.ptr)) < 0)
+		return error;
+
+	if ((error = git_repository_head(&head, sub)) < 0)
+		return error;
+
+	git_oid_cpy(&entry->id, git_reference_target(head));
+	entry->mode = GIT_FILEMODE_COMMIT;
+
+	git_reference_free(head);
+	git_repository_free(sub);
+	git_buf_free(&abspath);
+
+	*out = entry;
+	return 0;
+}
 
 int git_index_add_bypath(git_index *index, const char *path)
 {
@@ -1252,12 +1291,26 @@
 		ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path);
 		if (ret == GIT_ENOTFOUND)
 			return giterr_restore(&err);
-		else
-			git__free(err.error_msg.message);
 
-		ret = git_submodule_add_to_index(sm, false);
-		git_submodule_free(sm);
-		return ret;
+		git__free(err.error_msg.message);
+
+		/*
+		 * EEXISTS means that there is a repository at that path, but it's not known
+		 * as a submodule. We add its HEAD as an entry and don't register it.
+		 */
+		if (ret == GIT_EEXISTS) {
+			if ((ret = add_repo_as_submodule(&entry, index, path)) < 0)
+				return ret;
+
+			if ((ret = index_insert(index, &entry, 1, false)) < 0)
+				return ret;
+		} else if (ret < 0) {
+			return ret;
+		} else {
+			ret = git_submodule_add_to_index(sm, false);
+			git_submodule_free(sm);
+			return ret;
+		}
 	}
 
 	/* Adding implies conflict was resolved, move conflict entries to REUC */
diff --git a/src/indexer.c b/src/indexer.c
index 512addf..9aa0925 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -18,7 +18,7 @@
 #include "oidmap.h"
 #include "zstream.h"
 
-GIT__USE_OIDMAP;
+GIT__USE_OIDMAP
 
 extern git_mutex git__mwindow_mutex;
 
diff --git a/src/iterator.c b/src/iterator.c
index a312afb..cf51a34 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -1027,8 +1027,11 @@
 	strncomp = (flags & GIT_PATH_DIR_IGNORE_CASE) != 0 ?
 		git__strncasecmp : git__strncmp;
 
-	if ((error = git_path_diriter_init(&diriter, dirpath, flags)) < 0)
+	/* Any error here is equivalent to the dir not existing, skip over it */
+	if ((error = git_path_diriter_init(&diriter, dirpath, flags)) < 0) {
+		error = GIT_ENOTFOUND;
 		goto done;
+	}
 
 	while ((error = git_path_diriter_next(&diriter)) == 0) {
 		if ((error = git_path_diriter_fullpath(&path, &path_len, &diriter)) < 0)
diff --git a/src/pack-objects.c b/src/pack-objects.c
index e287e33..c4c061a 100644
--- a/src/pack-objects.c
+++ b/src/pack-objects.c
@@ -41,7 +41,7 @@
 	git_transfer_progress *stats;
 };
 
-GIT__USE_OIDMAP;
+GIT__USE_OIDMAP
 
 #ifdef GIT_THREADS
 
diff --git a/src/pack.c b/src/pack.c
index cd65267..45dd4d5 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -16,8 +16,8 @@
 
 #include <zlib.h>
 
-GIT__USE_OFFMAP;
-GIT__USE_OIDMAP;
+GIT__USE_OFFMAP
+GIT__USE_OIDMAP
 
 static int packfile_open(struct git_pack_file *p);
 static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_t n);
diff --git a/src/path.h b/src/path.h
index 5927a53..e6be06f 100644
--- a/src/path.h
+++ b/src/path.h
@@ -319,7 +319,7 @@
  * @param callback Function to invoke on each path.  Passed the `payload`
  *		and the buffer containing the current path.  The path should not
  *		be modified in any way. Return non-zero to stop iteration.
- * @param state Passed to fn as the first ath.
+ * @param payload Passed to fn as the first ath.
  */
 extern int git_path_walk_up(
 	git_buf *pathbuf,
diff --git a/src/push.h b/src/push.h
index 094f96c..a847ee0 100644
--- a/src/push.h
+++ b/src/push.h
@@ -83,7 +83,7 @@
  * Update remote tips after a push
  *
  * @param push The push object
- * @param signature The identity to use when updating reflogs
+ * @param callbacks the callbacks to use for this connection
  *
  * @return 0 or an error code
  */
@@ -100,6 +100,7 @@
  * order to find out which updates were accepted or rejected.
  *
  * @param push The push object
+ * @param callbacks the callbacks to use for this connection
  *
  * @return 0 or an error code
  */
@@ -117,6 +118,7 @@
  *
  * @param push The push object
  * @param cb The callback to call on each object
+ * @param data The payload passed to the callback
  *
  * @return 0 on success, non-zero callback return value, or error code
  */
diff --git a/src/revwalk.c b/src/revwalk.c
index 6acc5d0..dcdd979 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -14,7 +14,7 @@
 #include "git2/revparse.h"
 #include "merge.h"
 
-GIT__USE_OIDMAP;
+GIT__USE_OIDMAP
 
 git_commit_list_node *git_revwalk__commit_lookup(
 	git_revwalk *walk, const git_oid *oid)
diff --git a/src/transports/git.c b/src/transports/git.c
index 7e0a474..52de92d 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -50,6 +50,8 @@
 	}
 
 	repo = delim;
+	if (repo[1] == '~')
+		++repo;
 
 	delim = strchr(url, ':');
 	if (delim == NULL)
diff --git a/src/transports/http.c b/src/transports/http.c
index 1ed292b..e3d90de 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -255,7 +255,7 @@
 			GITERR_CHECK_ALLOC(t->content_type);
 		}
 	}
-	else if (!strcmp("WWW-Authenticate", git_buf_cstr(name))) {
+	else if (!strcasecmp("WWW-Authenticate", git_buf_cstr(name))) {
 		char *dup = git__strdup(git_buf_cstr(value));
 		GITERR_CHECK_ALLOC(dup);
 
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index 83af137..e3792eb 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -66,6 +66,8 @@
 	if (!git__prefixcmp(url, prefix_ssh)) {
 		url = url + strlen(prefix_ssh);
 		repo = strchr(url, '/');
+		if (repo && repo[1] == '~')
+			++repo;
 	} else {
 		repo = strchr(url, ':');
 		if (repo) repo++;
diff --git a/tests/core/filebuf.c b/tests/core/filebuf.c
index 5a3e751..3f7dc85 100644
--- a/tests/core/filebuf.c
+++ b/tests/core/filebuf.c
@@ -124,3 +124,30 @@
 	cl_must_pass(p_unlink(test));
 }
 
+void test_core_filebuf__rename_error(void)
+{
+	git_filebuf file = GIT_FILEBUF_INIT;
+	char *dir = "subdir",  *test = "subdir/test", *test_lock = "subdir/test.lock";
+	int fd;
+
+#ifndef GIT_WIN32
+	cl_skip();
+#endif
+
+	cl_git_pass(p_mkdir(dir, 0666));
+	cl_git_mkfile(test, "dummy content");
+	fd = p_open(test, O_RDONLY);
+	cl_assert(fd > 0);
+	cl_git_pass(git_filebuf_open(&file, test, 0, 0666));
+
+	cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks"));
+
+	cl_assert_equal_i(true, git_path_exists(test_lock));
+
+	cl_git_fail(git_filebuf_commit(&file));
+	p_close(fd);
+
+	git_filebuf_cleanup(&file);
+
+	cl_assert_equal_i(false, git_path_exists(test_lock));
+}
diff --git a/tests/index/bypath.c b/tests/index/bypath.c
index ddb766a..9706a88 100644
--- a/tests/index/bypath.c
+++ b/tests/index/bypath.c
@@ -33,3 +33,16 @@
 	cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0));
 	cl_assert_equal_i(0, status & GIT_SUBMODULE_STATUS_WD_MODIFIED);
 }
+
+void test_index_bypath__add_submodule_unregistered(void)
+{
+	const char *sm_name = "not-submodule";
+	const char *sm_head = "68e92c611b80ee1ed8f38314ff9577f0d15b2444";
+	const git_index_entry *entry;
+
+	cl_git_pass(git_index_add_bypath(g_idx, sm_name));
+
+	cl_assert(entry = git_index_get_bypath(g_idx, sm_name, 0));
+	cl_assert_equal_s(sm_head, git_oid_tostr_s(&entry->id));
+	cl_assert_equal_s(sm_name, entry->path);
+}
diff --git a/tests/repo/iterator.c b/tests/repo/iterator.c
index 26e8954..bb2d3a1 100644
--- a/tests/repo/iterator.c
+++ b/tests/repo/iterator.c
@@ -928,7 +928,7 @@
 	git_iterator_free(i);
 }
 
-void test_repo_iterator__fs_preserves_error(void)
+void test_repo_iterator__unreadable_dir(void)
 {
 	git_iterator *i;
 	const git_index_entry *e;
@@ -951,10 +951,6 @@
 
 	cl_git_pass(git_iterator_advance(&e, i)); /* a */
 	cl_git_fail(git_iterator_advance(&e, i)); /* b */
-	cl_assert(giterr_last());
-	cl_assert(giterr_last()->message != NULL);
-	/* skip 'c/' empty directory */
-	cl_git_pass(git_iterator_advance(&e, i)); /* d */
 	cl_assert_equal_i(GIT_ITEROVER, git_iterator_advance(&e, i));
 
 	cl_must_pass(p_chmod("empty_standard_repo/r/b", 0777));