summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml25
-rw-r--r--examples/network/fetch.c12
-rw-r--r--examples/network/git2.c5
-rw-r--r--examples/network/index-pack.c47
-rw-r--r--examples/network/ls-remote.c9
-rw-r--r--include/git2/attr.h55
-rw-r--r--include/git2/blob.h2
-rw-r--r--include/git2/branch.h4
-rw-r--r--include/git2/commit.h2
-rw-r--r--include/git2/common.h23
-rw-r--r--include/git2/config.h6
-rw-r--r--include/git2/diff.h18
-rw-r--r--include/git2/errors.h1
-rw-r--r--include/git2/index.h4
-rw-r--r--include/git2/message.h8
-rw-r--r--include/git2/notes.h44
-rw-r--r--include/git2/object.h2
-rw-r--r--include/git2/odb.h9
-rw-r--r--include/git2/odb_backend.h3
-rw-r--r--include/git2/oid.h28
-rw-r--r--include/git2/reflog.h2
-rw-r--r--include/git2/refs.h7
-rw-r--r--include/git2/remote.h5
-rw-r--r--include/git2/repository.h35
-rw-r--r--include/git2/status.h4
-rw-r--r--include/git2/tag.h2
-rw-r--r--include/git2/tree.h20
-rw-r--r--src/attr.c35
-rw-r--r--src/attr_file.c14
-rw-r--r--src/attr_file.h4
-rw-r--r--src/cache.c1
-rw-r--r--src/commit.c2
-rw-r--r--src/common.h3
-rw-r--r--src/config.c4
-rw-r--r--src/config_file.c10
-rw-r--r--src/date.c40
-rw-r--r--src/diff.c1
-rw-r--r--src/diff_output.c104
-rw-r--r--src/fetch.c223
-rw-r--r--src/fetch.h3
-rw-r--r--src/filebuf.c9
-rw-r--r--src/fileops.c4
-rw-r--r--src/ignore.c2
-rw-r--r--src/index.c11
-rw-r--r--src/message.c24
-rw-r--r--src/netops.c75
-rw-r--r--src/netops.h11
-rw-r--r--src/notes.c46
-rw-r--r--src/object.c2
-rw-r--r--src/odb.c8
-rw-r--r--src/odb_loose.c20
-rw-r--r--src/odb_pack.c50
-rw-r--r--src/oid.c7
-rw-r--r--src/oidmap.h7
-rw-r--r--src/pack.c17
-rw-r--r--src/pack.h2
-rw-r--r--src/path.h1
-rw-r--r--src/pkt.c38
-rw-r--r--src/protocol.c86
-rw-r--r--src/protocol.h12
-rw-r--r--src/reflog.c6
-rw-r--r--src/refs.c72
-rw-r--r--src/remote.c26
-rw-r--r--src/remote.h2
-rw-r--r--src/repository.c68
-rw-r--r--src/revparse.c14
-rw-r--r--src/sha1.h5
-rw-r--r--src/status.c24
-rw-r--r--src/transport.h22
-rw-r--r--src/transports/git.c284
-rw-r--r--src/transports/http.c434
-rw-r--r--src/transports/local.c67
-rw-r--r--src/tree.c45
-rw-r--r--src/util.c12
-rw-r--r--src/vector.c2
-rw-r--r--src/vector.h10
-rw-r--r--src/win32/posix_w32.c7
-rw-r--r--tests-clar/attr/repo.c22
-rw-r--r--tests-clar/config/read.c18
-rw-r--r--tests-clar/diff/diff_helpers.c2
-rw-r--r--tests-clar/diff/index.c50
-rw-r--r--tests-clar/network/remotelocal.c4
-rw-r--r--tests-clar/notes/notes.c30
-rw-r--r--tests-clar/object/blob/fromchunks.c2
-rw-r--r--tests-clar/object/commit/commitstagedfile.c67
-rw-r--r--tests-clar/object/tree/walk.c103
-rw-r--r--tests-clar/odb/foreach.c46
-rw-r--r--tests-clar/odb/pack_data_one.h19
-rw-r--r--tests-clar/odb/packed_one.c58
-rw-r--r--tests-clar/refs/branches/foreach.c29
-rw-r--r--tests-clar/refs/foreachglob.c28
-rw-r--r--tests-clar/refs/read.c24
-rw-r--r--tests-clar/repo/message.c47
-rw-r--r--tests-clar/resources/config/config144
-rw-r--r--tests-clar/resources/testrepo.git/refs/heads/chomped1
-rw-r--r--tests-clar/resources/testrepo.git/refs/heads/trailing1
-rw-r--r--tests-clar/status/worktree.c33
97 files changed, 1804 insertions, 1142 deletions
diff --git a/.travis.yml b/.travis.yml
index caead67b1..29ef9d40d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,16 +2,22 @@
# see travis-ci.org for details
# As CMake is not officially supported we use erlang VMs
-language: erlang
+language: c
+
+compiler:
+ - gcc
+ - clang
# Settings to try
env:
- - CC=gcc OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release"
- - CC=clang OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release"
- - CC=gcc OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=ON"
- - CC=clang OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=ON"
- - CC=i586-mingw32msvc-gcc OPTIONS="-DBUILD_CLAR=OFF -DWIN32=ON -DMINGW=ON"
-
+ - OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release"
+ - OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=ON"
+
+matrix:
+ include:
+ - compiler: i586-mingw32msvc-gcc
+ env: OPTIONS="-DBUILD_CLAR=OFF -DWIN32=ON -DMINGW=ON"
+
# Make sure CMake is installed
install:
- sudo apt-get install cmake valgrind
@@ -35,6 +41,11 @@ branches:
# Notify development list when needed
notifications:
+ irc:
+ channels:
+ - irc.freenode.net#libgit2
+ on_success: change
+ on_failure: always
recipients:
- vicent@github.com
email:
diff --git a/examples/network/fetch.c b/examples/network/fetch.c
index 73bfbddd0..52e0412f4 100644
--- a/examples/network/fetch.c
+++ b/examples/network/fetch.c
@@ -40,9 +40,8 @@ exit:
pthread_exit(&data->ret);
}
-int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data)
+static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data)
{
- const char *action;
char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1];
git_oid_fmt(b_str, b);
@@ -68,6 +67,7 @@ int fetch(git_repository *repo, int argc, char **argv)
struct dl_data data;
git_remote_callbacks callbacks;
+ argc = argc;
// Figure out whether it's a named remote or a URL
printf("Fetching %s\n", argv[1]);
if (git_remote_load(&remote, repo, argv[1]) < 0) {
@@ -96,10 +96,14 @@ int fetch(git_repository *repo, int argc, char **argv)
// the download rate.
do {
usleep(10000);
- printf("\rReceived %d/%d objects in %d bytes", stats.processed, stats.total, bytes);
+ printf("\rReceived %d/%d objects in %zu bytes", stats.processed, stats.total, bytes);
} while (!data.finished);
- printf("\rReceived %d/%d objects in %d bytes\n", stats.processed, stats.total, bytes);
+ if (data.ret < 0)
+ goto on_error;
+
+ pthread_join(worker, NULL);
+ printf("\rReceived %d/%d objects in %zu bytes\n", stats.processed, stats.total, bytes);
// Disconnect the underlying connection to prevent from idling.
git_remote_disconnect(remote);
diff --git a/examples/network/git2.c b/examples/network/git2.c
index 9f0f43e2c..ecb16630b 100644
--- a/examples/network/git2.c
+++ b/examples/network/git2.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include "common.h"
@@ -17,7 +18,7 @@ struct {
{ NULL, NULL}
};
-int run_command(git_cb fn, int argc, char **argv)
+static int run_command(git_cb fn, int argc, char **argv)
{
int error;
git_repository *repo;
@@ -46,7 +47,7 @@ int run_command(git_cb fn, int argc, char **argv)
int main(int argc, char **argv)
{
- int i, error;
+ int i;
if (argc < 2) {
fprintf(stderr, "usage: %s <cmd> [repo]\n", argv[0]);
diff --git a/examples/network/index-pack.c b/examples/network/index-pack.c
index ef5a35957..85aac4aff 100644
--- a/examples/network/index-pack.c
+++ b/examples/network/index-pack.c
@@ -2,13 +2,20 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
#include "common.h"
// This could be run in the main loop whilst the application waits for
// the indexing to finish in a worker thread
-int index_cb(const git_indexer_stats *stats, void *data)
+static int index_cb(const git_indexer_stats *stats, void *data)
{
+ data = data;
printf("\rProcessing %d of %d", stats->processed, stats->total);
+
+ return 0;
}
int index_pack(git_repository *repo, int argc, char **argv)
@@ -20,6 +27,7 @@ int index_pack(git_repository *repo, int argc, char **argv)
ssize_t read_bytes;
char buf[512];
+ repo = repo;
if (argc < 2) {
fprintf(stderr, "I need a packfile\n");
return EXIT_FAILURE;
@@ -43,7 +51,7 @@ int index_pack(git_repository *repo, int argc, char **argv)
if ((error = git_indexer_stream_add(idx, buf, read_bytes, &stats)) < 0)
goto cleanup;
- printf("\rIndexing %d of %d", stats.processed, stats.total);
+ index_cb(&stats, NULL);
} while (read_bytes > 0);
if (read_bytes < 0) {
@@ -65,38 +73,3 @@ int index_pack(git_repository *repo, int argc, char **argv)
git_indexer_stream_free(idx);
return error;
}
-
-int index_pack_old(git_repository *repo, int argc, char **argv)
-{
- git_indexer *indexer;
- git_indexer_stats stats;
- int error;
- char hash[GIT_OID_HEXSZ + 1] = {0};
-
- if (argc < 2) {
- fprintf(stderr, "I need a packfile\n");
- return EXIT_FAILURE;
- }
-
- // Create a new indexer
- error = git_indexer_new(&indexer, argv[1]);
- if (error < 0)
- return error;
-
- // Index the packfile. This function can take a very long time and
- // should be run in a worker thread.
- error = git_indexer_run(indexer, &stats);
- if (error < 0)
- return error;
-
- // Write the information out to an index file
- error = git_indexer_write(indexer);
-
- // Get the packfile's hash (which should become it's filename)
- git_oid_fmt(hash, git_indexer_hash(indexer));
- puts(hash);
-
- git_indexer_free(indexer);
-
- return 0;
-}
diff --git a/examples/network/ls-remote.c b/examples/network/ls-remote.c
index 39cc64725..822d6f668 100644
--- a/examples/network/ls-remote.c
+++ b/examples/network/ls-remote.c
@@ -7,12 +7,14 @@
static int show_ref__cb(git_remote_head *head, void *payload)
{
char oid[GIT_OID_HEXSZ + 1] = {0};
+
+ payload = payload;
git_oid_fmt(oid, &head->oid);
printf("%s\t%s\n", oid, head->name);
return 0;
}
-int use_unnamed(git_repository *repo, const char *url)
+static int use_unnamed(git_repository *repo, const char *url)
{
git_remote *remote = NULL;
int error;
@@ -37,7 +39,7 @@ cleanup:
return error;
}
-int use_remote(git_repository *repo, char *name)
+static int use_remote(git_repository *repo, char *name)
{
git_remote *remote = NULL;
int error;
@@ -63,8 +65,9 @@ cleanup:
int ls_remote(git_repository *repo, int argc, char **argv)
{
- int error, i;
+ int error;
+ argc = argc;
/* If there's a ':' in the name, assume it's an URL */
if (strchr(argv[1], ':') != NULL) {
error = use_unnamed(repo, argv[1]);
diff --git a/include/git2/attr.h b/include/git2/attr.h
index fad7183da..2de9f4b0e 100644
--- a/include/git2/attr.h
+++ b/include/git2/attr.h
@@ -30,7 +30,7 @@ GIT_BEGIN_DECL
* Then for file `xyz.c` looking up attribute "foo" gives a value for
* which `GIT_ATTR_TRUE(value)` is true.
*/
-#define GIT_ATTR_TRUE(attr) ((attr) == git_l_attr__true)
+#define GIT_ATTR_TRUE(attr) (git_attr_value(attr) == GIT_ATTR_TRUE_T)
/**
* GIT_ATTR_FALSE checks if an attribute is set off. In core git
@@ -44,7 +44,7 @@ GIT_BEGIN_DECL
* Then for file `zyx.h` looking up attribute "foo" gives a value for
* which `GIT_ATTR_FALSE(value)` is true.
*/
-#define GIT_ATTR_FALSE(attr) ((attr) == git_l_attr__false)
+#define GIT_ATTR_FALSE(attr) (git_attr_value(attr) == GIT_ATTR_FALSE_T)
/**
* GIT_ATTR_UNSPECIFIED checks if an attribute is unspecified. This
@@ -62,7 +62,7 @@ GIT_BEGIN_DECL
* file `onefile.rb` or looking up "bar" on any file will all give
* `GIT_ATTR_UNSPECIFIED(value)` of true.
*/
-#define GIT_ATTR_UNSPECIFIED(attr) (!(attr) || (attr) == git_l_attr__unset)
+#define GIT_ATTR_UNSPECIFIED(attr) (git_attr_value(attr) == GIT_ATTR_UNSPECIFIED_T)
/**
* GIT_ATTR_HAS_VALUE checks if an attribute is set to a value (as
@@ -74,13 +74,29 @@ GIT_BEGIN_DECL
* Given this, looking up "eol" for `onefile.txt` will give back the
* string "lf" and `GIT_ATTR_SET_TO_VALUE(attr)` will return true.
*/
-#define GIT_ATTR_HAS_VALUE(attr) \
- ((attr) && (attr) != git_l_attr__unset && \
- (attr) != git_l_attr__true && (attr) != git_attr__false)
+#define GIT_ATTR_HAS_VALUE(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_T)
-GIT_EXTERN(const char *) git_l_attr__true;
-GIT_EXTERN(const char *) git_l_attr__false;
-GIT_EXTERN(const char *) git_l_attr__unset;
+typedef enum {
+ GIT_ATTR_UNSPECIFIED_T = 0,
+ GIT_ATTR_TRUE_T,
+ GIT_ATTR_FALSE_T,
+ GIT_ATTR_VALUE_T,
+} git_attr_t;
+
+/*
+ * Return the value type for a given attribute.
+ *
+ * This can be either `TRUE`, `FALSE`, `UNSPECIFIED` (if the attribute
+ * was not set at all), or `VALUE`, if the attribute was set to
+ * an actual string.
+ *
+ * If the attribute has a `VALUE` string, it can be accessed normally
+ * as a NULL-terminated C string.
+ *
+ * @param attr The attribute
+ * @return the value type for the attribute
+ */
+GIT_EXTERN(git_attr_t) git_attr_value(const char *attr);
/**
* Check attribute flags: Reading values from index and working directory.
@@ -172,18 +188,17 @@ GIT_EXTERN(int) git_attr_get_many(
*
* @param repo The repository containing the path.
* @param flags A combination of GIT_ATTR_CHECK... flags.
- * @param path The path inside the repo to check attributes. This
- * does not have to exist, but if it does not, then
- * it will be treated as a plain file (i.e. not a directory).
- * @param callback The function that will be invoked on each attribute
- * and attribute value. The name parameter will be the name
- * of the attribute and the value will be the value it is
- * set to, including possibly NULL if the attribute is
- * explicitly set to UNSPECIFIED using the ! sign. This
- * will be invoked only once per attribute name, even if
- * there are multiple rules for a given file. The highest
- * priority rule will be used.
+ * @param path Path inside the repo to check attributes. This does not have
+ * to exist, but if it does not, then it will be treated as a
+ * plain file (i.e. not a directory).
+ * @param callback Function to invoke on each attribute name and value. The
+ * value may be NULL is the attribute is explicitly set to
+ * UNSPECIFIED using the '!' sign. Callback will be invoked
+ * only once per attribute name, even if there are multiple
+ * rules for a given file. The highest priority rule will be
+ * used. Return a non-zero value from this to stop looping.
* @param payload Passed on as extra parameter to callback function.
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_attr_foreach(
git_repository *repo,
diff --git a/include/git2/blob.h b/include/git2/blob.h
index 544dc7c41..f0719f15d 100644
--- a/include/git2/blob.h
+++ b/include/git2/blob.h
@@ -46,7 +46,7 @@ GIT_INLINE(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git
* @param len the length of the short identifier
* @return 0 or an error code
*/
-GIT_INLINE(int) git_blob_lookup_prefix(git_blob **blob, git_repository *repo, const git_oid *id, unsigned int len)
+GIT_INLINE(int) git_blob_lookup_prefix(git_blob **blob, git_repository *repo, const git_oid *id, size_t len)
{
return git_object_lookup_prefix((git_object **)blob, repo, id, len, GIT_OBJ_BLOB);
}
diff --git a/include/git2/branch.h b/include/git2/branch.h
index 2f46720af..8bf7eb9d4 100644
--- a/include/git2/branch.h
+++ b/include/git2/branch.h
@@ -74,6 +74,8 @@ GIT_EXTERN(int) git_branch_delete(
/**
* Loop over all the branches and issue a callback for each one.
*
+ * If the callback returns a non-zero value, this will stop looping.
+ *
* @param repo Repository where to find the branches.
*
* @param list_flags Filtering flags for the branch
@@ -84,7 +86,7 @@ GIT_EXTERN(int) git_branch_delete(
*
* @param payload Extra parameter to callback function.
*
- * @return 0 or an error code.
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_branch_foreach(
git_repository *repo,
diff --git a/include/git2/commit.h b/include/git2/commit.h
index e8ecc808b..a159b79e1 100644
--- a/include/git2/commit.h
+++ b/include/git2/commit.h
@@ -48,7 +48,7 @@ GIT_INLINE(int) git_commit_lookup(git_commit **commit, git_repository *repo, con
* @param len the length of the short identifier
* @return 0 or an error code
*/
-GIT_INLINE(int) git_commit_lookup_prefix(git_commit **commit, git_repository *repo, const git_oid *id, unsigned len)
+GIT_INLINE(int) git_commit_lookup_prefix(git_commit **commit, git_repository *repo, const git_oid *id, size_t len)
{
return git_object_lookup_prefix((git_object **)commit, repo, id, len, GIT_OBJ_COMMIT);
}
diff --git a/include/git2/common.h b/include/git2/common.h
index 1af045cff..0af37e81f 100644
--- a/include/git2/common.h
+++ b/include/git2/common.h
@@ -103,6 +103,29 @@ GIT_EXTERN(int) git_strarray_copy(git_strarray *tgt, const git_strarray *src);
*/
GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev);
+/**
+ * Combinations of these values describe the capabilities of libgit2.
+ */
+enum {
+ GIT_CAP_THREADS = ( 1 << 0 ),
+ GIT_CAP_HTTPS = ( 1 << 1 )
+};
+
+/**
+ * Query compile time options for libgit2.
+ *
+ * @return A combination of GIT_CAP_* values.
+ *
+ * - GIT_CAP_THREADS
+ * Libgit2 was compiled with thread support. Note that thread support is still to be seen as a
+ * 'work in progress'.
+ *
+ * - GIT_CAP_HTTPS
+ * Libgit2 supports the https:// protocol. This requires the open ssl library to be
+ * found when compiling libgit2.
+ */
+GIT_EXTERN(int) git_libgit2_capabilities(void);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/include/git2/config.h b/include/git2/config.h
index c46e7fc9d..f415fbd9d 100644
--- a/include/git2/config.h
+++ b/include/git2/config.h
@@ -302,12 +302,12 @@ GIT_EXTERN(int) git_config_delete(git_config *cfg, const char *name);
* The callback receives the normalized name and value of each variable
* in the config backend, and the data pointer passed to this function.
* As soon as one of the callback functions returns something other than 0,
- * this function returns that value.
+ * this function stops iterating and returns `GIT_EUSER`.
*
* @param cfg where to get the variables from
* @param callback the function to call on each variable
* @param payload the data to pass to the callback
- * @return 0 or the return value of the callback which didn't return 0
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_config_foreach(
git_config *cfg,
@@ -342,7 +342,7 @@ GIT_EXTERN(int) git_config_foreach_match(
*
* A mapping array looks as follows:
*
- * git_cvar_map autocrlf_mapping[3] = {
+ * git_cvar_map autocrlf_mapping[] = {
* {GIT_CVAR_FALSE, NULL, GIT_AUTO_CRLF_FALSE},
* {GIT_CVAR_TRUE, NULL, GIT_AUTO_CRLF_TRUE},
* {GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT},
diff --git a/include/git2/diff.h b/include/git2/diff.h
index 85727d969..79ef7a49b 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -332,6 +332,9 @@ GIT_EXTERN(int) git_diff_merge(
* callbacks will not be invoked for binary files on the diff list or for
* files whose only changed is a file mode change.
*
+ * Returning a non-zero value from any of the callbacks will terminate
+ * the iteration and cause this return `GIT_EUSER`.
+ *
* @param diff A git_diff_list generated by one of the above functions.
* @param cb_data Reference pointer that will be passed to your callbacks.
* @param file_cb Callback function to make per file in the diff.
@@ -341,6 +344,7 @@ GIT_EXTERN(int) git_diff_merge(
* @param line_cb Optional callback to make per line of diff text. This
* same callback will be made for context lines, added, and
* removed lines, and even for a deleted trailing newline.
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_diff_foreach(
git_diff_list *diff,
@@ -351,6 +355,14 @@ GIT_EXTERN(int) git_diff_foreach(
/**
* Iterate over a diff generating text output like "git diff --name-status".
+ *
+ * Returning a non-zero value from the callbacks will terminate the
+ * iteration and cause this return `GIT_EUSER`.
+ *
+ * @param diff A git_diff_list generated by one of the above functions.
+ * @param cb_data Reference pointer that will be passed to your callback.
+ * @param print_cb Callback to make per line of diff text.
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_diff_print_compact(
git_diff_list *diff,
@@ -362,6 +374,9 @@ GIT_EXTERN(int) git_diff_print_compact(
*
* This is a super easy way to generate a patch from a diff.
*
+ * Returning a non-zero value from the callbacks will terminate the
+ * iteration and cause this return `GIT_EUSER`.
+ *
* @param diff A git_diff_list generated by one of the above functions.
* @param cb_data Reference pointer that will be passed to your callbacks.
* @param print_cb Callback function to output lines of the diff. This
@@ -369,6 +384,7 @@ GIT_EXTERN(int) git_diff_print_compact(
* headers, and diff lines. Fortunately, you can probably
* use various GIT_DIFF_LINE constants to determine what
* text you are given.
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_diff_print_patch(
git_diff_list *diff,
@@ -393,6 +409,8 @@ GIT_EXTERN(int) git_diff_print_patch(
* When at least one of the blobs being dealt with is binary, the
* `git_diff_delta` binary attribute will be set to 1 and no call to the
* hunk_cb nor line_cb will be made.
+ *
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_diff_blobs(
git_blob *old_blob,
diff --git a/include/git2/errors.h b/include/git2/errors.h
index ca7f0de6e..2ab1da403 100644
--- a/include/git2/errors.h
+++ b/include/git2/errors.h
@@ -25,6 +25,7 @@ enum {
GIT_EEXISTS = -4,
GIT_EAMBIGUOUS = -5,
GIT_EBUFS = -6,
+ GIT_EUSER = -7,
GIT_PASSTHROUGH = -30,
GIT_REVWALKOVER = -31,
diff --git a/include/git2/index.h b/include/git2/index.h
index c88a1701c..062932e1a 100644
--- a/include/git2/index.h
+++ b/include/git2/index.h
@@ -280,7 +280,7 @@ GIT_EXTERN(int) git_index_remove(git_index *index, int position);
* @param n the position of the entry
* @return a pointer to the entry; NULL if out of bounds
*/
-GIT_EXTERN(git_index_entry *) git_index_get(git_index *index, unsigned int n);
+GIT_EXTERN(git_index_entry *) git_index_get(git_index *index, size_t n);
/**
* Get the count of entries currently in the index
@@ -320,7 +320,7 @@ GIT_EXTERN(const git_index_entry_unmerged *) git_index_get_unmerged_bypath(git_i
* @param n the position of the entry
* @return a pointer to the unmerged entry; NULL if out of bounds
*/
-GIT_EXTERN(const git_index_entry_unmerged *) git_index_get_unmerged_byindex(git_index *index, unsigned int n);
+GIT_EXTERN(const git_index_entry_unmerged *) git_index_get_unmerged_byindex(git_index *index, size_t n);
/**
* Return the stage number from a git index entry
diff --git a/include/git2/message.h b/include/git2/message.h
index 7f2558583..b42cb7677 100644
--- a/include/git2/message.h
+++ b/include/git2/message.h
@@ -23,8 +23,9 @@ GIT_BEGIN_DECL
*
* Optionally, can remove lines starting with a "#".
*
- * @param message_out The user allocated buffer which will be filled with
- * the cleaned up message.
+ * @param message_out The user allocated buffer which will be filled with
+ * the cleaned up message. Pass NULL if you just want to get the size of the
+ * prettified message as the output value.
*
* @param size The size of the allocated buffer message_out.
*
@@ -32,7 +33,8 @@ GIT_BEGIN_DECL
*
* @param strip_comments 1 to remove lines starting with a "#", 0 otherwise.
*
- * @return GIT_SUCCESS or an error code
+ * @return -1 on error, else number of characters in prettified message
+ * including the trailing NUL byte
*/
GIT_EXTERN(int) git_message_prettify(char *message_out, size_t buffer_size, const char *message, int strip_comments);
diff --git a/include/git2/notes.h b/include/git2/notes.h
index 19073abd1..af480a408 100644
--- a/include/git2/notes.h
+++ b/include/git2/notes.h
@@ -23,10 +23,11 @@ GIT_BEGIN_DECL
*
* The note must be freed manually by the user.
*
- * @param note the note; NULL in case of error
- * @param repo the Git repository
- * @param notes_ref OID reference to use (optional); defaults to "refs/notes/commits"
- * @param oid OID of the object
+ * @param note pointer to the read note; NULL in case of error
+ * @param repo repository where to look up the note
+ * @param notes_ref canonical name of the reference to use (optional);
+ * defaults to "refs/notes/commits"
+ * @param oid OID of the git object to read the note from
*
* @return 0 or an error code
*/
@@ -50,17 +51,17 @@ GIT_EXTERN(const char *) git_note_message(git_note *note);
*/
GIT_EXTERN(const git_oid *) git_note_oid(git_note *note);
-
/**
* Add a note for an object
*
- * @param oid pointer to store the OID (optional); NULL in case of error
- * @param repo the Git repository
+ * @param out pointer to store the OID (optional); NULL in case of error
+ * @param repo repository where to store the note
* @param author signature of the notes commit author
* @param committer signature of the notes commit committer
- * @param notes_ref OID reference to update (optional); defaults to "refs/notes/commits"
- * @param oid The OID of the object
- * @param oid The note to add for object oid
+ * @param notes_ref canonical name of the reference to use (optional);
+ * defaults to "refs/notes/commits"
+ * @param oid OID of the git object to decorate
+ * @param note Content of the note to add for object oid
*
* @return 0 or an error code
*/
@@ -73,11 +74,12 @@ GIT_EXTERN(int) git_note_create(git_oid *out, git_repository *repo,
/**
* Remove the note for an object
*
- * @param repo the Git repository
- * @param notes_ref OID reference to use (optional); defaults to "refs/notes/commits"
+ * @param repo repository where the note lives
+ * @param notes_ref canonical name of the reference to use (optional);
+ * defaults to "refs/notes/commits"
* @param author signature of the notes commit author
* @param committer signature of the notes commit committer
- * @param oid the oid which note's to be removed
+ * @param oid OID of the git object to remove the note from
*
* @return 0 or an error code
*/
@@ -119,19 +121,21 @@ typedef struct {
*
* @param repo Repository where to find the notes.
*
- * @param notes_ref OID reference to read from (optional); defaults to "refs/notes/commits".
+ * @param notes_ref Reference to read from (optional); defaults to
+ * "refs/notes/commits".
*
- * @param note_cb Callback to invoke per found annotation.
+ * @param note_cb Callback to invoke per found annotation. Return non-zero
+ * to stop looping.
*
* @param payload Extra parameter to callback function.
*
- * @return 0 or an error code.
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_note_foreach(
- git_repository *repo,
- const char *notes_ref,
- int (*note_cb)(git_note_data *note_data, void *payload),
- void *payload
+ git_repository *repo,
+ const char *notes_ref,
+ int (*note_cb)(git_note_data *note_data, void *payload),
+ void *payload
);
/** @} */
diff --git a/include/git2/object.h b/include/git2/object.h
index d9e653fd4..722434dec 100644
--- a/include/git2/object.h
+++ b/include/git2/object.h
@@ -75,7 +75,7 @@ GIT_EXTERN(int) git_object_lookup_prefix(
git_object **object_out,
git_repository *repo,
const git_oid *id,
- unsigned int len,
+ size_t len,
git_otype type);
/**
diff --git a/include/git2/odb.h b/include/git2/odb.h
index dac9e06a9..1919f61a0 100644
--- a/include/git2/odb.h
+++ b/include/git2/odb.h
@@ -139,7 +139,7 @@ GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *i
* GIT_ENOTFOUND if the object is not in the database.
* GIT_EAMBIGUOUS if the prefix is ambiguous (several objects match the prefix)
*/
-GIT_EXTERN(int) git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_id, unsigned int len);
+GIT_EXTERN(int) git_odb_read_prefix(git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len);
/**
* Read the header of an object from the database, without
@@ -176,13 +176,14 @@ GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id);
* List all objects available in the database
*
* The callback will be called for each object available in the
- * database. Note that the objects are likely to be returned in the
- * index order, which would make accessing the objects in that order
- * inefficient.
+ * database. Note that the objects are likely to be returned in the index
+ * order, which would make accessing the objects in that order inefficient.
+ * Return a non-zero value from the callback to stop looping.
*
* @param db database to use
* @param cb the callback to call for each object
* @param data data to pass to the callback
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_odb_foreach(git_odb *db, int (*cb)(git_oid *oid, void *data), void *data);
diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h
index 3f67202d1..b812fef1e 100644
--- a/include/git2/odb_backend.h
+++ b/include/git2/odb_backend.h
@@ -42,7 +42,7 @@ struct git_odb_backend {
void **, size_t *, git_otype *,
struct git_odb_backend *,
const git_oid *,
- unsigned int);
+ size_t);
int (* read_header)(
size_t *, git_otype *,
@@ -100,6 +100,7 @@ struct git_odb_stream {
GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir);
GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir, int compression_level, int do_fsync);
+GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **backend_out, const char *index_file);
GIT_END_DECL
diff --git a/include/git2/oid.h b/include/git2/oid.h
index a05b40a37..887b33e50 100644
--- a/include/git2/oid.h
+++ b/include/git2/oid.h
@@ -136,7 +136,31 @@ GIT_EXTERN(void) git_oid_cpy(git_oid *out, const git_oid *src);
* @param b second oid structure.
* @return <0, 0, >0 if a < b, a == b, a > b.
*/
-GIT_EXTERN(int) git_oid_cmp(const git_oid *a, const git_oid *b);
+GIT_INLINE(int) git_oid_cmp(const git_oid *a, const git_oid *b)
+{
+ const unsigned char *sha1 = a->id;
+ const unsigned char *sha2 = b->id;
+ int i;
+
+ for (i = 0; i < GIT_OID_RAWSZ; i++, sha1++, sha2++) {
+ if (*sha1 != *sha2)
+ return *sha1 - *sha2;
+ }
+
+ return 0;
+}
+
+/**
+ * Compare two oid structures for equality
+ *
+ * @param a first oid structure.
+ * @param b second oid structure.
+ * @return true if equal, false otherwise
+ */
+GIT_INLINE(int) git_oid_equal(const git_oid *a, const git_oid *b)
+{
+ return !git_oid_cmp(a, b);
+}
/**
* Compare the first 'len' hexadecimal characters (packets of 4 bits)
@@ -147,7 +171,7 @@ GIT_EXTERN(int) git_oid_cmp(const git_oid *a, const git_oid *b);
* @param len the number of hex chars to compare
* @return 0 in case of a match
*/
-GIT_EXTERN(int) git_oid_ncmp(const git_oid *a, const git_oid *b, unsigned int len);
+GIT_EXTERN(int) git_oid_ncmp(const git_oid *a, const git_oid *b, size_t len);
/**
* Check if an oid equals an hex formatted object id.
diff --git a/include/git2/reflog.h b/include/git2/reflog.h
index a73d1f7fd..447915ef8 100644
--- a/include/git2/reflog.h
+++ b/include/git2/reflog.h
@@ -92,7 +92,7 @@ GIT_EXTERN(unsigned int) git_reflog_entrycount(git_reflog *reflog);
* @param idx the position to lookup
* @return the entry; NULL if not found
*/
-GIT_EXTERN(const git_reflog_entry *) git_reflog_entry_byindex(git_reflog *reflog, unsigned int idx);
+GIT_EXTERN(const git_reflog_entry *) git_reflog_entry_byindex(git_reflog *reflog, size_t idx);
/**
* Remove an entry from the reflog by its index
diff --git a/include/git2/refs.h b/include/git2/refs.h
index 8dd8e3116..9e7060075 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -268,14 +268,15 @@ GIT_EXTERN(int) git_reference_list(git_strarray *array, git_repository *repo, un
*
* The `callback` function will be called for each of the references
* in the repository, and will receive the name of the reference and
- * the `payload` value passed to this method.
+ * the `payload` value passed to this method. Returning a non-zero
+ * value from the callback will terminate the iteration.
*
* @param repo Repository where to find the refs
* @param list_flags Filtering flags for the reference
* listing.
* @param callback Function which will be called for every listed ref
* @param payload Additional data to pass to the callback
- * @return 0 or an error code
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_reference_foreach(git_repository *repo, unsigned int list_flags, int (*callback)(const char *, void *), void *payload);
@@ -334,6 +335,8 @@ GIT_EXTERN(int) git_reference_cmp(git_reference *ref1, git_reference *ref2);
*
* @param repo Repository where to find the references.
*
+ * @param glob Glob pattern references should match.
+ *
* @param list_flags Filtering flags for the reference
* listing.
*
diff --git a/include/git2/remote.h b/include/git2/remote.h
index 7e563f96f..96f460e98 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -163,9 +163,12 @@ GIT_EXTERN(int) git_remote_connect(git_remote *remote, int direction);
* The remote (or more exactly its transport) must be connected. The
* memory belongs to the remote.
*
+ * If you a return a non-zero value from the callback, this will stop
+ * looping over the refs.
+ *
* @param refs where to store the refs
* @param remote the remote
- * @return 0 or an error code
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload);
diff --git a/include/git2/repository.h b/include/git2/repository.h
index ff81b75ec..e727ff317 100644
--- a/include/git2/repository.h
+++ b/include/git2/repository.h
@@ -36,6 +36,19 @@ GIT_BEGIN_DECL
GIT_EXTERN(int) git_repository_open(git_repository **repository, const char *path);
/**
+ * Create a "fake" repository to wrap an object database
+ *
+ * Create a repository object to wrap an object database to be used
+ * with the API when all you have is an object database. This doesn't
+ * have any paths associated with it, so use with care.
+ *
+ * @param repository pointer to the repo
+ * @param odb the object database to wrap
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_repository_wrap_odb(git_repository **repository, git_odb *odb);
+
+/**
* Look for a git repository and copy its path in the given buffer.
* The lookup start from base_path and walk across parent directories
* if nothing has been found. The lookup ends when the first repository
@@ -302,6 +315,28 @@ GIT_EXTERN(int) git_repository_index(git_index **out, git_repository *repo);
*/
GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index);
+/**
+ * Retrive git's prepared message
+ *
+ * Operations such as git revert/cherry-pick/merge with the -n option
+ * stop just short of creating a commit with the changes and save
+ * their prepared message in .git/MERGE_MSG so the next git-commit
+ * execution can present it to the user for them to amend if they
+ * wish.
+ *
+ * Use this function to get the contents of this file. Don't forget to
+ * remove the file after you create the commit.
+ */
+GIT_EXTERN(int) git_repository_message(char *buffer, size_t len, git_repository *repo);
+
+/**
+ * Remove git's prepared message.
+ *
+ * Remove the message that `git_repository_message` retrieves.
+ */
+GIT_EXTERN(int) git_repository_message_remove(git_repository *repo);
+
+
/** @} */
GIT_END_DECL
#endif
diff --git a/include/git2/status.h b/include/git2/status.h
index 9e7b5de4a..cc94d7680 100644
--- a/include/git2/status.h
+++ b/include/git2/status.h
@@ -38,11 +38,11 @@ enum {
*
* The callback is passed the path of the file, the status and the data
* pointer passed to this function. If the callback returns something other
- * than 0, this function will return that value.
+ * than 0, this function will stop looping and return GIT_EUSER.
*
* @param repo a repository object
* @param callback the function to call on each file
- * @return 0 on success or the return value of the callback that was non-zero
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_status_foreach(
git_repository *repo,
diff --git a/include/git2/tag.h b/include/git2/tag.h
index b522451a1..aab4b77a8 100644
--- a/include/git2/tag.h
+++ b/include/git2/tag.h
@@ -46,7 +46,7 @@ GIT_INLINE(int) git_tag_lookup(git_tag **tag, git_repository *repo, const git_oi
* @param len the length of the short identifier
* @return 0 or an error code
*/
-GIT_INLINE(int) git_tag_lookup_prefix(git_tag **tag, git_repository *repo, const git_oid *id, unsigned int len)
+GIT_INLINE(int) git_tag_lookup_prefix(git_tag **tag, git_repository *repo, const git_oid *id, size_t len)
{
return git_object_lookup_prefix((git_object **)tag, repo, id, len, (git_otype)GIT_OBJ_TAG);
}
diff --git a/include/git2/tree.h b/include/git2/tree.h
index f12b15e2e..85407d7ac 100644
--- a/include/git2/tree.h
+++ b/include/git2/tree.h
@@ -50,7 +50,7 @@ GIT_INLINE(int) git_tree_lookup_prefix(
git_tree **tree,
git_repository *repo,
const git_oid *id,
- unsigned int len)
+ size_t len)
{
return git_object_lookup_prefix((git_object **)tree, repo, id, len, GIT_OBJ_TREE);
}
@@ -126,7 +126,18 @@ GIT_EXTERN(const git_tree_entry *) git_tree_entry_byname(git_tree *tree, const c
* @param idx the position in the entry list
* @return the tree entry; NULL if not found
*/
-GIT_EXTERN(const git_tree_entry *) git_tree_entry_byindex(git_tree *tree, unsigned int idx);
+GIT_EXTERN(const git_tree_entry *) git_tree_entry_byindex(git_tree *tree, size_t idx);
+
+/**
+ * Lookup a tree entry by SHA value.
+ *
+ * Warning: this must examine every entry in the tree, so it is not fast.
+ *
+ * @param tree a previously loaded tree.
+ * @param oid the sha being looked for
+ * @return the tree entry; NULL if not found
+ */
+GIT_EXTERN(const git_tree_entry *) git_tree_entry_byoid(git_tree *tree, const git_oid *oid);
/**
* Get the UNIX file attributes of a tree entry
@@ -340,8 +351,9 @@ enum git_treewalk_mode {
* the current (relative) root for the entry and the entry
* data itself.
*
- * If the callback returns a negative value, the passed entry
- * will be skipped on the traversal.
+ * If the callback returns a positive value, the passed entry will be
+ * skipped on the traversal (in pre mode). A negative value stops the
+ * walk.
*
* @param tree The tree to walk
* @param callback Function to call on each tree entry
diff --git a/src/attr.c b/src/attr.c
index 6fbd005d5..de714a697 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -1,10 +1,30 @@
#include "repository.h"
#include "fileops.h"
#include "config.h"
+#include "git2/oid.h"
#include <ctype.h>
GIT__USE_STRMAP;
+const char *git_attr__true = "[internal]__TRUE__";
+const char *git_attr__false = "[internal]__FALSE__";
+const char *git_attr__unset = "[internal]__UNSET__";
+
+git_attr_t git_attr_value(const char *attr)
+{
+ if (attr == NULL || attr == git_attr__unset)
+ return GIT_ATTR_UNSPECIFIED_T;
+
+ if (attr == git_attr__true)
+ return GIT_ATTR_TRUE_T;
+
+ if (attr == git_attr__false)
+ return GIT_ATTR_FALSE_T;
+
+ return GIT_ATTR_VALUE_T;
+}
+
+
static int collect_attr_files(
git_repository *repo,
uint32_t flags,
@@ -22,7 +42,7 @@ int git_attr_get(
int error;
git_attr_path path;
git_vector files = GIT_VECTOR_INIT;
- unsigned int i, j;
+ size_t i, j;
git_attr_file *file;
git_attr_name attr;
git_attr_rule *rule;
@@ -74,7 +94,7 @@ int git_attr_get_many(
int error;
git_attr_path path;
git_vector files = GIT_VECTOR_INIT;
- unsigned int i, j, k;
+ size_t i, j, k;
git_attr_file *file;
git_attr_rule *rule;
attr_get_many_info *info = NULL;
@@ -138,7 +158,7 @@ int git_attr_foreach(
int error;
git_attr_path path;
git_vector files = GIT_VECTOR_INIT;
- unsigned int i, j, k;
+ size_t i, j, k;
git_attr_file *file;
git_attr_rule *rule;
git_attr_assignment *assign;
@@ -163,11 +183,14 @@ int git_attr_foreach(
continue;
git_strmap_insert(seen, assign->name, assign, error);
- if (error >= 0)
- error = callback(assign->name, assign->value, payload);
+ if (error < 0)
+ goto cleanup;
- if (error != 0)
+ error = callback(assign->name, assign->value, payload);
+ if (error) {
+ error = GIT_EUSER;
goto cleanup;
+ }
}
}
}
diff --git a/src/attr_file.c b/src/attr_file.c
index 837c42d8e..20b3cf631 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -5,10 +5,6 @@
#include "git2/tree.h"
#include <ctype.h>
-const char *git_l_attr__true = "[internal]__TRUE__";
-const char *git_l_attr__false = "[internal]__FALSE__";
-const char *git_l_attr__unset = "[internal]__UNSET__";
-
static int sort_by_hash_and_name(const void *a_raw, const void *b_raw);
static void git_attr_rule__clear(git_attr_rule *rule);
@@ -183,7 +179,7 @@ int git_attr_file__lookup_one(
const char *attr,
const char **value)
{
- unsigned int i;
+ size_t i;
git_attr_name name;
git_attr_rule *rule;
@@ -493,14 +489,14 @@ int git_attr_assignment__parse(
}
assign->name_hash = 5381;
- assign->value = git_l_attr__true;
+ assign->value = git_attr__true;
/* look for magic name prefixes */
if (*scan == '-') {
- assign->value = git_l_attr__false;
+ assign->value = git_attr__false;
scan++;
} else if (*scan == '!') {
- assign->value = git_l_attr__unset; /* explicit unspecified state */
+ assign->value = git_attr__unset; /* explicit unspecified state */
scan++;
} else if (*scan == '#') /* comment rest of line */
break;
@@ -536,7 +532,7 @@ int git_attr_assignment__parse(
}
/* expand macros (if given a repo with a macro cache) */
- if (repo != NULL && assign->value == git_l_attr__true) {
+ if (repo != NULL && assign->value == git_attr__true) {
git_attr_rule *macro =
git_attr_cache__lookup_macro(repo, assign->name);
diff --git a/src/attr_file.h b/src/attr_file.h
index 7939f838a..9d6730d90 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -24,6 +24,10 @@
#define GIT_ATTR_FNMATCH_HASWILD (1U << 5)
#define GIT_ATTR_FNMATCH_ALLOWSPACE (1U << 6)
+extern const char *git_attr__true;
+extern const char *git_attr__false;
+extern const char *git_attr__unset;
+
typedef struct {
char *pattern;
size_t length;
diff --git a/src/cache.c b/src/cache.c
index f8d89403b..3aa14f012 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -11,6 +11,7 @@
#include "thread-utils.h"
#include "util.h"
#include "cache.h"
+#include "git2/oid.h"
int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr)
{
diff --git a/src/commit.c b/src/commit.c
index 32c47944b..b66978aff 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -226,7 +226,7 @@ GIT_COMMIT_GETTER(const char *, message, commit->message)
GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding)
GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time)
GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)
-GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length)
+GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)commit->parent_oids.length)
GIT_COMMIT_GETTER(const git_oid *, tree_oid, &commit->tree_oid);
int git_commit_tree(git_tree **tree_out, git_commit *commit)
diff --git a/src/common.h b/src/common.h
index 1db308fc7..1d85428b3 100644
--- a/src/common.h
+++ b/src/common.h
@@ -59,4 +59,7 @@ void giterr_set_regex(const regex_t *regex, int error_code);
#include "util.h"
+typedef struct git_transport git_transport;
+typedef struct gitno_buffer gitno_buffer;
+
#endif /* INCLUDE_common_h__ */
diff --git a/src/config.c b/src/config.c
index 98fb3b20d..44cfe760c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -410,7 +410,7 @@ int git_config_get_multivar(git_config *cfg, const char *name, const char *regex
file_internal *internal;
git_config_file *file;
int ret = GIT_ENOTFOUND;
- unsigned int i;
+ size_t i;
assert(cfg->files.length);
@@ -434,7 +434,7 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex
file_internal *internal;
git_config_file *file;
int ret = GIT_ENOTFOUND;
- unsigned int i;
+ size_t i;
for (i = cfg->files.length; i > 0; --i) {
internal = git_vector_get(&cfg->files, i - 1);
diff --git a/src/config_file.c b/src/config_file.c
index 7ced1e5ba..547509b9f 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -218,8 +218,10 @@ static int file_foreach(
continue;
/* abort iterator on non-zero return value */
- if ((result = fn(key, var->value, data)) != 0)
+ if (fn(key, var->value, data)) {
+ result = GIT_EUSER;
goto cleanup;
+ }
}
);
@@ -1341,10 +1343,8 @@ static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_val
else
value_start = var_end + 1;
- if (git__isspace(var_end[-1])) {
- do var_end--;
- while (git__isspace(var_end[0]));
- }
+ do var_end--;
+ while (git__isspace(*var_end));
*var_name = git__strndup(line, var_end - line + 1);
GITERR_CHECK_ALLOC(*var_name);
diff --git a/src/date.c b/src/date.c
index f0e637a45..965e6caab 100644
--- a/src/date.c
+++ b/src/date.c
@@ -121,9 +121,9 @@ static const struct {
{ "IDLE", +12, 0, }, /* International Date Line East */
};
-static int match_string(const char *date, const char *str)
+static size_t match_string(const char *date, const char *str)
{
- int i = 0;
+ size_t i = 0;
for (i = 0; *date; date++, str++, i++) {
if (*date == *str)
@@ -149,12 +149,12 @@ static int skip_alpha(const char *date)
/*
* Parse month, weekday, or timezone name
*/
-static int match_alpha(const char *date, struct tm *tm, int *offset)
+static size_t match_alpha(const char *date, struct tm *tm, int *offset)
{
unsigned int i;
for (i = 0; i < 12; i++) {
- int match = match_string(date, month_names[i]);
+ size_t match = match_string(date, month_names[i]);
if (match >= 3) {
tm->tm_mon = i;
return match;
@@ -162,7 +162,7 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
}
for (i = 0; i < 7; i++) {
- int match = match_string(date, weekday_names[i]);
+ size_t match = match_string(date, weekday_names[i]);
if (match >= 3) {
tm->tm_wday = i;
return match;
@@ -170,8 +170,8 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
}
for (i = 0; i < ARRAY_SIZE(timezone_names); i++) {
- int match = match_string(date, timezone_names[i].name);
- if (match >= 3 || match == (int)strlen(timezone_names[i].name)) {
+ size_t match = match_string(date, timezone_names[i].name);
+ if (match >= 3 || match == strlen(timezone_names[i].name)) {
int off = timezone_names[i].offset;
/* This is bogus, but we like summer */
@@ -241,7 +241,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,
return 0;
}
-static int match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm)
+static size_t match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm)
{
time_t now;
struct tm now_tm;
@@ -319,9 +319,9 @@ static int nodate(struct tm *tm)
/*
* We've seen a digit. Time? Year? Date?
*/
-static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt)
+static size_t match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt)
{
- int n;
+ size_t n;
char *end;
unsigned long num;
@@ -349,7 +349,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
case '/':
case '-':
if (isdigit(end[1])) {
- int match = match_multi_number(num, *end, date, end, tm);
+ size_t match = match_multi_number(num, *end, date, end, tm);
if (match)
return match;
}
@@ -413,11 +413,11 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
return n;
}
-static int match_tz(const char *date, int *offp)
+static size_t match_tz(const char *date, int *offp)
{
char *end;
int hour = strtoul(date + 1, &end, 10);
- int n = end - (date + 1);
+ size_t n = end - (date + 1);
int min = 0;
if (n == 4) {
@@ -506,7 +506,7 @@ static int parse_date_basic(const char *date, git_time_t *timestamp, int *offset
!match_object_header_date(date + 1, timestamp, offset))
return 0; /* success */
for (;;) {
- int match = 0;
+ size_t match = 0;
unsigned char c = *date;
/* Stop at end of string or newline */
@@ -685,7 +685,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
;
for (i = 0; i < 12; i++) {
- int match = match_string(date, month_names[i]);
+ size_t match = match_string(date, month_names[i]);
if (match >= 3) {
tm->tm_mon = i;
*touched = 1;
@@ -694,7 +694,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
}
for (s = special; s->name; s++) {
- int len = strlen(s->name);
+ size_t len = strlen(s->name);
if (match_string(date, s->name) == len) {
s->fn(tm, now, num);
*touched = 1;
@@ -704,7 +704,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
if (!*num) {
for (i = 1; i < 11; i++) {
- int len = strlen(number_name[i]);
+ size_t len = strlen(number_name[i]);
if (match_string(date, number_name[i]) == len) {
*num = i;
*touched = 1;
@@ -720,7 +720,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
tl = typelen;
while (tl->type) {
- int len = strlen(tl->type);
+ size_t len = strlen(tl->type);
if (match_string(date, tl->type) >= len-1) {
update_tm(tm, now, tl->length * *num);
*num = 0;
@@ -731,7 +731,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
}
for (i = 0; i < 7; i++) {
- int match = match_string(date, weekday_names[i]);
+ size_t match = match_string(date, weekday_names[i]);
if (match >= 3) {
int diff, n = *num -1;
*num = 0;
@@ -783,7 +783,7 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
case '/':
case '-':
if (isdigit(end[1])) {
- int match = match_multi_number(number, *end, date, end, tm);
+ size_t match = match_multi_number(number, *end, date, end, tm);
if (match)
return date + match;
}
diff --git a/src/diff.c b/src/diff.c
index 2b1529d63..a5bf07a65 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
#include "git2/diff.h"
+#include "git2/oid.h"
#include "diff.h"
#include "fileops.h"
#include "config.h"
diff --git a/src/diff_output.c b/src/diff_output.c
index f6650b345..bd8e8edda 100644
--- a/src/diff_output.c
+++ b/src/diff_output.c
@@ -8,6 +8,7 @@
#include "git2/diff.h"
#include "git2/attr.h"
#include "git2/blob.h"
+#include "git2/oid.h"
#include "xdiff/xdiff.h"
#include <ctype.h>
#include "diff.h"
@@ -23,6 +24,7 @@ typedef struct {
unsigned int index;
git_diff_delta *delta;
git_diff_range range;
+ int error;
} diff_output_info;
static int read_next_int(const char **str, int *value)
@@ -49,25 +51,24 @@ static int diff_output_cb(void *priv, mmbuffer_t *bufs, int len)
/* expect something of the form "@@ -%d[,%d] +%d[,%d] @@" */
if (*scan != '@')
- return -1;
-
- if (read_next_int(&scan, &range.old_start) < 0)
- return -1;
- if (*scan == ',' && read_next_int(&scan, &range.old_lines) < 0)
- return -1;
-
- if (read_next_int(&scan, &range.new_start) < 0)
- return -1;
- if (*scan == ',' && read_next_int(&scan, &range.new_lines) < 0)
- return -1;
-
- if (range.old_start < 0 || range.new_start < 0)
- return -1;
-
- memcpy(&info->range, &range, sizeof(git_diff_range));
-
- return info->hunk_cb(
- info->cb_data, info->delta, &range, bufs[0].ptr, bufs[0].size);
+ info->error = -1;
+ else if (read_next_int(&scan, &range.old_start) < 0)
+ info->error = -1;
+ else if (*scan == ',' && read_next_int(&scan, &range.old_lines) < 0)
+ info->error = -1;
+ else if (read_next_int(&scan, &range.new_start) < 0)
+ info->error = -1;
+ else if (*scan == ',' && read_next_int(&scan, &range.new_lines) < 0)
+ info->error = -1;
+ else if (range.old_start < 0 || range.new_start < 0)
+ info->error = -1;
+ else {
+ memcpy(&info->range, &range, sizeof(git_diff_range));
+
+ if (info->hunk_cb(
+ info->cb_data, info->delta, &range, bufs[0].ptr, bufs[0].size))
+ info->error = GIT_EUSER;
+ }
}
if ((len == 2 || len == 3) && info->line_cb) {
@@ -80,23 +81,24 @@ static int diff_output_cb(void *priv, mmbuffer_t *bufs, int len)
GIT_DIFF_LINE_CONTEXT;
if (info->line_cb(
- info->cb_data, info->delta, &info->range, origin, bufs[1].ptr, bufs[1].size) < 0)
- return -1;
+ info->cb_data, info->delta, &info->range, origin, bufs[1].ptr, bufs[1].size))
+ info->error = GIT_EUSER;
/* This should only happen if we are adding a line that does not
* have a newline at the end and the old code did. In that case,
* we have a ADD with a DEL_EOFNL as a pair.
*/
- if (len == 3) {
+ else if (len == 3) {
origin = (origin == GIT_DIFF_LINE_ADDITION) ?
GIT_DIFF_LINE_DEL_EOFNL : GIT_DIFF_LINE_ADD_EOFNL;
- return info->line_cb(
- info->cb_data, info->delta, &info->range, origin, bufs[2].ptr, bufs[2].size);
+ if (info->line_cb(
+ info->cb_data, info->delta, &info->range, origin, bufs[2].ptr, bufs[2].size))
+ info->error = GIT_EUSER;
}
}
- return 0;
+ return info->error;
}
#define BINARY_DIFF_FLAGS (GIT_DIFF_FILE_BINARY|GIT_DIFF_FILE_NOT_BINARY)
@@ -318,6 +320,7 @@ int git_diff_foreach(
xdemitconf_t xdiff_config;
xdemitcb_t xdiff_callback;
+ memset(&info, 0, sizeof(info));
info.diff = diff;
info.cb_data = data;
info.hunk_cb = hunk_cb;
@@ -422,11 +425,11 @@ int git_diff_foreach(
* diffs to tell if a file has really been changed.
*/
- if (file_cb != NULL) {
- error = file_cb(
- data, delta, (float)info.index / diff->deltas.length);
- if (error < 0)
- goto cleanup;
+ if (file_cb != NULL &&
+ file_cb(data, delta, (float)info.index / diff->deltas.length))
+ {
+ error = GIT_EUSER;
+ goto cleanup;
}
/* don't do hunk and line diffs if file is binary */
@@ -451,6 +454,7 @@ int git_diff_foreach(
xdl_diff(&old_xdiff_data, &new_xdiff_data,
&xdiff_params, &xdiff_config, &xdiff_callback);
+ error = info.error;
cleanup:
release_content(&delta->old_file, &old_data, old_blob);
@@ -524,7 +528,11 @@ static int print_compact(void *data, git_diff_delta *delta, float progress)
if (git_buf_oom(pi->buf))
return -1;
- return pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf));
+ if (pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_FILE_HDR,
+ git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
+ return GIT_EUSER;
+
+ return 0;
}
int git_diff_print_compact(
@@ -586,7 +594,6 @@ static int print_patch_file(void *data, git_diff_delta *delta, float progress)
const char *oldpath = delta->old_file.path;
const char *newpfx = pi->diff->opts.new_prefix;
const char *newpath = delta->new_file.path;
- int result;
GIT_UNUSED(progress);
@@ -619,9 +626,8 @@ static int print_patch_file(void *data, git_diff_delta *delta, float progress)
if (git_buf_oom(pi->buf))
return -1;
- result = pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf));
- if (result < 0)
- return result;
+ if (pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
+ return GIT_EUSER;
if (delta->binary != 1)
return 0;
@@ -633,7 +639,11 @@ static int print_patch_file(void *data, git_diff_delta *delta, float progress)
if (git_buf_oom(pi->buf))
return -1;
- return pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_BINARY, git_buf_cstr(pi->buf), git_buf_len(pi->buf));
+ if (pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_BINARY,
+ git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
+ return GIT_EUSER;
+
+ return 0;
}
static int print_patch_hunk(
@@ -649,7 +659,11 @@ static int print_patch_hunk(
if (git_buf_printf(pi->buf, "%.*s", (int)header_len, header) < 0)
return -1;
- return pi->print_cb(pi->cb_data, d, r, GIT_DIFF_LINE_HUNK_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf));
+ if (pi->print_cb(pi->cb_data, d, r, GIT_DIFF_LINE_HUNK_HDR,
+ git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
+ return GIT_EUSER;
+
+ return 0;
}
static int print_patch_line(
@@ -674,7 +688,11 @@ static int print_patch_line(
if (git_buf_oom(pi->buf))
return -1;
- return pi->print_cb(pi->cb_data, delta, range, line_origin, git_buf_cstr(pi->buf), git_buf_len(pi->buf));
+ if (pi->print_cb(pi->cb_data, delta, range, line_origin,
+ git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
+ return GIT_EUSER;
+
+ return 0;
}
int git_diff_print_patch(
@@ -763,11 +781,8 @@ int git_diff_blobs(
if (file_is_binary_by_content(&delta, &old_map, &new_map) < 0)
return -1;
- if (file_cb != NULL) {
- int error = file_cb(cb_data, &delta, 1);
- if (error < 0)
- return error;
- }
+ if (file_cb != NULL && file_cb(cb_data, &delta, 1))
+ return GIT_EUSER;
/* don't do hunk and line diffs if the two blobs are identical */
if (delta.status == GIT_DELTA_UNMODIFIED)
@@ -777,6 +792,7 @@ int git_diff_blobs(
if (delta.binary == 1)
return 0;
+ memset(&info, 0, sizeof(info));
info.diff = NULL;
info.delta = &delta;
info.cb_data = cb_data;
@@ -790,5 +806,5 @@ int git_diff_blobs(
xdl_diff(&old_data, &new_data, &xdiff_params, &xdiff_config, &xdiff_callback);
- return 0;
+ return info.error;
}
diff --git a/src/fetch.c b/src/fetch.c
index 603284842..d96ac7781 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -5,7 +5,6 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "git2/remote.h"
#include "git2/oid.h"
#include "git2/refs.h"
#include "git2/revwalk.h"
@@ -18,6 +17,7 @@
#include "pack.h"
#include "fetch.h"
#include "netops.h"
+#include "pkt.h"
struct filter_payload {
git_remote *remote;
@@ -70,7 +70,62 @@ static int filter_wants(git_remote *remote)
if (git_repository_odb__weakptr(&p.odb, remote->repo) < 0)
return -1;
- return remote->transport->ls(remote->transport, &filter_ref__cb, &p);
+ return git_remote_ls(remote, filter_ref__cb, &p);
+}
+
+/* Wait until we get an ack from the */
+static int recv_pkt(git_pkt **out, gitno_buffer *buf)
+{
+ const char *ptr = buf->data, *line_end = ptr;
+ git_pkt *pkt;
+ int pkt_type, error = 0, ret;
+
+ do {
+ if (buf->offset > 0)
+ error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
+ else
+ error = GIT_EBUFS;
+
+ if (error == 0)
+ break; /* return the pkt */
+
+ if (error < 0 && error != GIT_EBUFS)
+ return -1;
+
+ if ((ret = gitno_recv(buf)) < 0)
+ return -1;
+ } while (error);
+
+ gitno_consume(buf, line_end);
+ pkt_type = pkt->type;
+ if (out != NULL)
+ *out = pkt;
+ else
+ git__free(pkt);
+
+ return pkt_type;
+}
+
+static int store_common(git_transport *t)
+{
+ git_pkt *pkt = NULL;
+ gitno_buffer *buf = &t->buffer;
+
+ do {
+ if (recv_pkt(&pkt, buf) < 0)
+ return -1;
+
+ if (pkt->type == GIT_PKT_ACK) {
+ if (git_vector_insert(&t->common, pkt) < 0)
+ return -1;
+ } else {
+ git__free(pkt);
+ return 0;
+ }
+
+ } while (1);
+
+ return 0;
}
/*
@@ -81,6 +136,12 @@ static int filter_wants(git_remote *remote)
int git_fetch_negotiate(git_remote *remote)
{
git_transport *t = remote->transport;
+ gitno_buffer *buf = &t->buffer;
+ git_buf data = GIT_BUF_INIT;
+ git_revwalk *walk = NULL;
+ int error, pkt_type;
+ unsigned int i;
+ git_oid oid;
if (filter_wants(remote) < 0) {
giterr_set(GITERR_NET, "Failed to filter the reference list for wants");
@@ -92,60 +153,174 @@ int git_fetch_negotiate(git_remote *remote)
return 0;
/*
- * Now we have everything set up so we can start tell the server
- * what we want and what we have.
+ * Now we have everything set up so we can start tell the
+ * server what we want and what we have. Call the function if
+ * the transport has its own logic. This is transitional and
+ * will be removed once this function can support git and http.
*/
- return t->negotiate_fetch(t, remote->repo, &remote->refs);
+ if (t->own_logic)
+ return t->negotiate_fetch(t, remote->repo, &remote->refs);
+
+ /* No own logic, do our thing */
+ if (git_pkt_buffer_wants(&remote->refs, &t->caps, &data) < 0)
+ return -1;
+
+ if (git_fetch_setup_walk(&walk, remote->repo) < 0)
+ goto on_error;
+ /*
+ * We don't support any kind of ACK extensions, so the negotiation
+ * boils down to sending what we have and listening for an ACK
+ * every once in a while.
+ */
+ i = 0;
+ while ((error = git_revwalk_next(&oid, walk)) == 0) {
+ git_pkt_buffer_have(&oid, &data);
+ i++;
+ if (i % 20 == 0) {
+ git_pkt_buffer_flush(&data);
+ if (git_buf_oom(&data))
+ goto on_error;
+
+ if (t->negotiation_step(t, data.ptr, data.size) < 0)
+ goto on_error;
+
+ git_buf_clear(&data);
+ if (t->caps.multi_ack) {
+ if (store_common(t) < 0)
+ goto on_error;
+ } else {
+ pkt_type = recv_pkt(NULL, buf);
+
+ if (pkt_type == GIT_PKT_ACK) {
+ break;
+ } else if (pkt_type == GIT_PKT_NAK) {
+ continue;
+ } else {
+ giterr_set(GITERR_NET, "Unexpected pkt type");
+ goto on_error;
+ }
+ }
+ }
+
+ if (t->common.length > 0)
+ break;
+
+ if (i % 20 == 0 && t->rpc) {
+ git_pkt_ack *pkt;
+ unsigned int i;
+
+ if (git_pkt_buffer_wants(&remote->refs, &t->caps, &data) < 0)
+ goto on_error;
+
+ git_vector_foreach(&t->common, i, pkt) {
+ git_pkt_buffer_have(&pkt->oid, &data);
+ }
+
+ if (git_buf_oom(&data))
+ goto on_error;
+ }
+ }
+
+ if (error < 0 && error != GIT_REVWALKOVER)
+ goto on_error;
+
+ /* Tell the other end that we're done negotiating */
+ if (t->rpc && t->common.length > 0) {
+ git_pkt_ack *pkt;
+ unsigned int i;
+
+ if (git_pkt_buffer_wants(&remote->refs, &t->caps, &data) < 0)
+ goto on_error;
+
+ git_vector_foreach(&t->common, i, pkt) {
+ git_pkt_buffer_have(&pkt->oid, &data);
+ }
+
+ if (git_buf_oom(&data))
+ goto on_error;
+ }
+
+ git_pkt_buffer_done(&data);
+ if (t->negotiation_step(t, data.ptr, data.size) < 0)
+ goto on_error;
+
+ git_buf_free(&data);
+ git_revwalk_free(walk);
+
+ /* Now let's eat up whatever the server gives us */
+ if (!t->caps.multi_ack) {
+ pkt_type = recv_pkt(NULL, buf);
+ if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) {
+ giterr_set(GITERR_NET, "Unexpected pkt type");
+ return -1;
+ }
+ } else {
+ git_pkt_ack *pkt;
+ do {
+ if (recv_pkt((git_pkt **)&pkt, buf) < 0)
+ return -1;
+
+ if (pkt->type == GIT_PKT_NAK ||
+ (pkt->type == GIT_PKT_ACK && pkt->status != GIT_ACK_CONTINUE)) {
+ git__free(pkt);
+ break;
+ }
+
+ git__free(pkt);
+ } while (1);
+ }
+
+ return 0;
+
+on_error:
+ git_revwalk_free(walk);
+ git_buf_free(&data);
+ return -1;
}
int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats)
{
+ git_transport *t = remote->transport;
+
if(!remote->need_pack)
return 0;
- return remote->transport->download_pack(remote->transport, remote->repo, bytes, stats);
+ if (t->own_logic)
+ return t->download_pack(t, remote->repo, bytes, stats);
+
+ return git_fetch__download_pack(t, remote->repo, bytes, stats);
+
}
/* Receiving data from a socket and storing it is pretty much the same for git and HTTP */
int git_fetch__download_pack(
- const char *buffered,
- size_t buffered_size,
git_transport *t,
git_repository *repo,
git_off_t *bytes,
git_indexer_stats *stats)
{
int recvd;
- char buff[1024];
- gitno_buffer buf;
git_buf path = GIT_BUF_INIT;
+ gitno_buffer *buf = &t->buffer;
git_indexer_stream *idx = NULL;
- gitno_buffer_setup(t, &buf, buff, sizeof(buff));
-
- if (memcmp(buffered, "PACK", strlen("PACK"))) {
- giterr_set(GITERR_NET, "The pack doesn't start with the signature");
- return -1;
- }
-
if (git_buf_joinpath(&path, git_repository_path(repo), "objects/pack") < 0)
return -1;
if (git_indexer_stream_new(&idx, git_buf_cstr(&path)) < 0)
goto on_error;
+ git_buf_free(&path);
memset(stats, 0, sizeof(git_indexer_stats));
- if (git_indexer_stream_add(idx, buffered, buffered_size, stats) < 0)
- goto on_error;
-
- *bytes = buffered_size;
+ *bytes = 0;
do {
- if (git_indexer_stream_add(idx, buf.data, buf.offset, stats) < 0)
+ if (git_indexer_stream_add(idx, buf->data, buf->offset, stats) < 0)
goto on_error;
- gitno_consume_n(&buf, buf.offset);
- if ((recvd = gitno_recv(&buf)) < 0)
+ gitno_consume_n(buf, buf->offset);
+
+ if ((recvd = gitno_recv(buf)) < 0)
goto on_error;
*bytes += recvd;
diff --git a/src/fetch.h b/src/fetch.h
index a7f126520..87bb43b07 100644
--- a/src/fetch.h
+++ b/src/fetch.h
@@ -12,8 +12,7 @@
int git_fetch_negotiate(git_remote *remote);
int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats);
-int git_fetch__download_pack(const char *buffered, size_t buffered_size, git_transport *t,
- git_repository *repo, git_off_t *bytes, git_indexer_stats *stats);
+int git_fetch__download_pack(git_transport *t, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats);
int git_fetch_setup_walk(git_revwalk **out, git_repository *repo);
#endif
diff --git a/src/filebuf.c b/src/filebuf.c
index 876f8e3e7..8b3ebb3e2 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -319,10 +319,15 @@ int git_filebuf_commit(git_filebuf *file, mode_t mode)
if (verify_last_error(file) < 0)
goto on_error;
- p_close(file->fd);
- file->fd = -1;
file->fd_is_open = false;
+ if (p_close(file->fd) < 0) {
+ giterr_set(GITERR_OS, "Failed to close file at '%s'", file->path_lock);
+ goto on_error;
+ }
+
+ file->fd = -1;
+
if (p_chmod(file->path_lock, mode)) {
giterr_set(GITERR_OS, "Failed to set attributes for file at '%s'", file->path_lock);
goto on_error;
diff --git a/src/fileops.c b/src/fileops.c
index bc58a0572..4de58b0cc 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -424,6 +424,7 @@ int git_futils_find_system_file(git_buf *path, const char *filename)
}
if (win32_find_file(path, &root, filename) < 0) {
+ giterr_set(GITERR_OS, "The system file '%s' doesn't exist", filename);
git_buf_clear(path);
return GIT_ENOTFOUND;
}
@@ -438,6 +439,7 @@ int git_futils_find_system_file(git_buf *path, const char *filename)
return 0;
git_buf_clear(path);
+ giterr_set(GITERR_OS, "The system file '%s' doesn't exist", filename);
return GIT_ENOTFOUND;
#endif
}
@@ -455,6 +457,7 @@ int git_futils_find_global_file(git_buf *path, const char *filename)
}
if (win32_find_file(path, &root, filename) < 0) {
+ giterr_set(GITERR_OS, "The global file '%s' doesn't exist", filename);
git_buf_clear(path);
return GIT_ENOTFOUND;
}
@@ -473,6 +476,7 @@ int git_futils_find_global_file(git_buf *path, const char *filename)
return -1;
if (git_path_exists(path->ptr) == false) {
+ giterr_set(GITERR_OS, "The global file '%s' doesn't exist", filename);
git_buf_clear(path);
return GIT_ENOTFOUND;
}
diff --git a/src/ignore.c b/src/ignore.c
index f2d08f59e..93d979f1a 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -156,7 +156,7 @@ void git_ignore__free(git_ignores *ignores)
static bool ignore_lookup_in_rules(
git_vector *rules, git_attr_path *path, int *ignored)
{
- unsigned int j;
+ size_t j;
git_attr_fnmatch *match;
git_vector_rforeach(rules, j, match) {
diff --git a/src/index.c b/src/index.c
index 5f6206554..a1042b723 100644
--- a/src/index.c
+++ b/src/index.c
@@ -14,6 +14,7 @@
#include "tree-cache.h"
#include "hash.h"
#include "git2/odb.h"
+#include "git2/oid.h"
#include "git2/blob.h"
#include "git2/config.h"
@@ -329,16 +330,16 @@ int git_index_write(git_index *index)
unsigned int git_index_entrycount(git_index *index)
{
assert(index);
- return index->entries.length;
+ return (unsigned int)index->entries.length;
}
unsigned int git_index_entrycount_unmerged(git_index *index)
{
assert(index);
- return index->unmerged.length;
+ return (unsigned int)index->unmerged.length;
}
-git_index_entry *git_index_get(git_index *index, unsigned int n)
+git_index_entry *git_index_get(git_index *index, size_t n)
{
git_vector_sort(&index->entries);
return git_vector_get(&index->entries, n);
@@ -584,7 +585,7 @@ const git_index_entry_unmerged *git_index_get_unmerged_bypath(
}
const git_index_entry_unmerged *git_index_get_unmerged_byindex(
- git_index *index, unsigned int n)
+ git_index *index, size_t n)
{
assert(index);
return git_vector_get(&index->unmerged, n);
@@ -963,7 +964,7 @@ static int write_index(git_index *index, git_filebuf *file)
header.signature = htonl(INDEX_HEADER_SIG);
header.version = htonl(is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER);
- header.entry_count = htonl(index->entries.length);
+ header.entry_count = htonl((uint32_t)index->entries.length);
if (git_filebuf_write(file, &header, sizeof(struct index_header)) < 0)
return -1;
diff --git a/src/message.c b/src/message.c
index a4aadb28f..e6dedc9fb 100644
--- a/src/message.c
+++ b/src/message.c
@@ -62,21 +62,25 @@ int git_message__prettify(git_buf *message_out, const char *message, int strip_c
int git_message_prettify(char *message_out, size_t buffer_size, const char *message, int strip_comments)
{
git_buf buf = GIT_BUF_INIT;
+ ssize_t out_size = -1;
- if (strlen(message) + 1 > buffer_size) { /* We have to account for a potentially missing \n */
+ if (message_out && buffer_size)
+ *message_out = '\0';
+
+ if (git_message__prettify(&buf, message, strip_comments) < 0)
+ goto done;
+
+ if (message_out && buf.size + 1 > buffer_size) { /* +1 for NUL byte */
giterr_set(GITERR_INVALID, "Buffer too short to hold the cleaned message");
- return -1;
+ goto done;
}
- *message_out = '\0';
+ if (message_out)
+ git_buf_copy_cstr(message_out, buffer_size, &buf);
- if (git_message__prettify(&buf, message, strip_comments) < 0) {
- git_buf_free(&buf);
- return -1;
- }
+ out_size = buf.size + 1;
- git_buf_copy_cstr(message_out, buffer_size, &buf);
+done:
git_buf_free(&buf);
-
- return 0;
+ return out_size;
}
diff --git a/src/netops.c b/src/netops.c
index b369e5106..49a0308bb 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -61,63 +61,72 @@ static int ssl_set_error(gitno_ssl *ssl, int error)
}
#endif
-void gitno_buffer_setup(git_transport *t, gitno_buffer *buf, char *data, unsigned int len)
+int gitno_recv(gitno_buffer *buf)
{
- memset(buf, 0x0, sizeof(gitno_buffer));
- memset(data, 0x0, len);
- buf->data = data;
- buf->len = len;
- buf->offset = 0;
- buf->fd = t->socket;
-#ifdef GIT_SSL
- if (t->encrypt)
- buf->ssl = &t->ssl;
-#endif
+ return buf->recv(buf);
}
#ifdef GIT_SSL
-static int ssl_recv(gitno_ssl *ssl, void *data, size_t len)
+static int gitno__recv_ssl(gitno_buffer *buf)
{
int ret;
do {
- ret = SSL_read(ssl->ssl, data, len);
- } while (SSL_get_error(ssl->ssl, ret) == SSL_ERROR_WANT_READ);
+ ret = SSL_read(buf->ssl->ssl, buf->data + buf->offset, buf->len - buf->offset);
+ } while (SSL_get_error(buf->ssl->ssl, ret) == SSL_ERROR_WANT_READ);
- if (ret < 0)
- return ssl_set_error(ssl, ret);
+ if (ret < 0) {
+ net_set_error("Error receiving socket data");
+ return -1;
+ }
+ buf->offset += ret;
return ret;
}
#endif
-int gitno_recv(gitno_buffer *buf)
+int gitno__recv(gitno_buffer *buf)
{
int ret;
-#ifdef GIT_SSL
- if (buf->ssl != NULL) {
- if ((ret = ssl_recv(buf->ssl, buf->data + buf->offset, buf->len - buf->offset)) < 0)
- return -1;
- } else {
- ret = p_recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0);
- if (ret < 0) {
- net_set_error("Error receiving socket data");
- return -1;
- }
- }
-#else
ret = p_recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0);
if (ret < 0) {
net_set_error("Error receiving socket data");
return -1;
}
-#endif
buf->offset += ret;
return ret;
}
+void gitno_buffer_setup_callback(
+ git_transport *t,
+ gitno_buffer *buf,
+ char *data,
+ size_t len,
+ int (*recv)(gitno_buffer *buf), void *cb_data)
+{
+ memset(buf, 0x0, sizeof(gitno_buffer));
+ memset(data, 0x0, len);
+ buf->data = data;
+ buf->len = len;
+ buf->offset = 0;
+ buf->fd = t->socket;
+ buf->recv = recv;
+ buf->cb_data = cb_data;
+}
+
+void gitno_buffer_setup(git_transport *t, gitno_buffer *buf, char *data, size_t len)
+{
+#ifdef GIT_SSL
+ if (t->use_ssl) {
+ gitno_buffer_setup_callback(t, buf, data, len, gitno__recv_ssl, NULL);
+ buf->ssl = &t->ssl;
+ } else
+#endif
+ gitno_buffer_setup_callback(t, buf, data, len, gitno__recv, NULL);
+}
+
/* Consume up to ptr and move the rest of the buffer to the beginning */
void gitno_consume(gitno_buffer *buf, const char *ptr)
{
@@ -147,7 +156,7 @@ int gitno_ssl_teardown(git_transport *t)
int ret;
#endif
- if (!t->encrypt)
+ if (!t->use_ssl)
return 0;
#ifdef GIT_SSL
@@ -415,7 +424,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port)
t->socket = s;
p_freeaddrinfo(info);
- if (t->encrypt && ssl_setup(t, host) < 0)
+ if (t->use_ssl && ssl_setup(t, host) < 0)
return -1;
return 0;
@@ -445,7 +454,7 @@ int gitno_send(git_transport *t, const char *msg, size_t len, int flags)
size_t off = 0;
#ifdef GIT_SSL
- if (t->encrypt)
+ if (t->use_ssl)
return send_ssl(&t->ssl, msg, len);
#endif
diff --git a/src/netops.h b/src/netops.h
index 4976f87f8..7c53fd0dc 100644
--- a/src/netops.h
+++ b/src/netops.h
@@ -8,10 +8,9 @@
#define INCLUDE_netops_h__
#include "posix.h"
-#include "transport.h"
#include "common.h"
-typedef struct gitno_buffer {
+struct gitno_buffer {
char *data;
size_t len;
size_t offset;
@@ -19,10 +18,14 @@ typedef struct gitno_buffer {
#ifdef GIT_SSL
struct gitno_ssl *ssl;
#endif
-} gitno_buffer;
+ int (*recv)(gitno_buffer *buffer);
+ void *cb_data;
+};
-void gitno_buffer_setup(git_transport *t, gitno_buffer *buf, char *data, unsigned int len);
+void gitno_buffer_setup(git_transport *t, gitno_buffer *buf, char *data, size_t len);
+void gitno_buffer_setup_callback(git_transport *t, gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data);
int gitno_recv(gitno_buffer *buf);
+int gitno__recv(gitno_buffer *buf);
void gitno_consume(gitno_buffer *buf, const char *ptr);
void gitno_consume_n(gitno_buffer *buf, size_t cons);
diff --git a/src/notes.c b/src/notes.c
index 7813e9985..6f9e7779d 100644
--- a/src/notes.c
+++ b/src/notes.c
@@ -522,13 +522,14 @@ static int process_entry_path(
int (*note_cb)(git_note_data *note_data, void *payload),
void *payload)
{
- int i = 0, j = 0, error = -1, len;
+ int error = -1;
+ size_t i = 0, j = 0, len;
git_buf buf = GIT_BUF_INIT;
git_note_data note_data;
- if (git_buf_puts(&buf, entry_path) < 0)
+ if ((error = git_buf_puts(&buf, entry_path)) < 0)
goto cleanup;
-
+
len = git_buf_len(&buf);
while (i < len) {
@@ -536,10 +537,9 @@ static int process_entry_path(
i++;
continue;
}
-
+
if (git__fromhex(buf.ptr[i]) < 0) {
/* This is not a note entry */
- error = 0;
goto cleanup;
}
@@ -555,16 +555,17 @@ static int process_entry_path(
if (j != GIT_OID_HEXSZ) {
/* This is not a note entry */
- error = 0;
goto cleanup;
}
- if (git_oid_fromstr(&note_data.annotated_object_oid, buf.ptr) < 0)
- return -1;
+ if ((error = git_oid_fromstr(
+ &note_data.annotated_object_oid, buf.ptr)) < 0)
+ goto cleanup;
git_oid_cpy(&note_data.blob_oid, note_oid);
- error = note_cb(&note_data, payload);
+ if (note_cb(&note_data, payload))
+ error = GIT_EUSER;
cleanup:
git_buf_free(&buf);
@@ -577,34 +578,27 @@ int git_note_foreach(
int (*note_cb)(git_note_data *note_data, void *payload),
void *payload)
{
- int error = -1;
+ int error;
git_iterator *iter = NULL;
git_tree *tree = NULL;
git_commit *commit = NULL;
const git_index_entry *item;
- if ((error = retrieve_note_tree_and_commit(&tree, &commit, repo, &notes_ref)) < 0)
- goto cleanup;
-
- if (git_iterator_for_tree(&iter, repo, tree) < 0)
- goto cleanup;
-
- if (git_iterator_current(iter, &item) < 0)
- goto cleanup;
+ if (!(error = retrieve_note_tree_and_commit(
+ &tree, &commit, repo, &notes_ref)) &&
+ !(error = git_iterator_for_tree(&iter, repo, tree)))
+ error = git_iterator_current(iter, &item);
- while (item) {
- if (process_entry_path(item->path, &item->oid, note_cb, payload) < 0)
- goto cleanup;
+ while (!error && item) {
+ error = process_entry_path(item->path, &item->oid, note_cb, payload);
- if (git_iterator_advance(iter, &item) < 0)
- goto cleanup;
+ if (!error)
+ error = git_iterator_advance(iter, &item);
}
- error = 0;
-
-cleanup:
git_iterator_free(iter);
git_tree_free(tree);
git_commit_free(commit);
+
return error;
}
diff --git a/src/object.c b/src/object.c
index 3ff894212..227774047 100644
--- a/src/object.c
+++ b/src/object.c
@@ -81,7 +81,7 @@ int git_object_lookup_prefix(
git_object **object_out,
git_repository *repo,
const git_oid *id,
- unsigned int len,
+ size_t len,
git_otype type)
{
git_object *object = NULL;
diff --git a/src/odb.c b/src/odb.c
index 493c8292a..d5902840d 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -14,6 +14,7 @@
#include "delta-apply.h"
#include "git2/odb_backend.h"
+#include "git2/oid.h"
#define GIT_ALTERNATES_FILE "info/alternates"
@@ -553,7 +554,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
}
int git_odb_read_prefix(
- git_odb_object **out, git_odb *db, const git_oid *short_id, unsigned int len)
+ git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len)
{
unsigned int i;
int error = GIT_ENOTFOUND;
@@ -609,9 +610,12 @@ int git_odb_foreach(git_odb *db, int (*cb)(git_oid *oid, void *data), void *data
{
unsigned int i;
backend_internal *internal;
+
git_vector_foreach(&db->backends, i, internal) {
git_odb_backend *b = internal->backend;
- b->foreach(b, cb, data);
+ int error = b->foreach(b, cb, data);
+ if (error < 0)
+ return error;
}
return 0;
diff --git a/src/odb_loose.c b/src/odb_loose.c
index 2197a4264..41121ae10 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -42,7 +42,7 @@ typedef struct loose_backend {
typedef struct {
size_t dir_len;
unsigned char short_oid[GIT_OID_HEXSZ]; /* hex formatted oid to match */
- unsigned int short_oid_len;
+ size_t short_oid_len;
int found; /* number of matching
* objects already found */
unsigned char res_oid[GIT_OID_HEXSZ]; /* hex formatted oid of
@@ -502,7 +502,7 @@ static int locate_object_short_oid(
git_oid *res_oid,
loose_backend *backend,
const git_oid *short_oid,
- unsigned int len)
+ size_t len)
{
char *objects_dir = backend->objects_dir;
size_t dir_len = strlen(objects_dir);
@@ -629,7 +629,7 @@ static int loose_backend__read_prefix(
git_otype *type_p,
git_odb_backend *backend,
const git_oid *short_oid,
- unsigned int len)
+ size_t len)
{
int error = 0;
@@ -680,6 +680,7 @@ struct foreach_state {
size_t dir_len;
int (*cb)(git_oid *oid, void *data);
void *data;
+ int cb_error;
};
GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr)
@@ -718,8 +719,10 @@ static int foreach_object_dir_cb(void *_state, git_buf *path)
if (filename_to_oid(&oid, path->ptr + state->dir_len) < 0)
return 0;
- if (state->cb(&oid, state->data) < 0)
+ if (state->cb(&oid, state->data)) {
+ state->cb_error = GIT_EUSER;
return -1;
+ }
return 0;
}
@@ -728,10 +731,7 @@ static int foreach_cb(void *_state, git_buf *path)
{
struct foreach_state *state = (struct foreach_state *) _state;
- if (git_path_direach(path, foreach_object_dir_cb, state) < 0)
- return -1;
-
- return 0;
+ return git_path_direach(path, foreach_object_dir_cb, state);
}
static int loose_backend__foreach(git_odb_backend *_backend, int (*cb)(git_oid *oid, void *data), void *data)
@@ -749,14 +749,16 @@ static int loose_backend__foreach(git_odb_backend *_backend, int (*cb)(git_oid *
git_buf_sets(&buf, objects_dir);
git_path_to_dir(&buf);
+ memset(&state, 0, sizeof(state));
state.cb = cb;
state.data = data;
state.dir_len = git_buf_len(&buf);
error = git_path_direach(&buf, foreach_cb, &state);
+
git_buf_free(&buf);
- return error;
+ return state.cb_error ? state.cb_error : error;
}
static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
diff --git a/src/odb_pack.c b/src/odb_pack.c
index 4b860e864..8fc6e68e8 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -149,7 +149,7 @@ static int pack_entry_find_prefix(
struct git_pack_entry *e,
struct pack_backend *backend,
const git_oid *short_oid,
- unsigned int len);
+ size_t len);
@@ -295,7 +295,7 @@ static int pack_entry_find_prefix(
struct git_pack_entry *e,
struct pack_backend *backend,
const git_oid *short_oid,
- unsigned int len)
+ size_t len)
{
int error;
unsigned int i;
@@ -384,7 +384,7 @@ static int pack_backend__read_prefix(
git_otype *type_p,
git_odb_backend *backend,
const git_oid *short_oid,
- unsigned int len)
+ size_t len)
{
int error = 0;
@@ -422,6 +422,7 @@ static int pack_backend__exists(git_odb_backend *backend, const git_oid *oid)
static int pack_backend__foreach(git_odb_backend *_backend, int (*cb)(git_oid *oid, void *data), void *data)
{
+ int error;
struct git_pack_file *p;
struct pack_backend *backend;
unsigned int i;
@@ -430,12 +431,14 @@ static int pack_backend__foreach(git_odb_backend *_backend, int (*cb)(git_oid *o
backend = (struct pack_backend *)_backend;
/* Make sure we know about the packfiles */
- if (packfile_refresh_all(backend) < 0)
- return -1;
+ if ((error = packfile_refresh_all(backend)) < 0)
+ return error;
git_vector_foreach(&backend->packs, i, p) {
- git_pack_foreach_entry(p, cb, &data);
+ if ((error = git_pack_foreach_entry(p, cb, &data)) < 0)
+ return error;
}
+
return 0;
}
@@ -458,6 +461,41 @@ static void pack_backend__free(git_odb_backend *_backend)
git__free(backend);
}
+int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx)
+{
+ struct pack_backend *backend = NULL;
+ struct git_pack_file *packfile = NULL;
+
+ if (git_packfile_check(&packfile, idx) < 0)
+ return -1;
+
+ backend = git__calloc(1, sizeof(struct pack_backend));
+ GITERR_CHECK_ALLOC(backend);
+
+ if (git_vector_init(&backend->packs, 1, NULL) < 0)
+ goto on_error;
+
+ if (git_vector_insert(&backend->packs, packfile) < 0)
+ goto on_error;
+
+ backend->parent.read = &pack_backend__read;
+ backend->parent.read_prefix = &pack_backend__read_prefix;
+ backend->parent.read_header = NULL;
+ backend->parent.exists = &pack_backend__exists;
+ backend->parent.foreach = &pack_backend__foreach;
+ backend->parent.free = &pack_backend__free;
+
+ *backend_out = (git_odb_backend *)backend;
+
+ return 0;
+
+on_error:
+ git_vector_free(&backend->packs);
+ git__free(backend);
+ git__free(packfile);
+ return -1;
+}
+
int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
{
struct pack_backend *backend = NULL;
diff --git a/src/oid.c b/src/oid.c
index 87756010b..821442d19 100644
--- a/src/oid.c
+++ b/src/oid.c
@@ -161,12 +161,7 @@ void git_oid_cpy(git_oid *out, const git_oid *src)
memcpy(out->id, src->id, sizeof(out->id));
}
-int git_oid_cmp(const git_oid *a, const git_oid *b)
-{
- return memcmp(a->id, b->id, sizeof(a->id));
-}
-
-int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, unsigned int len)
+int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len)
{
const unsigned char *a = oid_a->id;
const unsigned char *b = oid_b->id;
diff --git a/src/oidmap.h b/src/oidmap.h
index 5a0bab6ec..1791adb16 100644
--- a/src/oidmap.h
+++ b/src/oidmap.h
@@ -28,13 +28,8 @@ GIT_INLINE(khint_t) hash_git_oid(const git_oid *oid)
return h;
}
-GIT_INLINE(int) hash_git_oid_equal(const git_oid *a, const git_oid *b)
-{
- return (memcmp(a->id, b->id, sizeof(a->id)) == 0);
-}
-
#define GIT__USE_OIDMAP \
- __KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, hash_git_oid, hash_git_oid_equal)
+ __KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, hash_git_oid, git_oid_equal)
#define git_oidmap_alloc() kh_init(oid)
#define git_oidmap_free(h) kh_destroy(oid,h), h = NULL
diff --git a/src/pack.c b/src/pack.c
index 1d88eaa7d..e1fa085fd 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -38,7 +38,7 @@ static int pack_entry_find_offset(
git_oid *found_oid,
struct git_pack_file *p,
const git_oid *short_oid,
- unsigned int len);
+ size_t len);
static int packfile_error(const char *message)
{
@@ -687,10 +687,9 @@ static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_
}
int git_pack_foreach_entry(
- struct git_pack_file *p,
- int (*cb)(git_oid *oid, void *data),
- void *data)
-
+ struct git_pack_file *p,
+ int (*cb)(git_oid *oid, void *data),
+ void *data)
{
const unsigned char *index = p->index_map.data, *current;
unsigned stride;
@@ -722,7 +721,9 @@ int git_pack_foreach_entry(
current = index;
for (i = 0; i < p->num_objects; i++) {
- cb((git_oid *)current, data);
+ if (cb((git_oid *)current, data))
+ return GIT_EUSER;
+
current += stride;
}
@@ -734,7 +735,7 @@ static int pack_entry_find_offset(
git_oid *found_oid,
struct git_pack_file *p,
const git_oid *short_oid,
- unsigned int len)
+ size_t len)
{
const uint32_t *level1_ofs = p->index_map.data;
const unsigned char *index = p->index_map.data;
@@ -827,7 +828,7 @@ int git_pack_entry_find(
struct git_pack_entry *e,
struct git_pack_file *p,
const git_oid *short_oid,
- unsigned int len)
+ size_t len)
{
git_off_t offset;
git_oid found_oid;
diff --git a/src/pack.h b/src/pack.h
index 7e1f978b0..178545675 100644
--- a/src/pack.h
+++ b/src/pack.h
@@ -101,7 +101,7 @@ int git_pack_entry_find(
struct git_pack_entry *e,
struct git_pack_file *p,
const git_oid *short_oid,
- unsigned int len);
+ size_t len);
int git_pack_foreach_entry(
struct git_pack_file *p,
int (*cb)(git_oid *oid, void *data),
diff --git a/src/path.h b/src/path.h
index 5eecb7261..14618b2fc 100644
--- a/src/path.h
+++ b/src/path.h
@@ -239,6 +239,7 @@ extern int git_path_apply_relative(git_buf *target, const char *relpath);
* the input state and the second arg is pathbuf. The function
* may modify the pathbuf, but only by appending new text.
* @param state to pass to fn as the first arg.
+ * @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
extern int git_path_direach(
git_buf *pathbuf,
diff --git a/src/pkt.c b/src/pkt.c
index e003b97e2..8c916fff0 100644
--- a/src/pkt.c
+++ b/src/pkt.c
@@ -42,15 +42,29 @@ static int flush_pkt(git_pkt **out)
/* the rest of the line will be useful for multi_ack */
static int ack_pkt(git_pkt **out, const char *line, size_t len)
{
- git_pkt *pkt;
+ git_pkt_ack *pkt;
GIT_UNUSED(line);
GIT_UNUSED(len);
- pkt = git__malloc(sizeof(git_pkt));
+ pkt = git__calloc(1, sizeof(git_pkt_ack));
GITERR_CHECK_ALLOC(pkt);
pkt->type = GIT_PKT_ACK;
- *out = pkt;
+ line += 3;
+ len -= 3;
+
+ if (len >= GIT_OID_HEXSZ) {
+ git_oid_fromstr(&pkt->oid, line + 1);
+ line += GIT_OID_HEXSZ + 1;
+ len -= GIT_OID_HEXSZ + 1;
+ }
+
+ if (len >= 7) {
+ if (!git__prefixcmp(line + 1, "continue"))
+ pkt->status = GIT_ACK_CONTINUE;
+ }
+
+ *out = (git_pkt *) pkt;
return 0;
}
@@ -283,20 +297,28 @@ int git_pkt_buffer_flush(git_buf *buf)
static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps, git_buf *buf)
{
- char capstr[20];
+ git_buf str = GIT_BUF_INIT;
char oid[GIT_OID_HEXSZ +1] = {0};
unsigned int len;
if (caps->ofs_delta)
- strncpy(capstr, GIT_CAP_OFS_DELTA, sizeof(capstr));
+ git_buf_puts(&str, GIT_CAP_OFS_DELTA " ");
+
+ if (caps->multi_ack)
+ git_buf_puts(&str, GIT_CAP_MULTI_ACK " ");
+
+ if (git_buf_oom(&str))
+ return -1;
len = (unsigned int)
(strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ +
- strlen(capstr) + 1 /* LF */);
+ git_buf_len(&str) + 1 /* LF */);
git_buf_grow(buf, git_buf_len(buf) + len);
-
git_oid_fmt(oid, &head->oid);
- return git_buf_printf(buf, "%04xwant %s %s\n", len, oid, capstr);
+ git_buf_printf(buf, "%04xwant %s %s\n", len, oid, git_buf_cstr(&str));
+ git_buf_free(&str);
+
+ return git_buf_oom(buf);
}
/*
diff --git a/src/protocol.c b/src/protocol.c
index 6b3861796..20d6e230f 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -9,38 +9,36 @@
#include "pkt.h"
#include "buffer.h"
-int git_protocol_store_refs(git_protocol *p, const char *data, size_t len)
+int git_protocol_store_refs(git_transport *t, int flushes)
{
- git_buf *buf = &p->buf;
- git_vector *refs = p->refs;
- int error;
- const char *line_end, *ptr;
-
- if (len == 0) { /* EOF */
- if (git_buf_len(buf) != 0) {
- giterr_set(GITERR_NET, "Unexpected EOF");
- return p->error = -1;
- } else {
- return 0;
- }
- }
+ gitno_buffer *buf = &t->buffer;
+ git_vector *refs = &t->refs;
+ int error, flush = 0, recvd;
+ const char *line_end;
+ git_pkt *pkt;
- git_buf_put(buf, data, len);
- ptr = buf->ptr;
- while (1) {
- git_pkt *pkt;
+ do {
+ if (buf->offset > 0)
+ error = git_pkt_parse_line(&pkt, buf->data, &line_end, buf->offset);
+ else
+ error = GIT_EBUFS;
- if (git_buf_len(buf) == 0)
- return 0;
+ if (error < 0 && error != GIT_EBUFS)
+ return -1;
- error = git_pkt_parse_line(&pkt, ptr, &line_end, git_buf_len(buf));
- if (error == GIT_EBUFS)
- return 0; /* Ask for more */
- if (error < 0)
- return p->error = -1;
+ if (error == GIT_EBUFS) {
+ if ((recvd = gitno_recv(buf)) < 0)
+ return -1;
- git_buf_consume(buf, line_end);
+ if (recvd == 0 && !flush) {
+ giterr_set(GITERR_NET, "Early EOF");
+ return -1;
+ }
+
+ continue;
+ }
+ gitno_consume(buf, line_end);
if (pkt->type == GIT_PKT_ERR) {
giterr_set(GITERR_NET, "Remote error: %s", ((git_pkt_err *)pkt)->error);
git__free(pkt);
@@ -48,10 +46,42 @@ int git_protocol_store_refs(git_protocol *p, const char *data, size_t len)
}
if (git_vector_insert(refs, pkt) < 0)
- return p->error = -1;
+ return -1;
if (pkt->type == GIT_PKT_FLUSH)
- p->flush = 1;
+ flush++;
+ } while (flush < flushes);
+
+ return flush;
+}
+
+int git_protocol_detect_caps(git_pkt_ref *pkt, git_transport_caps *caps)
+{
+ const char *ptr;
+
+ /* No refs or capabilites, odd but not a problem */
+ if (pkt == NULL || pkt->capabilities == NULL)
+ return 0;
+
+ ptr = pkt->capabilities;
+ while (ptr != NULL && *ptr != '\0') {
+ if (*ptr == ' ')
+ ptr++;
+
+ if(!git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) {
+ caps->common = caps->ofs_delta = 1;
+ ptr += strlen(GIT_CAP_OFS_DELTA);
+ continue;
+ }
+
+ if(!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK)) {
+ caps->common = caps->multi_ack = 1;
+ ptr += strlen(GIT_CAP_MULTI_ACK);
+ continue;
+ }
+
+ /* We don't know this capability, so skip it */
+ ptr = strchr(ptr, ' ');
}
return 0;
diff --git a/src/protocol.h b/src/protocol.h
index a6c3e0735..615be8d63 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -9,15 +9,9 @@
#include "transport.h"
#include "buffer.h"
+#include "pkt.h"
-typedef struct {
- git_transport *transport;
- git_vector *refs;
- git_buf buf;
- int error;
- unsigned int flush :1;
-} git_protocol;
-
-int git_protocol_store_refs(git_protocol *p, const char *data, size_t len);
+int git_protocol_store_refs(git_transport *t, int flushes);
+int git_protocol_detect_caps(git_pkt_ref *pkt, git_transport_caps *caps);
#endif
diff --git a/src/reflog.c b/src/reflog.c
index 53cc25fa1..80e40b960 100644
--- a/src/reflog.c
+++ b/src/reflog.c
@@ -197,7 +197,7 @@ static int create_new_reflog_file(const char *filepath)
int git_reflog_read(git_reflog **reflog, git_reference *ref)
{
- int error;
+ int error = -1;
git_buf log_path = GIT_BUF_INIT;
git_buf log_file = GIT_BUF_INIT;
git_reflog *log = NULL;
@@ -406,10 +406,10 @@ int git_reflog_delete(git_reference *ref)
unsigned int git_reflog_entrycount(git_reflog *reflog)
{
assert(reflog);
- return reflog->entries.length;
+ return (unsigned int)reflog->entries.length;
}
-const git_reflog_entry * git_reflog_entry_byindex(git_reflog *reflog, unsigned int idx)
+const git_reflog_entry * git_reflog_entry_byindex(git_reflog *reflog, size_t idx)
{
assert(reflog);
return git_vector_get(&reflog->entries, idx);
diff --git a/src/refs.c b/src/refs.c
index 32f54fc31..cf55a6fd5 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -14,6 +14,7 @@
#include <git2/tag.h>
#include <git2/object.h>
+#include <git2/oid.h>
GIT__USE_STRMAP;
@@ -128,6 +129,7 @@ static int reference_read(
result = git_futils_readbuffer_updated(file_content, path.ptr, mtime, updated);
git_buf_free(&path);
+
return result;
}
@@ -135,12 +137,13 @@ static int loose_parse_symbolic(git_reference *ref, git_buf *file_content)
{
const unsigned int header_len = (unsigned int)strlen(GIT_SYMREF);
const char *refname_start;
- char *eol;
refname_start = (const char *)file_content->ptr;
- if (git_buf_len(file_content) < header_len + 1)
- goto corrupt;
+ if (git_buf_len(file_content) < header_len + 1) {
+ giterr_set(GITERR_REFERENCE, "Corrupted loose reference file");
+ return -1;
+ }
/*
* Assume we have already checked for the header
@@ -151,45 +154,16 @@ static int loose_parse_symbolic(git_reference *ref, git_buf *file_content)
ref->target.symbolic = git__strdup(refname_start);
GITERR_CHECK_ALLOC(ref->target.symbolic);
- /* remove newline at the end of file */
- eol = strchr(ref->target.symbolic, '\n');
- if (eol == NULL)
- goto corrupt;
-
- *eol = '\0';
- if (eol[-1] == '\r')
- eol[-1] = '\0';
-
return 0;
-
-corrupt:
- giterr_set(GITERR_REFERENCE, "Corrupted loose reference file");
- return -1;
}
static int loose_parse_oid(git_oid *oid, git_buf *file_content)
{
- char *buffer;
-
- buffer = (char *)file_content->ptr;
-
- /* File format: 40 chars (OID) + newline */
- if (git_buf_len(file_content) < GIT_OID_HEXSZ + 1)
- goto corrupt;
-
- if (git_oid_fromstr(oid, buffer) < 0)
- goto corrupt;
-
- buffer = buffer + GIT_OID_HEXSZ;
- if (*buffer == '\r')
- buffer++;
-
- if (*buffer != '\n')
- goto corrupt;
-
- return 0;
+ /* File format: 40 chars (OID) */
+ if (git_buf_len(file_content) == GIT_OID_HEXSZ &&
+ git_oid_fromstr(oid, git_buf_cstr(file_content)) == 0)
+ return 0;
-corrupt:
giterr_set(GITERR_REFERENCE, "Corrupted loose reference file");
return -1;
}
@@ -226,6 +200,8 @@ static int loose_lookup(git_reference *ref)
if (!updated)
return 0;
+ git_buf_rtrim(&ref_file);
+
if (ref->flags & GIT_REF_SYMBOLIC) {
git__free(ref->target.symbolic);
ref->target.symbolic = NULL;
@@ -259,6 +235,8 @@ static int loose_lookup_to_packfile(
if (reference_read(&ref_file, NULL, repo->path_repository, name, NULL) < 0)
return -1;
+ git_buf_rtrim(&ref_file);
+
name_len = strlen(name);
ref = git__malloc(sizeof(struct packref) + name_len + 1);
GITERR_CHECK_ALLOC(ref);
@@ -500,6 +478,7 @@ struct dirent_list_data {
int (*callback)(const char *, void *);
void *callback_payload;
+ int callback_error;
};
static int _dirent_loose_listall(void *_data, git_buf *full_path)
@@ -520,7 +499,10 @@ static int _dirent_loose_listall(void *_data, git_buf *full_path)
return 0; /* we are filtering out this reference */
}
- return data->callback(file_path, data->callback_payload);
+ if (data->callback(file_path, data->callback_payload))
+ data->callback_error = GIT_EUSER;
+
+ return data->callback_error;
}
static int _dirent_loose_load(void *data, git_buf *full_path)
@@ -843,15 +825,17 @@ static int reference_path_available(
const char *ref,
const char* old_ref)
{
+ int error;
struct reference_available_t data;
data.new_ref = ref;
data.old_ref = old_ref;
data.available = 1;
- if (git_reference_foreach(repo, GIT_REF_LISTALL,
- _reference_available_cb, (void *)&data) < 0)
- return -1;
+ error = git_reference_foreach(
+ repo, GIT_REF_LISTALL, _reference_available_cb, (void *)&data);
+ if (error < 0)
+ return error;
if (!data.available) {
giterr_set(GITERR_REFERENCE,
@@ -1486,8 +1470,8 @@ int git_reference_foreach(
return -1;
git_strmap_foreach(repo->references.packfile, ref_name, ref, {
- if (callback(ref_name, payload) < 0)
- return 0;
+ if (callback(ref_name, payload))
+ return GIT_EUSER;
});
}
@@ -1499,14 +1483,16 @@ int git_reference_foreach(
data.repo = repo;
data.callback = callback;
data.callback_payload = payload;
+ data.callback_error = 0;
if (git_buf_joinpath(&refs_path, repo->path_repository, GIT_REFS_DIR) < 0)
return -1;
result = git_path_direach(&refs_path, _dirent_loose_listall, &data);
+
git_buf_free(&refs_path);
- return result;
+ return data.callback_error ? GIT_EUSER : result;
}
static int cb__reflist_add(const char *ref, void *data)
diff --git a/src/remote.c b/src/remote.c
index c2bfb09bb..fe026b175 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -5,15 +5,16 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
-#include "git2/remote.h"
#include "git2/config.h"
#include "git2/types.h"
+#include "git2/oid.h"
#include "config.h"
#include "repository.h"
#include "remote.h"
#include "fetch.h"
#include "refs.h"
+#include "pkt.h"
#include <regex.h>
@@ -401,6 +402,10 @@ on_error:
int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
{
+ git_vector *refs = &remote->transport->refs;
+ unsigned int i;
+ git_pkt *p = NULL;
+
assert(remote);
if (!remote->transport || !remote->transport->connected) {
@@ -408,7 +413,19 @@ int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
return -1;
}
- return remote->transport->ls(remote->transport, list_cb, payload);
+ git_vector_foreach(refs, i, p) {
+ git_pkt_ref *pkt = NULL;
+
+ if (p->type != GIT_PKT_REF)
+ continue;
+
+ pkt = (git_pkt_ref *)p;
+
+ if (list_cb(&pkt->head, payload))
+ return GIT_EUSER;
+ }
+
+ return 0;
}
int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats)
@@ -580,6 +597,11 @@ int git_remote_list(git_strarray *remotes_list, git_repository *repo)
}
git_vector_free(&list);
+
+ /* cb error is converted to GIT_EUSER by git_config_foreach */
+ if (error == GIT_EUSER)
+ error = -1;
+
return error;
}
diff --git a/src/remote.h b/src/remote.h
index 5083b9912..67933a327 100644
--- a/src/remote.h
+++ b/src/remote.h
@@ -7,6 +7,8 @@
#ifndef INCLUDE_remote_h__
#define INCLUDE_remote_h__
+#include "git2/remote.h"
+
#include "refspec.h"
#include "transport.h"
#include "repository.h"
diff --git a/src/repository.c b/src/repository.c
index a2931713e..6f1f4349b 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -388,6 +388,19 @@ int git_repository_open(git_repository **repo_out, const char *path)
repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL);
}
+int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb)
+{
+ git_repository *repo;
+
+ repo = repository_alloc();
+ GITERR_CHECK_ALLOC(repo);
+
+ git_repository_set_odb(repo, odb);
+ *repo_out = repo;
+
+ return 0;
+}
+
int git_repository_discover(
char *repository_path,
size_t size,
@@ -1058,3 +1071,58 @@ int git_repository_head_tree(git_tree **tree, git_repository *repo)
*tree = (git_tree *)obj;
return 0;
}
+
+#define MERGE_MSG_FILE "MERGE_MSG"
+
+int git_repository_message(char *buffer, size_t len, git_repository *repo)
+{
+ git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
+ struct stat st;
+ ssize_t size;
+ int error;
+
+ if (git_buf_joinpath(&path, repo->path_repository, MERGE_MSG_FILE) < 0)
+ return -1;
+
+ error = p_stat(git_buf_cstr(&path), &st);
+ if (error < 0) {
+ if (errno == ENOENT)
+ error = GIT_ENOTFOUND;
+
+ git_buf_free(&path);
+ return error;
+ }
+
+ if (buffer == NULL) {
+ git_buf_free(&path);
+ return (int)st.st_size;
+ }
+
+ if (git_futils_readbuffer(&buf, git_buf_cstr(&path)) < 0)
+ goto on_error;
+
+ memcpy(buffer, git_buf_cstr(&buf), len);
+ size = git_buf_len(&buf);
+
+ git_buf_free(&path);
+ git_buf_free(&buf);
+ return size;
+
+on_error:
+ git_buf_free(&path);
+ return -1;
+}
+
+int git_repository_message_remove(git_repository *repo)
+{
+ git_buf path = GIT_BUF_INIT;
+ int error;
+
+ if (git_buf_joinpath(&path, repo->path_repository, MERGE_MSG_FILE) < 0)
+ return -1;
+
+ error = p_unlink(git_buf_cstr(&path));
+ git_buf_free(&path);
+
+ return error;
+}
diff --git a/src/revparse.c b/src/revparse.c
index e2c0de612..3855c29f1 100644
--- a/src/revparse.c
+++ b/src/revparse.c
@@ -338,7 +338,7 @@ cleanup:
return error;
}
-static int handle_at_syntax(git_object **out, git_reference **ref, const char *spec, int identifier_len, git_repository* repo, const char *curly_braces_content)
+static int handle_at_syntax(git_object **out, git_reference **ref, const char *spec, size_t identifier_len, git_repository* repo, const char *curly_braces_content)
{
bool is_numeric;
int parsed = 0, error = -1;
@@ -547,7 +547,7 @@ static int handle_caret_curly_syntax(git_object **out, git_object *obj, const ch
return git_object_peel(out, obj, expected_type);
}
-static int extract_curly_braces_content(git_buf *buf, const char *spec, int *pos)
+static int extract_curly_braces_content(git_buf *buf, const char *spec, size_t *pos)
{
git_buf_clear(buf);
@@ -572,7 +572,7 @@ static int extract_curly_braces_content(git_buf *buf, const char *spec, int *pos
return 0;
}
-static int extract_path(git_buf *buf, const char *spec, int *pos)
+static int extract_path(git_buf *buf, const char *spec, size_t *pos)
{
git_buf_clear(buf);
@@ -588,7 +588,7 @@ static int extract_path(git_buf *buf, const char *spec, int *pos)
return 0;
}
-static int extract_how_many(int *n, const char *spec, int *pos)
+static int extract_how_many(int *n, const char *spec, size_t *pos)
{
const char *end_ptr;
int parsed, accumulated;
@@ -633,7 +633,7 @@ static int object_from_reference(git_object **object, git_reference *reference)
return error;
}
-static int ensure_base_rev_loaded(git_object **object, git_reference **reference, const char *spec, int identifier_len, git_repository *repo, bool allow_empty_identifier)
+static int ensure_base_rev_loaded(git_object **object, git_reference **reference, const char *spec, size_t identifier_len, git_repository *repo, bool allow_empty_identifier)
{
int error;
git_buf identifier = GIT_BUF_INIT;
@@ -670,7 +670,7 @@ static int ensure_base_rev_is_not_known_yet(git_object *object, const char *spec
return revspec_error(spec);
}
-static bool any_left_hand_identifier(git_object *object, git_reference *reference, int identifier_len)
+static bool any_left_hand_identifier(git_object *object, git_reference *reference, size_t identifier_len)
{
if (object != NULL)
return true;
@@ -694,7 +694,7 @@ static int ensure_left_hand_identifier_is_not_known_yet(git_object *object, git_
int git_revparse_single(git_object **out, git_repository *repo, const char *spec)
{
- int pos = 0, identifier_len = 0;
+ size_t pos = 0, identifier_len = 0;
int error = -1, n;
git_buf buf = GIT_BUF_INIT;
diff --git a/src/sha1.h b/src/sha1.h
index 93a244d76..f0a16f2cf 100644
--- a/src/sha1.h
+++ b/src/sha1.h
@@ -5,6 +5,9 @@
* a Linking Exception. For full terms see the included COPYING file.
*/
+#ifndef INCLUDE_sha1_h__
+#define INCLUDE_sha1_h__
+
typedef struct {
unsigned long long size;
unsigned int H[5];
@@ -19,3 +22,5 @@ void git__blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx);
#define SHA1_Init git__blk_SHA1_Init
#define SHA1_Update git__blk_SHA1_Update
#define SHA1_Final git__blk_SHA1_Final
+
+#endif
diff --git a/src/status.c b/src/status.c
index d78237689..8e462552e 100644
--- a/src/status.c
+++ b/src/status.c
@@ -81,7 +81,7 @@ int git_status_foreach_ext(
git_status_show_t show =
opts ? opts->show : GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
git_diff_delta *i2h, *w2i;
- unsigned int i, j, i_max, j_max;
+ size_t i, j, i_max, j_max;
assert(show <= GIT_STATUS_SHOW_INDEX_THEN_WORKDIR);
@@ -114,7 +114,8 @@ int git_status_foreach_ext(
if (show == GIT_STATUS_SHOW_INDEX_THEN_WORKDIR) {
for (i = 0; !err && i < idx2head->deltas.length; i++) {
i2h = GIT_VECTOR_GET(&idx2head->deltas, i);
- err = cb(i2h->old_file.path, index_delta2status(i2h->status), cbdata);
+ if (cb(i2h->old_file.path, index_delta2status(i2h->status), cbdata))
+ err = GIT_EUSER;
}
git_diff_list_free(idx2head);
idx2head = NULL;
@@ -130,14 +131,17 @@ int git_status_foreach_ext(
cmp = !w2i ? -1 : !i2h ? 1 : strcmp(i2h->old_file.path, w2i->old_file.path);
if (cmp < 0) {
- err = cb(i2h->old_file.path, index_delta2status(i2h->status), cbdata);
+ if (cb(i2h->old_file.path, index_delta2status(i2h->status), cbdata))
+ err = GIT_EUSER;
i++;
} else if (cmp > 0) {
- err = cb(w2i->old_file.path, workdir_delta2status(w2i->status), cbdata);
+ if (cb(w2i->old_file.path, workdir_delta2status(w2i->status), cbdata))
+ err = GIT_EUSER;
j++;
} else {
- err = cb(i2h->old_file.path, index_delta2status(i2h->status) |
- workdir_delta2status(w2i->status), cbdata);
+ if (cb(i2h->old_file.path, index_delta2status(i2h->status) |
+ workdir_delta2status(w2i->status), cbdata))
+ err = GIT_EUSER;
i++; j++;
}
}
@@ -146,6 +150,7 @@ cleanup:
git_tree_free(head);
git_diff_list_free(idx2head);
git_diff_list_free(wd2idx);
+
return err;
}
@@ -166,9 +171,10 @@ int git_status_foreach(
}
struct status_file_info {
+ char *expected;
unsigned int count;
unsigned int status;
- char *expected;
+ int ambiguous;
};
static int get_one_status(const char *path, unsigned int status, void *data)
@@ -183,6 +189,7 @@ static int get_one_status(const char *path, unsigned int status, void *data)
p_fnmatch(sfi->expected, path, 0) != 0)) {
giterr_set(GITERR_INVALID,
"Ambiguous path '%s' given to git_status_file", sfi->expected);
+ sfi->ambiguous = true;
return GIT_EAMBIGUOUS;
}
@@ -215,6 +222,9 @@ int git_status_file(
error = git_status_foreach_ext(repo, &opts, get_one_status, &sfi);
+ if (error < 0 && sfi.ambiguous)
+ error = GIT_EAMBIGUOUS;
+
if (!error && !sfi.count) {
giterr_set(GITERR_INVALID,
"Attempt to get status of nonexistent file '%s'", path);
diff --git a/src/transport.h b/src/transport.h
index 68b92f7a6..c4306165c 100644
--- a/src/transport.h
+++ b/src/transport.h
@@ -12,6 +12,7 @@
#include "vector.h"
#include "posix.h"
#include "common.h"
+#include "netops.h"
#ifdef GIT_SSL
# include <openssl/ssl.h>
# include <openssl/err.h>
@@ -19,10 +20,12 @@
#define GIT_CAP_OFS_DELTA "ofs-delta"
+#define GIT_CAP_MULTI_ACK "multi_ack"
typedef struct git_transport_caps {
int common:1,
- ofs_delta:1;
+ ofs_delta:1,
+ multi_ack: 1;
} git_transport_caps;
#ifdef GIT_SSL
@@ -70,19 +73,25 @@ struct git_transport {
int direction : 1, /* 0 fetch, 1 push */
connected : 1,
check_cert: 1,
- encrypt : 1;
+ use_ssl : 1,
+ own_logic: 1, /* transitional */
+ rpc: 1; /* git-speak for the HTTP transport */
#ifdef GIT_SSL
struct gitno_ssl ssl;
#endif
+ git_vector refs;
+ git_vector common;
+ gitno_buffer buffer;
GIT_SOCKET socket;
+ git_transport_caps caps;
/**
* Connect and store the remote heads
*/
int (*connect)(struct git_transport *transport, int dir);
/**
- * Give a list of references, useful for ls-remote
+ * Send our side of a negotiation
*/
- int (*ls)(struct git_transport *transport, git_headlist_cb list_cb, void *opaque);
+ int (*negotiation_step)(struct git_transport *transport, void *data, size_t len);
/**
* Push the changes over
*/
@@ -97,10 +106,6 @@ struct git_transport {
*/
int (*download_pack)(struct git_transport *transport, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats);
/**
- * Fetch the changes
- */
- int (*fetch)(struct git_transport *transport);
- /**
* Close the connection
*/
int (*close)(struct git_transport *transport);
@@ -124,7 +129,6 @@ int git_transport_dummy(struct git_transport **transport);
*/
int git_transport_valid_url(const char *url);
-typedef struct git_transport git_transport;
typedef int (*git_transport_cb)(git_transport **transport);
#endif
diff --git a/src/transports/git.c b/src/transports/git.c
index 45f571f20..7a65718f7 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -24,12 +24,7 @@
typedef struct {
git_transport parent;
- git_protocol proto;
- git_vector refs;
- git_remote_head **heads;
- git_transport_caps caps;
char buff[1024];
- gitno_buffer buf;
#ifdef GIT_WIN32
WSADATA wsd;
#endif
@@ -127,68 +122,6 @@ on_error:
}
/*
- * Read from the socket and store the references in the vector
- */
-static int store_refs(transport_git *t)
-{
- gitno_buffer *buf = &t->buf;
- int ret = 0;
-
- while (1) {
- if ((ret = gitno_recv(buf)) < 0)
- return -1;
- if (ret == 0) /* Orderly shutdown, so exit */
- return 0;
-
- ret = git_protocol_store_refs(&t->proto, buf->data, buf->offset);
- if (ret == GIT_EBUFS) {
- gitno_consume_n(buf, buf->len);
- continue;
- }
-
- if (ret < 0)
- return ret;
-
- gitno_consume_n(buf, buf->offset);
-
- if (t->proto.flush) { /* No more refs */
- t->proto.flush = 0;
- return 0;
- }
- }
-}
-
-static int detect_caps(transport_git *t)
-{
- git_vector *refs = &t->refs;
- git_pkt_ref *pkt;
- git_transport_caps *caps = &t->caps;
- const char *ptr;
-
- pkt = git_vector_get(refs, 0);
- /* No refs or capabilites, odd but not a problem */
- if (pkt == NULL || pkt->capabilities == NULL)
- return 0;
-
- ptr = pkt->capabilities;
- while (ptr != NULL && *ptr != '\0') {
- if (*ptr == ' ')
- ptr++;
-
- if(!git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) {
- caps->common = caps->ofs_delta = 1;
- ptr += strlen(GIT_CAP_OFS_DELTA);
- continue;
- }
-
- /* We don't know this capability, so skip it */
- ptr = strchr(ptr, ' ');
- }
-
- return 0;
-}
-
-/*
* Since this is a network connection, we need to parse and store the
* pkt-lines at this stage and keep them there.
*/
@@ -202,202 +135,26 @@ static int git_connect(git_transport *transport, int direction)
}
t->parent.direction = direction;
- if (git_vector_init(&t->refs, 16, NULL) < 0)
- return -1;
/* Connect and ask for the refs */
if (do_connect(t, transport->url) < 0)
- goto cleanup;
+ return -1;
- gitno_buffer_setup(transport, &t->buf, t->buff, sizeof(t->buff));
+ gitno_buffer_setup(transport, &transport->buffer, t->buff, sizeof(t->buff));
t->parent.connected = 1;
- if (store_refs(t) < 0)
- goto cleanup;
-
- if (detect_caps(t) < 0)
- goto cleanup;
-
- return 0;
-cleanup:
- git_vector_free(&t->refs);
- return -1;
-}
-
-static int git_ls(git_transport *transport, git_headlist_cb list_cb, void *opaque)
-{
- transport_git *t = (transport_git *) transport;
- git_vector *refs = &t->refs;
- unsigned int i;
- git_pkt *p = NULL;
-
- git_vector_foreach(refs, i, p) {
- git_pkt_ref *pkt = NULL;
-
- if (p->type != GIT_PKT_REF)
- continue;
-
- pkt = (git_pkt_ref *)p;
-
- if (list_cb(&pkt->head, opaque) < 0) {
- giterr_set(GITERR_NET, "User callback returned error");
- return -1;
- }
- }
-
- return 0;
-}
-
-/* Wait until we get an ack from the */
-static int recv_pkt(gitno_buffer *buf)
-{
- const char *ptr = buf->data, *line_end;
- git_pkt *pkt;
- int pkt_type, error;
-
- do {
- /* Wait for max. 1 second */
- if ((error = gitno_select_in(buf, 1, 0)) < 0) {
- return -1;
- } else if (error == 0) {
- /*
- * Some servers don't respond immediately, so if this
- * happens, we keep sending information until it
- * answers. Pretend we received a NAK to convince higher
- * layers to do so.
- */
- return GIT_PKT_NAK;
- }
-
- if ((error = gitno_recv(buf)) < 0)
- return -1;
-
- error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
- if (error == GIT_EBUFS)
- continue;
- if (error < 0)
- return -1;
- } while (error);
-
- gitno_consume(buf, line_end);
- pkt_type = pkt->type;
- git__free(pkt);
-
- return pkt_type;
-}
-
-static int git_negotiate_fetch(git_transport *transport, git_repository *repo, const git_vector *wants)
-{
- transport_git *t = (transport_git *) transport;
- git_revwalk *walk;
- git_oid oid;
- int error;
- unsigned int i;
- git_buf data = GIT_BUF_INIT;
- gitno_buffer *buf = &t->buf;
-
- if (git_pkt_buffer_wants(wants, &t->caps, &data) < 0)
+ if (git_protocol_store_refs(transport, 1) < 0)
return -1;
- if (git_fetch_setup_walk(&walk, repo) < 0)
- goto on_error;
-
- if (gitno_send(transport, data.ptr, data.size, 0) < 0)
- goto on_error;
-
- git_buf_clear(&data);
- /*
- * We don't support any kind of ACK extensions, so the negotiation
- * boils down to sending what we have and listening for an ACK
- * every once in a while.
- */
- i = 0;
- while ((error = git_revwalk_next(&oid, walk)) == 0) {
- git_pkt_buffer_have(&oid, &data);
- i++;
- if (i % 20 == 0) {
- int pkt_type;
-
- git_pkt_buffer_flush(&data);
- if (git_buf_oom(&data))
- goto on_error;
-
- if (gitno_send(transport, data.ptr, data.size, 0) < 0)
- goto on_error;
-
- pkt_type = recv_pkt(buf);
-
- if (pkt_type == GIT_PKT_ACK) {
- break;
- } else if (pkt_type == GIT_PKT_NAK) {
- continue;
- } else {
- giterr_set(GITERR_NET, "Unexpected pkt type");
- goto on_error;
- }
-
- }
- }
- if (error < 0 && error != GIT_REVWALKOVER)
- goto on_error;
-
- /* Tell the other end that we're done negotiating */
- git_buf_clear(&data);
- git_pkt_buffer_flush(&data);
- git_pkt_buffer_done(&data);
- if (gitno_send(transport, data.ptr, data.size, 0) < 0)
- goto on_error;
+ if (git_protocol_detect_caps(git_vector_get(&transport->refs, 0), &transport->caps) < 0)
+ return -1;
- git_buf_free(&data);
- git_revwalk_free(walk);
return 0;
-
-on_error:
- git_buf_free(&data);
- git_revwalk_free(walk);
- return -1;
}
-static int git_download_pack(git_transport *transport, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats)
+static int git_negotiation_step(struct git_transport *transport, void *data, size_t len)
{
- transport_git *t = (transport_git *) transport;
- int error = 0, read_bytes;
- gitno_buffer *buf = &t->buf;
- git_pkt *pkt;
- const char *line_end, *ptr;
-
- /*
- * For now, we ignore everything and wait for the pack
- */
- do {
- ptr = buf->data;
- /* Whilst we're searching for the pack */
- while (1) {
- if (buf->offset == 0) {
- break;
- }
-
- error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset);
- if (error == GIT_EBUFS)
- break;
-
- if (error < 0)
- return error;
-
- if (pkt->type == GIT_PKT_PACK) {
- git__free(pkt);
- return git_fetch__download_pack(buf->data, buf->offset, transport, repo, bytes, stats);
- }
-
- /* For now we don't care about anything */
- git__free(pkt);
- gitno_consume(buf, line_end);
- }
-
- read_bytes = gitno_recv(buf);
- } while (read_bytes);
-
- return read_bytes;
+ return gitno_send(transport, data, len, 0);
}
static int git_close(git_transport *t)
@@ -408,6 +165,7 @@ static int git_close(git_transport *t)
return -1;
/* Can't do anything if there's an error, so don't bother checking */
gitno_send(t, buf.ptr, buf.size, 0);
+ git_buf_free(&buf);
if (gitno_close(t->socket) < 0) {
giterr_set(GITERR_NET, "Failed to close socket");
@@ -426,17 +184,22 @@ static int git_close(git_transport *t)
static void git_free(git_transport *transport)
{
transport_git *t = (transport_git *) transport;
- git_vector *refs = &t->refs;
+ git_vector *refs = &transport->refs;
unsigned int i;
for (i = 0; i < refs->length; ++i) {
git_pkt *p = git_vector_get(refs, i);
git_pkt_free(p);
}
+ git_vector_free(refs);
+ refs = &transport->common;
+ for (i = 0; i < refs->length; ++i) {
+ git_pkt *p = git_vector_get(refs, i);
+ git_pkt_free(p);
+ }
git_vector_free(refs);
- git__free(t->heads);
- git_buf_free(&t->proto.buf);
+
git__free(t->parent.url);
git__free(t);
}
@@ -452,15 +215,16 @@ int git_transport_git(git_transport **out)
GITERR_CHECK_ALLOC(t);
memset(t, 0x0, sizeof(transport_git));
+ if (git_vector_init(&t->parent.common, 8, NULL))
+ goto on_error;
+
+ if (git_vector_init(&t->parent.refs, 16, NULL) < 0)
+ goto on_error;
t->parent.connect = git_connect;
- t->parent.ls = git_ls;
- t->parent.negotiate_fetch = git_negotiate_fetch;
- t->parent.download_pack = git_download_pack;
+ t->parent.negotiation_step = git_negotiation_step;
t->parent.close = git_close;
t->parent.free = git_free;
- t->proto.refs = &t->refs;
- t->proto.transport = (git_transport *) t;
*out = (git_transport *) t;
@@ -474,4 +238,8 @@ int git_transport_git(git_transport **out)
#endif
return 0;
+
+on_error:
+ git__free(t);
+ return -1;
}
diff --git a/src/transports/http.c b/src/transports/http.c
index f25d639f3..85fec413a 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -29,11 +29,8 @@ enum last_cb {
typedef struct {
git_transport parent;
- git_protocol proto;
- git_vector refs;
- git_vector common;
+ http_parser_settings settings;
git_buf buf;
- git_remote_head **heads;
int error;
int transfer_finished :1,
ct_found :1,
@@ -46,7 +43,7 @@ typedef struct {
char *host;
char *port;
char *service;
- git_transport_caps caps;
+ char buffer[4096];
#ifdef GIT_WIN32
WSADATA wsd;
#endif
@@ -183,17 +180,6 @@ static int on_headers_complete(http_parser *parser)
return 0;
}
-static int on_body_store_refs(http_parser *parser, const char *str, size_t len)
-{
- transport_http *t = (transport_http *) parser->data;
-
- if (parser->status_code == 404) {
- return git_buf_put(&t->buf, str, len);
- }
-
- return git_protocol_store_refs(&t->proto, str, len);
-}
-
static int on_message_complete(http_parser *parser)
{
transport_http *t = (transport_http *) parser->data;
@@ -208,51 +194,64 @@ static int on_message_complete(http_parser *parser)
return 0;
}
-static int store_refs(transport_http *t)
+static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len)
{
- http_parser_settings settings;
- char buffer[1024];
- gitno_buffer buf;
- git_pkt *pkt;
- int ret;
+ git_transport *transport = (git_transport *) parser->data;
+ transport_http *t = (transport_http *) parser->data;
+ gitno_buffer *buf = &transport->buffer;
- http_parser_init(&t->parser, HTTP_RESPONSE);
- t->parser.data = t;
- memset(&settings, 0x0, sizeof(http_parser_settings));
- settings.on_header_field = on_header_field;
- settings.on_header_value = on_header_value;
- settings.on_headers_complete = on_headers_complete;
- settings.on_body = on_body_store_refs;
- settings.on_message_complete = on_message_complete;
+ if (buf->len - buf->offset < len) {
+ giterr_set(GITERR_NET, "Can't fit data in the buffer");
+ return t->error = -1;
+ }
- gitno_buffer_setup((git_transport *)t, &buf, buffer, sizeof(buffer));
+ memcpy(buf->data + buf->offset, str, len);
+ buf->offset += len;
- while(1) {
- size_t parsed;
+ return 0;
+}
- if ((ret = gitno_recv(&buf)) < 0)
- return -1;
+static int http_recv_cb(gitno_buffer *buf)
+{
+ git_transport *transport = (git_transport *) buf->cb_data;
+ transport_http *t = (transport_http *) transport;
+ size_t old_len;
+ gitno_buffer inner;
+ char buffer[2048];
+ int error;
- parsed = http_parser_execute(&t->parser, &settings, buf.data, buf.offset);
- /* Both should happen at the same time */
- if (parsed != buf.offset || t->error < 0)
- return t->error;
+ if (t->transfer_finished)
+ return 0;
- gitno_consume_n(&buf, parsed);
+ gitno_buffer_setup(transport, &inner, buffer, sizeof(buffer));
- if (ret == 0 || t->transfer_finished)
- return 0;
- }
+ if ((error = gitno_recv(&inner)) < 0)
+ return -1;
- pkt = git_vector_get(&t->refs, 0);
- if (pkt == NULL || pkt->type != GIT_PKT_COMMENT) {
- giterr_set(GITERR_NET, "Invalid HTTP response");
- return t->error = -1;
- } else {
- git_vector_remove(&t->refs, 0);
- }
+ old_len = buf->offset;
+ http_parser_execute(&t->parser, &t->settings, inner.data, inner.offset);
+ if (t->error < 0)
+ return t->error;
- return 0;
+ return buf->offset - old_len;
+}
+
+/* Set up the gitno_buffer so calling gitno_recv() grabs data from the HTTP response */
+static void setup_gitno_buffer(git_transport *transport)
+{
+ transport_http *t = (transport_http *) transport;
+
+ http_parser_init(&t->parser, HTTP_RESPONSE);
+ t->parser.data = t;
+ t->transfer_finished = 0;
+ memset(&t->settings, 0x0, sizeof(http_parser_settings));
+ t->settings.on_header_field = on_header_field;
+ t->settings.on_header_value = on_header_value;
+ t->settings.on_headers_complete = on_headers_complete;
+ t->settings.on_body = on_body_fill_buffer;
+ t->settings.on_message_complete = on_message_complete;
+
+ gitno_buffer_setup_callback(transport, &transport->buffer, t->buffer, sizeof(t->buffer), http_recv_cb, t);
}
static int http_connect(git_transport *transport, int direction)
@@ -263,6 +262,7 @@ static int http_connect(git_transport *transport, int direction)
const char *service = "upload-pack";
const char *url = t->parent.url, *prefix_http = "http://", *prefix_https = "https://";
const char *default_port;
+ git_pkt *pkt;
if (direction == GIT_DIR_PUSH) {
giterr_set(GITERR_NET, "Pushing over HTTP is not implemented");
@@ -270,8 +270,6 @@ static int http_connect(git_transport *transport, int direction)
}
t->parent.direction = direction;
- if (git_vector_init(&t->refs, 16, NULL) < 0)
- return -1;
if (!git__prefixcmp(url, prefix_http)) {
url = t->parent.url + strlen(prefix_http);
@@ -304,307 +302,61 @@ static int http_connect(git_transport *transport, int direction)
if (gitno_send(transport, request.ptr, request.size, 0) < 0)
goto cleanup;
- ret = store_refs(t);
-
-cleanup:
- git_buf_free(&request);
- git_buf_clear(&t->buf);
-
- return ret;
-}
-
-static int http_ls(git_transport *transport, git_headlist_cb list_cb, void *opaque)
-{
- transport_http *t = (transport_http *) transport;
- git_vector *refs = &t->refs;
- unsigned int i;
- git_pkt_ref *p;
-
- git_vector_foreach(refs, i, p) {
- if (p->type != GIT_PKT_REF)
- continue;
-
- if (list_cb(&p->head, opaque) < 0) {
- giterr_set(GITERR_NET, "The user callback returned error");
- return -1;
- }
- }
-
- return 0;
-}
-
-static int on_body_parse_response(http_parser *parser, const char *str, size_t len)
-{
- transport_http *t = (transport_http *) parser->data;
- git_buf *buf = &t->buf;
- git_vector *common = &t->common;
- int error;
- const char *line_end, *ptr;
-
- if (len == 0) { /* EOF */
- if (git_buf_len(buf) != 0) {
- giterr_set(GITERR_NET, "Unexpected EOF");
- return t->error = -1;
- } else {
- return 0;
- }
- }
-
- git_buf_put(buf, str, len);
- ptr = buf->ptr;
- while (1) {
- git_pkt *pkt;
-
- if (git_buf_len(buf) == 0)
- return 0;
-
- error = git_pkt_parse_line(&pkt, ptr, &line_end, git_buf_len(buf));
- if (error == GIT_EBUFS) {
- return 0; /* Ask for more */
- }
- if (error < 0)
- return t->error = -1;
-
- git_buf_consume(buf, line_end);
-
- if (pkt->type == GIT_PKT_PACK) {
- git__free(pkt);
- t->pack_ready = 1;
- return 0;
- }
-
- if (pkt->type == GIT_PKT_NAK) {
- git__free(pkt);
- return 0;
- }
-
- if (pkt->type != GIT_PKT_ACK) {
- git__free(pkt);
- continue;
- }
-
- if (git_vector_insert(common, pkt) < 0)
- return -1;
- }
-
- return error;
-
-}
-
-static int parse_response(transport_http *t)
-{
- int ret = 0;
- http_parser_settings settings;
- char buffer[1024];
- gitno_buffer buf;
-
- http_parser_init(&t->parser, HTTP_RESPONSE);
- t->parser.data = t;
- t->transfer_finished = 0;
- memset(&settings, 0x0, sizeof(http_parser_settings));
- settings.on_header_field = on_header_field;
- settings.on_header_value = on_header_value;
- settings.on_headers_complete = on_headers_complete;
- settings.on_body = on_body_parse_response;
- settings.on_message_complete = on_message_complete;
-
- gitno_buffer_setup((git_transport *)t, &buf, buffer, sizeof(buffer));
-
- while(1) {
- size_t parsed;
-
- if ((ret = gitno_recv(&buf)) < 0)
- return -1;
-
- parsed = http_parser_execute(&t->parser, &settings, buf.data, buf.offset);
- /* Both should happen at the same time */
- if (parsed != buf.offset || t->error < 0)
- return t->error;
-
- gitno_consume_n(&buf, parsed);
+ setup_gitno_buffer(transport);
+ if ((ret = git_protocol_store_refs(transport, 2)) < 0)
+ goto cleanup;
- if (ret == 0 || t->transfer_finished || t->pack_ready) {
- return 0;
- }
+ pkt = git_vector_get(&transport->refs, 0);
+ if (pkt == NULL || pkt->type != GIT_PKT_COMMENT) {
+ giterr_set(GITERR_NET, "Invalid HTTP response");
+ return t->error = -1;
+ } else {
+ /* Remove the comment and flush pkts */
+ git_vector_remove(&transport->refs, 0);
+ git__free(pkt);
+ pkt = git_vector_get(&transport->refs, 0);
+ git_vector_remove(&transport->refs, 0);
+ git__free(pkt);
}
- return ret;
-}
-
-static int http_negotiate_fetch(git_transport *transport, git_repository *repo, const git_vector *wants)
-{
- transport_http *t = (transport_http *) transport;
- int ret;
- unsigned int i;
- char buff[128];
- gitno_buffer buf;
- git_revwalk *walk = NULL;
- git_oid oid;
- git_pkt_ack *pkt;
- git_vector *common = &t->common;
- git_buf request = GIT_BUF_INIT, data = GIT_BUF_INIT;
-
- gitno_buffer_setup(transport, &buf, buff, sizeof(buff));
-
- if (git_vector_init(common, 16, NULL) < 0)
- return -1;
-
- if (git_fetch_setup_walk(&walk, repo) < 0)
- return -1;
-
- do {
- if ((ret = do_connect(t, t->host, t->port)) < 0)
- goto cleanup;
-
- if ((ret = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0)
- goto cleanup;
-
- /* We need to send these on each connection */
- git_vector_foreach (common, i, pkt) {
- if ((ret = git_pkt_buffer_have(&pkt->oid, &data)) < 0)
- goto cleanup;
- }
-
- i = 0;
- while ((i < 20) && ((ret = git_revwalk_next(&oid, walk)) == 0)) {
- if ((ret = git_pkt_buffer_have(&oid, &data)) < 0)
- goto cleanup;
-
- i++;
- }
-
- git_pkt_buffer_done(&data);
-
- if ((ret = gen_request(&request, t->path, t->host, "POST", "upload-pack", data.size, 0)) < 0)
- goto cleanup;
-
- if ((ret = gitno_send(transport, request.ptr, request.size, 0)) < 0)
- goto cleanup;
-
- if ((ret = gitno_send(transport, data.ptr, data.size, 0)) < 0)
- goto cleanup;
-
- git_buf_clear(&request);
- git_buf_clear(&data);
-
- if (ret < 0 || i >= 256)
- break;
-
- if ((ret = parse_response(t)) < 0)
- goto cleanup;
-
- if (t->pack_ready) {
- ret = 0;
- goto cleanup;
- }
-
- } while(1);
+ if (git_protocol_detect_caps(git_vector_get(&transport->refs, 0), &transport->caps) < 0)
+ return t->error = -1;
cleanup:
git_buf_free(&request);
- git_buf_free(&data);
- git_revwalk_free(walk);
- return ret;
-}
-
-typedef struct {
- git_indexer_stream *idx;
- git_indexer_stats *stats;
- transport_http *transport;
-} download_pack_cbdata;
-
-static int on_message_complete_download_pack(http_parser *parser)
-{
- download_pack_cbdata *data = (download_pack_cbdata *) parser->data;
-
- data->transport->transfer_finished = 1;
-
- return 0;
-}
-static int on_body_download_pack(http_parser *parser, const char *str, size_t len)
-{
- download_pack_cbdata *data = (download_pack_cbdata *) parser->data;
- transport_http *t = data->transport;
- git_indexer_stream *idx = data->idx;
- git_indexer_stats *stats = data->stats;
+ git_buf_clear(&t->buf);
- return t->error = git_indexer_stream_add(idx, str, len, stats);
+ return ret;
}
-/*
- * As the server is probably using Transfer-Encoding: chunked, we have
- * to use the HTTP parser to download the pack instead of giving it to
- * the simple downloader. Furthermore, we're using keep-alive
- * connections, so the simple downloader would just hang.
- */
-static int http_download_pack(git_transport *transport, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats)
+static int http_negotiation_step(struct git_transport *transport, void *data, size_t len)
{
transport_http *t = (transport_http *) transport;
- git_buf *oldbuf = &t->buf;
- int recvd;
- http_parser_settings settings;
- char buffer[1024];
- gitno_buffer buf;
- git_buf path = GIT_BUF_INIT;
- git_indexer_stream *idx = NULL;
- download_pack_cbdata data;
-
- gitno_buffer_setup(transport, &buf, buffer, sizeof(buffer));
-
- if (memcmp(oldbuf->ptr, "PACK", strlen("PACK"))) {
- giterr_set(GITERR_NET, "The pack doesn't start with a pack signature");
- return -1;
- }
-
- if (git_buf_joinpath(&path, git_repository_path(repo), "objects/pack") < 0)
- return -1;
+ git_buf request = GIT_BUF_INIT;
+ int ret;
- if (git_indexer_stream_new(&idx, git_buf_cstr(&path)) < 0)
+ /* First, send the data as a HTTP POST request */
+ if ((ret = do_connect(t, t->host, t->port)) < 0)
return -1;
- /*
- * This is part of the previous response, so we don't want to
- * re-init the parser, just set these two callbacks.
- */
- memset(stats, 0, sizeof(git_indexer_stats));
- data.stats = stats;
- data.idx = idx;
- data.transport = t;
- t->parser.data = &data;
- t->transfer_finished = 0;
- memset(&settings, 0x0, sizeof(settings));
- settings.on_message_complete = on_message_complete_download_pack;
- settings.on_body = on_body_download_pack;
- *bytes = git_buf_len(oldbuf);
-
- if (git_indexer_stream_add(idx, git_buf_cstr(oldbuf), git_buf_len(oldbuf), stats) < 0)
+ if ((ret = gen_request(&request, t->path, t->host, "POST", "upload-pack", len, 0)) < 0)
goto on_error;
- gitno_buffer_setup(transport, &buf, buffer, sizeof(buffer));
-
- do {
- size_t parsed;
-
- if ((recvd = gitno_recv(&buf)) < 0)
- goto on_error;
+ if ((ret = gitno_send(transport, request.ptr, request.size, 0)) < 0)
+ goto on_error;
- parsed = http_parser_execute(&t->parser, &settings, buf.data, buf.offset);
- if (parsed != buf.offset || t->error < 0)
- goto on_error;
+ if ((ret = gitno_send(transport, data, len, 0)) < 0)
+ goto on_error;
- *bytes += recvd;
- gitno_consume_n(&buf, parsed);
- } while (recvd > 0 && !t->transfer_finished);
+ git_buf_free(&request);
- if (git_indexer_stream_finalize(idx, stats) < 0)
- goto on_error;
+ /* Then we need to set up the buffer to grab data from the HTTP response */
+ setup_gitno_buffer(transport);
- git_indexer_stream_free(idx);
return 0;
on_error:
- git_indexer_stream_free(idx);
- git_buf_free(&path);
+ git_buf_free(&request);
return -1;
}
@@ -627,8 +379,8 @@ static int http_close(git_transport *transport)
static void http_free(git_transport *transport)
{
transport_http *t = (transport_http *) transport;
- git_vector *refs = &t->refs;
- git_vector *common = &t->common;
+ git_vector *refs = &transport->refs;
+ git_vector *common = &transport->common;
unsigned int i;
git_pkt *p;
@@ -649,8 +401,6 @@ static void http_free(git_transport *transport)
}
git_vector_free(common);
git_buf_free(&t->buf);
- git_buf_free(&t->proto.buf);
- git__free(t->heads);
git__free(t->content_type);
git__free(t->host);
git__free(t->port);
@@ -669,13 +419,15 @@ int git_transport_http(git_transport **out)
memset(t, 0x0, sizeof(transport_http));
t->parent.connect = http_connect;
- t->parent.ls = http_ls;
- t->parent.negotiate_fetch = http_negotiate_fetch;
- t->parent.download_pack = http_download_pack;
+ t->parent.negotiation_step = http_negotiation_step;
t->parent.close = http_close;
t->parent.free = http_free;
- t->proto.refs = &t->refs;
- t->proto.transport = (git_transport *) t;
+ t->parent.rpc = 1;
+
+ if (git_vector_init(&t->parent.refs, 16, NULL) < 0) {
+ git__free(t);
+ return -1;
+ }
#ifdef GIT_WIN32
/* on win32, the WSA context needs to be initialized
@@ -698,7 +450,7 @@ int git_transport_https(git_transport **out)
if (git_transport_http((git_transport **)&t) < 0)
return -1;
- t->parent.encrypt = 1;
+ t->parent.use_ssl = 1;
t->parent.check_cert = 1;
*out = (git_transport *) t;
diff --git a/src/transports/local.c b/src/transports/local.c
index 0e1ae3752..561c84fa0 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -15,11 +15,11 @@
#include "posix.h"
#include "path.h"
#include "buffer.h"
+#include "pkt.h"
typedef struct {
git_transport parent;
git_repository *repo;
- git_vector refs;
} transport_local;
static int add_ref(transport_local *t, const char *name)
@@ -27,19 +27,32 @@ static int add_ref(transport_local *t, const char *name)
const char peeled[] = "^{}";
git_remote_head *head;
git_object *obj = NULL, *target = NULL;
+ git_transport *transport = (git_transport *) t;
git_buf buf = GIT_BUF_INIT;
+ git_pkt_ref *pkt;
head = git__malloc(sizeof(git_remote_head));
GITERR_CHECK_ALLOC(head);
+ pkt = git__malloc(sizeof(git_pkt_ref));
+ GITERR_CHECK_ALLOC(pkt);
head->name = git__strdup(name);
GITERR_CHECK_ALLOC(head->name);
- if (git_reference_name_to_oid(&head->oid, t->repo, name) < 0 ||
- git_vector_insert(&t->refs, head) < 0)
- {
- git__free(head->name);
+ if (git_reference_name_to_oid(&head->oid, t->repo, name) < 0) {
git__free(head);
+ git__free(pkt->head.name);
+ git__free(pkt);
+ }
+
+ pkt->type = GIT_PKT_REF;
+ memcpy(&pkt->head, head, sizeof(git_remote_head));
+ git__free(head);
+
+ if (git_vector_insert(&transport->refs, pkt) < 0)
+ {
+ git__free(pkt->head.name);
+ git__free(pkt);
return -1;
}
@@ -47,7 +60,7 @@ static int add_ref(transport_local *t, const char *name)
if (git__prefixcmp(name, GIT_REFS_TAGS_DIR))
return 0;
- if (git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJ_ANY) < 0)
+ if (git_object_lookup(&obj, t->repo, &pkt->head.oid, GIT_OBJ_ANY) < 0)
return -1;
head = NULL;
@@ -66,14 +79,20 @@ static int add_ref(transport_local *t, const char *name)
head->name = git_buf_detach(&buf);
+ pkt = git__malloc(sizeof(git_pkt_ref));
+ GITERR_CHECK_ALLOC(pkt);
+ pkt->type = GIT_PKT_REF;
+
if (git_tag_peel(&target, (git_tag *) obj) < 0)
goto on_error;
git_oid_cpy(&head->oid, git_object_id(target));
git_object_free(obj);
git_object_free(target);
+ memcpy(&pkt->head, head, sizeof(git_remote_head));
+ git__free(head);
- if (git_vector_insert(&t->refs, head) < 0)
+ if (git_vector_insert(&transport->refs, pkt) < 0)
return -1;
return 0;
@@ -88,11 +107,12 @@ static int store_refs(transport_local *t)
{
unsigned int i;
git_strarray ref_names = {0};
+ git_transport *transport = (git_transport *) t;
assert(t);
if (git_reference_list(&ref_names, t->repo, GIT_REF_LISTALL) < 0 ||
- git_vector_init(&t->refs, (unsigned int)ref_names.count, NULL) < 0)
+ git_vector_init(&transport->refs, (unsigned int)ref_names.count, NULL) < 0)
goto on_error;
/* Sort the references first */
@@ -111,28 +131,11 @@ static int store_refs(transport_local *t)
return 0;
on_error:
- git_vector_free(&t->refs);
+ git_vector_free(&transport->refs);
git_strarray_free(&ref_names);
return -1;
}
-static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *payload)
-{
- transport_local *t = (transport_local *) transport;
- git_vector *refs = &t->refs;
- unsigned int i;
- git_remote_head *h;
-
- assert(transport && transport->connected);
-
- git_vector_foreach(refs, i, h) {
- if (list_cb(h, payload) < 0)
- return -1;
- }
-
- return 0;
-}
-
/*
* Try to open the url as a git directory. The direction doesn't
* matter in this case because we're calulating the heads ourselves.
@@ -201,14 +204,14 @@ static void local_free(git_transport *transport)
{
unsigned int i;
transport_local *t = (transport_local *) transport;
- git_vector *vec = &t->refs;
- git_remote_head *h;
+ git_vector *vec = &transport->refs;
+ git_pkt_ref *pkt;
assert(transport);
- git_vector_foreach (vec, i, h) {
- git__free(h->name);
- git__free(h);
+ git_vector_foreach (vec, i, pkt) {
+ git__free(pkt->head.name);
+ git__free(pkt);
}
git_vector_free(vec);
@@ -229,8 +232,8 @@ int git_transport_local(git_transport **out)
memset(t, 0x0, sizeof(transport_local));
+ t->parent.own_logic = 1;
t->parent.connect = local_connect;
- t->parent.ls = local_ls;
t->parent.negotiate_fetch = local_negotiate_fetch;
t->parent.close = local_close;
t->parent.free = local_free;
diff --git a/src/tree.c b/src/tree.c
index 9d793cbb8..19250fe5e 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -234,12 +234,27 @@ const git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename
return entry_fromname(tree, filename, strlen(filename));
}
-const git_tree_entry *git_tree_entry_byindex(git_tree *tree, unsigned int idx)
+const git_tree_entry *git_tree_entry_byindex(git_tree *tree, size_t idx)
{
assert(tree);
return git_vector_get(&tree->entries, idx);
}
+const git_tree_entry *git_tree_entry_byoid(git_tree *tree, const git_oid *oid)
+{
+ unsigned int i;
+ git_tree_entry *e;
+
+ assert(tree);
+
+ git_vector_foreach(&tree->entries, i, e) {
+ if (memcmp(&e->oid.id, &oid->id, sizeof(oid->id)) == 0)
+ return e;
+ }
+
+ return NULL;
+}
+
int git_tree__prefix_position(git_tree *tree, const char *path)
{
git_vector *entries = &tree->entries;
@@ -270,7 +285,7 @@ int git_tree__prefix_position(git_tree *tree, const char *path)
unsigned int git_tree_entrycount(git_tree *tree)
{
assert(tree);
- return tree->entries.length;
+ return (unsigned int)tree->entries.length;
}
static int tree_error(const char *str)
@@ -501,7 +516,7 @@ static void sort_entries(git_treebuilder *bld)
int git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source)
{
git_treebuilder *bld;
- unsigned int i, source_entries = DEFAULT_TREE_SIZE;
+ size_t i, source_entries = DEFAULT_TREE_SIZE;
assert(builder_p);
@@ -724,7 +739,7 @@ int git_tree_entry_bypath(
}
switch (path[filename_len]) {
- case '/':
+ case '/':
/* If there are more components in the path...
* then this entry *must* be a tree */
if (!git_tree_entry__is_tree(entry)) {
@@ -772,8 +787,13 @@ static int tree_walk(
for (i = 0; i < tree->entries.length; ++i) {
git_tree_entry *entry = tree->entries.contents[i];
- if (preorder && callback(path->ptr, entry, payload) < 0)
- return -1;
+ if (preorder) {
+ error = callback(path->ptr, entry, payload);
+ if (error > 0)
+ continue;
+ if (error < 0)
+ return GIT_EUSER;
+ }
if (git_tree_entry__is_tree(entry)) {
git_tree *subtree;
@@ -790,18 +810,21 @@ static int tree_walk(
if (git_buf_oom(path))
return -1;
- if (tree_walk(subtree, callback, path, payload, preorder) < 0)
- return -1;
+ error = tree_walk(subtree, callback, path, payload, preorder);
+ if (error != 0)
+ break;
git_buf_truncate(path, path_len);
git_tree_free(subtree);
}
- if (!preorder && callback(path->ptr, entry, payload) < 0)
- return -1;
+ if (!preorder && callback(path->ptr, entry, payload) < 0) {
+ error = GIT_EUSER;
+ break;
+ }
}
- return 0;
+ return error;
}
int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payload)
diff --git a/src/util.c b/src/util.c
index 90bb3d02a..51bf843de 100644
--- a/src/util.c
+++ b/src/util.c
@@ -22,6 +22,18 @@ void git_libgit2_version(int *major, int *minor, int *rev)
*rev = LIBGIT2_VER_REVISION;
}
+int git_libgit2_capabilities()
+{
+ return 0
+#ifdef GIT_THREADS
+ | GIT_CAP_THREADS
+#endif
+#ifdef GIT_SSL
+ | GIT_CAP_HTTPS
+#endif
+ ;
+}
+
void git_strarray_free(git_strarray *array)
{
size_t i;
diff --git a/src/vector.c b/src/vector.c
index 6f9aacccf..0308ce26e 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -35,7 +35,7 @@ void git_vector_free(git_vector *v)
v->_alloc_size = 0;
}
-int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp)
+int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp)
{
assert(v);
diff --git a/src/vector.h b/src/vector.h
index 9139db345..f75e634ba 100644
--- a/src/vector.h
+++ b/src/vector.h
@@ -12,16 +12,16 @@
typedef int (*git_vector_cmp)(const void *, const void *);
typedef struct git_vector {
- unsigned int _alloc_size;
+ size_t _alloc_size;
git_vector_cmp _cmp;
void **contents;
- unsigned int length;
+ size_t length;
int sorted;
} git_vector;
#define GIT_VECTOR_INIT {0}
-int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp);
+int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp);
void git_vector_free(git_vector *v);
void git_vector_clear(git_vector *v);
void git_vector_swap(git_vector *a, git_vector *b);
@@ -45,12 +45,12 @@ GIT_INLINE(int) git_vector_bsearch2(
return git_vector_bsearch3(NULL, v, cmp, key);
}
-GIT_INLINE(void *) git_vector_get(git_vector *v, unsigned int position)
+GIT_INLINE(void *) git_vector_get(git_vector *v, size_t position)
{
return (position < v->length) ? v->contents[position] : NULL;
}
-GIT_INLINE(const void *) git_vector_get_const(const git_vector *v, unsigned int position)
+GIT_INLINE(const void *) git_vector_get_const(const git_vector *v, size_t position)
{
return (position < v->length) ? v->contents[position] : NULL;
}
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 557760b94..aa34ad3ac 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -61,6 +61,7 @@ GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft)
static int do_lstat(const char *file_name, struct stat *buf)
{
WIN32_FILE_ATTRIBUTE_DATA fdata;
+ DWORD last_error;
wchar_t* fbuf = gitwin_to_utf16(file_name);
if (!fbuf)
return -1;
@@ -94,6 +95,12 @@ static int do_lstat(const char *file_name, struct stat *buf)
return 0;
}
+ last_error = GetLastError();
+ if (last_error == ERROR_FILE_NOT_FOUND)
+ errno = ENOENT;
+ else if (last_error == ERROR_PATH_NOT_FOUND)
+ errno = ENOTDIR;
+
git__free(fbuf);
return -1;
}
diff --git a/tests-clar/attr/repo.c b/tests-clar/attr/repo.c
index c37ff544a..4a317e4f3 100644
--- a/tests-clar/attr/repo.c
+++ b/tests-clar/attr/repo.c
@@ -113,6 +113,22 @@ static int count_attrs(
return 0;
}
+static int cancel_iteration(
+ const char *name,
+ const char *value,
+ void *payload)
+{
+ GIT_UNUSED(name);
+ GIT_UNUSED(value);
+
+ *((int *)payload) -= 1;
+
+ if (*((int *)payload) < 0)
+ return -1;
+
+ return 0;
+}
+
void test_attr_repo__foreach(void)
{
int count;
@@ -131,6 +147,12 @@ void test_attr_repo__foreach(void)
cl_git_pass(git_attr_foreach(g_repo, 0, "sub/subdir_test2.txt",
&count_attrs, &count));
cl_assert(count == 6); /* repoattr, rootattr, subattr, reposub, negattr, another */
+
+ count = 2;
+ cl_assert_equal_i(
+ GIT_EUSER, git_attr_foreach(
+ g_repo, 0, "sub/subdir_test1", &cancel_iteration, &count)
+ );
}
void test_attr_repo__manpage_example(void)
diff --git a/tests-clar/config/read.c b/tests-clar/config/read.c
index a8504da02..fcd22463d 100644
--- a/tests-clar/config/read.c
+++ b/tests-clar/config/read.c
@@ -226,7 +226,7 @@ void test_config_read__foreach(void)
count = 3;
cl_git_fail(ret = git_config_foreach(cfg, cfg_callback_countdown, &count));
- cl_assert_equal_i(-100, ret);
+ cl_assert_equal_i(GIT_EUSER, ret);
git_config_free(cfg);
}
@@ -266,6 +266,22 @@ void test_config_read__foreach_match(void)
git_config_free(cfg);
}
+void test_config_read__whitespace_not_required_around_assignment(void)
+{
+ git_config *cfg;
+ const char *str;
+
+ cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config14")));
+
+ cl_git_pass(git_config_get_string(&str, cfg, "a.b"));
+ cl_assert_equal_s(str, "c");
+
+ cl_git_pass(git_config_get_string(&str, cfg, "d.e"));
+ cl_assert_equal_s(str, "f");
+
+ git_config_free(cfg);
+}
+
#if 0
BEGIN_TEST(config10, "a repo's config overrides the global config")
diff --git a/tests-clar/diff/diff_helpers.c b/tests-clar/diff/diff_helpers.c
index 1d9f6121c..18daa080b 100644
--- a/tests-clar/diff/diff_helpers.c
+++ b/tests-clar/diff/diff_helpers.c
@@ -5,7 +5,7 @@ git_tree *resolve_commit_oid_to_tree(
git_repository *repo,
const char *partial_oid)
{
- unsigned int len = (unsigned int)strlen(partial_oid);
+ size_t len = strlen(partial_oid);
git_oid oid;
git_object *obj = NULL;
git_tree *tree = NULL;
diff --git a/tests-clar/diff/index.c b/tests-clar/diff/index.c
index 171815df5..89e65e3b7 100644
--- a/tests-clar/diff/index.c
+++ b/tests-clar/diff/index.c
@@ -90,3 +90,53 @@ void test_diff_index__0(void)
git_tree_free(a);
git_tree_free(b);
}
+
+static int diff_stop_after_2_files(
+ void *cb_data,
+ git_diff_delta *delta,
+ float progress)
+{
+ diff_expects *e = cb_data;
+
+ GIT_UNUSED(progress);
+ GIT_UNUSED(delta);
+
+ e->files++;
+
+ return (e->files == 2);
+}
+
+void test_diff_index__1(void)
+{
+ /* grabbed a couple of commit oids from the history of the attr repo */
+ const char *a_commit = "26a125ee1bf"; /* the current HEAD */
+ const char *b_commit = "0017bd4ab1ec3"; /* the start */
+ git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit);
+ git_tree *b = resolve_commit_oid_to_tree(g_repo, b_commit);
+ git_diff_options opts = {0};
+ git_diff_list *diff = NULL;
+ diff_expects exp;
+
+ cl_assert(a);
+ cl_assert(b);
+
+ opts.context_lines = 1;
+ opts.interhunk_lines = 1;
+
+ memset(&exp, 0, sizeof(exp));
+
+ cl_git_pass(git_diff_index_to_tree(g_repo, &opts, a, &diff));
+
+ cl_assert_equal_i(
+ GIT_EUSER,
+ git_diff_foreach(diff, &exp, diff_stop_after_2_files, NULL, NULL)
+ );
+
+ cl_assert(exp.files == 2);
+
+ git_diff_list_free(diff);
+ diff = NULL;
+
+ git_tree_free(a);
+ git_tree_free(b);
+}
diff --git a/tests-clar/network/remotelocal.c b/tests-clar/network/remotelocal.c
index 16e3fe2dd..63016db5f 100644
--- a/tests-clar/network/remotelocal.c
+++ b/tests-clar/network/remotelocal.c
@@ -107,7 +107,7 @@ void test_network_remotelocal__retrieve_advertised_references(void)
cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs));
- cl_assert_equal_i(how_many_refs, 23);
+ cl_assert_equal_i(how_many_refs, 25);
}
void test_network_remotelocal__retrieve_advertised_references_from_spaced_repository(void)
@@ -121,7 +121,7 @@ void test_network_remotelocal__retrieve_advertised_references_from_spaced_reposi
cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs));
- cl_assert_equal_i(how_many_refs, 23);
+ cl_assert_equal_i(how_many_refs, 25);
git_remote_free(remote); /* Disconnect from the "spaced repo" before the cleanup */
remote = NULL;
diff --git a/tests-clar/notes/notes.c b/tests-clar/notes/notes.c
index e1387782e..dfd7f5231 100644
--- a/tests-clar/notes/notes.c
+++ b/tests-clar/notes/notes.c
@@ -95,11 +95,39 @@ void test_notes_notes__can_retrieve_a_list_of_notes_for_a_given_namespace(void)
create_note(&note_oid3, "refs/notes/i-can-see-dead-notes", "9fd738e8f7967c078dceed8190330fc8648ee56a", "I decorate 9fd7 and 4a20\n");
create_note(&note_oid4, "refs/notes/i-can-see-dead-notes", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "I decorate 9fd7 and 4a20\n");
- cl_git_pass(git_note_foreach(_repo, "refs/notes/i-can-see-dead-notes", note_list_cb, &retrieved_notes));
+ cl_git_pass(git_note_foreach
+(_repo, "refs/notes/i-can-see-dead-notes", note_list_cb, &retrieved_notes));
cl_assert_equal_i(4, retrieved_notes);
}
+static int note_cancel_cb(git_note_data *note_data, void *payload)
+{
+ unsigned int *count = (unsigned int *)payload;
+
+ GIT_UNUSED(note_data);
+
+ (*count)++;
+
+ return (*count > 2);
+}
+
+void test_notes_notes__can_cancel_foreach(void)
+{
+ git_oid note_oid1, note_oid2, note_oid3, note_oid4;
+ unsigned int retrieved_notes = 0;
+
+ create_note(&note_oid1, "refs/notes/i-can-see-dead-notes", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "I decorate a65f\n");
+ create_note(&note_oid2, "refs/notes/i-can-see-dead-notes", "c47800c7266a2be04c571c04d5a6614691ea99bd", "I decorate c478\n");
+ create_note(&note_oid3, "refs/notes/i-can-see-dead-notes", "9fd738e8f7967c078dceed8190330fc8648ee56a", "I decorate 9fd7 and 4a20\n");
+ create_note(&note_oid4, "refs/notes/i-can-see-dead-notes", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "I decorate 9fd7 and 4a20\n");
+
+ cl_assert_equal_i(
+ GIT_EUSER,
+ git_note_foreach(_repo, "refs/notes/i-can-see-dead-notes",
+ note_cancel_cb, &retrieved_notes));
+}
+
void test_notes_notes__retrieving_a_list_of_notes_for_an_unknown_namespace_returns_ENOTFOUND(void)
{
int error;
diff --git a/tests-clar/object/blob/fromchunks.c b/tests-clar/object/blob/fromchunks.c
index 228e969b6..dc57d4fbe 100644
--- a/tests-clar/object/blob/fromchunks.c
+++ b/tests-clar/object/blob/fromchunks.c
@@ -30,7 +30,7 @@ static int text_chunked_source_cb(char *content, size_t max_length, void *payloa
return 0;
strcpy(content, textual_content);
- return strlen(textual_content);
+ return (int)strlen(textual_content);
}
void test_object_blob_fromchunks__can_create_a_blob_from_a_in_memory_chunk_provider(void)
diff --git a/tests-clar/object/commit/commitstagedfile.c b/tests-clar/object/commit/commitstagedfile.c
index 628ef43c2..882fb49ae 100644
--- a/tests-clar/object/commit/commitstagedfile.c
+++ b/tests-clar/object/commit/commitstagedfile.c
@@ -109,7 +109,7 @@ void test_object_commit_commitstagedfile__generate_predictable_object_ids(void)
cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60));
cl_git_pass(git_tree_lookup(&tree, repo, &tree_oid));
- cl_git_pass(git_message_prettify(buffer, 128, "Initial commit", 0));
+ cl_assert_equal_i(16, git_message_prettify(buffer, 128, "Initial commit", 0));
cl_git_pass(git_commit_create_v(
&commit_oid,
@@ -128,3 +128,68 @@ void test_object_commit_commitstagedfile__generate_predictable_object_ids(void)
git_tree_free(tree);
git_index_free(index);
}
+
+void test_object_commit_commitstagedfile__message_prettify(void)
+{
+ char buffer[100];
+
+ cl_assert(git_message_prettify(buffer, sizeof(buffer), "", 0) == 1);
+ cl_assert_equal_s(buffer, "");
+ cl_assert(git_message_prettify(buffer, sizeof(buffer), "", 1) == 1);
+ cl_assert_equal_s(buffer, "");
+
+ cl_assert_equal_i(7, git_message_prettify(buffer, sizeof(buffer), "Short", 0));
+ cl_assert_equal_s("Short\n", buffer);
+ cl_assert_equal_i(7, git_message_prettify(buffer, sizeof(buffer), "Short", 1));
+ cl_assert_equal_s("Short\n", buffer);
+
+ cl_assert(git_message_prettify(buffer, sizeof(buffer), "This is longer\nAnd multiline\n# with some comments still in\n", 0) > 0);
+ cl_assert_equal_s(buffer, "This is longer\nAnd multiline\n# with some comments still in\n");
+
+ cl_assert(git_message_prettify(buffer, sizeof(buffer), "This is longer\nAnd multiline\n# with some comments still in\n", 1) > 0);
+ cl_assert_equal_s(buffer, "This is longer\nAnd multiline\n");
+
+ /* try out overflow */
+ cl_assert(git_message_prettify(buffer, sizeof(buffer),
+ "1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
+ "1234567890" "1234567890" "1234567890" "1234567890" "12345678",
+ 0) > 0);
+ cl_assert_equal_s(buffer,
+ "1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
+ "1234567890" "1234567890" "1234567890" "1234567890" "12345678\n");
+
+ cl_assert(git_message_prettify(buffer, sizeof(buffer),
+ "1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
+ "1234567890" "1234567890" "1234567890" "1234567890" "12345678\n",
+ 0) > 0);
+ cl_assert_equal_s(buffer,
+ "1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
+ "1234567890" "1234567890" "1234567890" "1234567890" "12345678\n");
+
+ cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
+ "1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
+ "1234567890" "1234567890" "1234567890" "1234567890" "123456789",
+ 0));
+ cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
+ "1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
+ "1234567890" "1234567890" "1234567890" "1234567890" "123456789\n",
+ 0));
+ cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
+ "1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
+ "1234567890" "1234567890" "1234567890" "1234567890" "1234567890",
+ 0));
+ cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
+ "1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
+ "1234567890" "1234567890" "1234567890" "1234567890" "1234567890""x",
+ 0));
+
+ cl_assert(git_message_prettify(buffer, sizeof(buffer),
+ "1234567890" "1234567890" "1234567890" "1234567890" "1234567890\n"
+ "# 1234567890" "1234567890" "1234567890" "1234567890" "1234567890\n"
+ "1234567890",
+ 1) > 0);
+
+ cl_assert(git_message_prettify(NULL, 0, "", 0) == 1);
+ cl_assert(git_message_prettify(NULL, 0, "Short test", 0) == 12);
+ cl_assert(git_message_prettify(NULL, 0, "Test\n# with\nComments", 1) == 15);
+}
diff --git a/tests-clar/object/tree/walk.c b/tests-clar/object/tree/walk.c
new file mode 100644
index 000000000..58b0bca4c
--- /dev/null
+++ b/tests-clar/object/tree/walk.c
@@ -0,0 +1,103 @@
+#include "clar_libgit2.h"
+#include "tree.h"
+
+static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd";
+static git_repository *g_repo;
+
+void test_object_tree_walk__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("testrepo");
+}
+
+void test_object_tree_walk__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+static int treewalk_count_cb(
+ const char *root, const git_tree_entry *entry, void *payload)
+{
+ int *count = payload;
+
+ GIT_UNUSED(root);
+ GIT_UNUSED(entry);
+
+ (*count) += 1;
+
+ return 0;
+}
+
+void test_object_tree_walk__0(void)
+{
+ git_oid id;
+ git_tree *tree;
+ int ct;
+
+ git_oid_fromstr(&id, tree_oid);
+
+ cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
+
+ ct = 0;
+ cl_git_pass(git_tree_walk(tree, treewalk_count_cb, GIT_TREEWALK_PRE, &ct));
+ cl_assert_equal_i(3, ct);
+
+ ct = 0;
+ cl_git_pass(git_tree_walk(tree, treewalk_count_cb, GIT_TREEWALK_POST, &ct));
+ cl_assert_equal_i(3, ct);
+
+ git_tree_free(tree);
+}
+
+
+static int treewalk_stop_cb(
+ const char *root, const git_tree_entry *entry, void *payload)
+{
+ int *count = payload;
+
+ GIT_UNUSED(root);
+ GIT_UNUSED(entry);
+
+ (*count) += 1;
+
+ return (*count == 2) ? -1 : 0;
+}
+
+static int treewalk_stop_immediately_cb(
+ const char *root, const git_tree_entry *entry, void *payload)
+{
+ GIT_UNUSED(root);
+ GIT_UNUSED(entry);
+ GIT_UNUSED(payload);
+ return -100;
+}
+
+void test_object_tree_walk__1(void)
+{
+ git_oid id;
+ git_tree *tree;
+ int ct;
+
+ git_oid_fromstr(&id, tree_oid);
+
+ cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
+
+ ct = 0;
+ cl_assert_equal_i(
+ GIT_EUSER, git_tree_walk(tree, treewalk_stop_cb, GIT_TREEWALK_PRE, &ct));
+ cl_assert_equal_i(2, ct);
+
+ ct = 0;
+ cl_assert_equal_i(
+ GIT_EUSER, git_tree_walk(tree, treewalk_stop_cb, GIT_TREEWALK_POST, &ct));
+ cl_assert_equal_i(2, ct);
+
+ cl_assert_equal_i(
+ GIT_EUSER, git_tree_walk(
+ tree, treewalk_stop_immediately_cb, GIT_TREEWALK_PRE, NULL));
+
+ cl_assert_equal_i(
+ GIT_EUSER, git_tree_walk(
+ tree, treewalk_stop_immediately_cb, GIT_TREEWALK_POST, NULL));
+
+ git_tree_free(tree);
+}
diff --git a/tests-clar/odb/foreach.c b/tests-clar/odb/foreach.c
index e5d01eafd..c1304a2e4 100644
--- a/tests-clar/odb/foreach.c
+++ b/tests-clar/odb/foreach.c
@@ -7,16 +7,13 @@ static git_odb *_odb;
static git_repository *_repo;
static int nobj;
-void test_odb_foreach__initialize(void)
-{
- cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git")));
- git_repository_odb(&_odb, _repo);
-}
-
void test_odb_foreach__cleanup(void)
{
git_odb_free(_odb);
git_repository_free(_repo);
+
+ _odb = NULL;
+ _repo = NULL;
}
static int foreach_cb(git_oid *oid, void *data)
@@ -41,6 +38,43 @@ static int foreach_cb(git_oid *oid, void *data)
*/
void test_odb_foreach__foreach(void)
{
+ cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git")));
+ git_repository_odb(&_odb, _repo);
+
cl_git_pass(git_odb_foreach(_odb, foreach_cb, NULL));
cl_assert_equal_i(43 + 1640, nobj); /* count + in-pack */
}
+
+void test_odb_foreach__one_pack(void)
+{
+ git_odb_backend *backend = NULL;
+
+ cl_git_pass(git_odb_new(&_odb));
+ cl_git_pass(git_odb_backend_one_pack(&backend, cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx")));
+ cl_git_pass(git_odb_add_backend(_odb, backend, 1));
+ _repo = NULL;
+
+ nobj = 0;
+ cl_git_pass(git_odb_foreach(_odb, foreach_cb, NULL));
+ cl_assert(nobj == 1628);
+}
+
+static int foreach_stop_cb(git_oid *oid, void *data)
+{
+ GIT_UNUSED(data);
+ GIT_UNUSED(oid);
+
+ nobj++;
+
+ return (nobj == 1000);
+}
+
+void test_odb_foreach__interrupt_foreach(void)
+{
+ nobj = 0;
+ cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git")));
+ git_repository_odb(&_odb, _repo);
+
+ cl_assert_equal_i(GIT_EUSER, git_odb_foreach(_odb, foreach_stop_cb, NULL));
+ cl_assert(nobj == 1000);
+}
diff --git a/tests-clar/odb/pack_data_one.h b/tests-clar/odb/pack_data_one.h
new file mode 100644
index 000000000..13570ba78
--- /dev/null
+++ b/tests-clar/odb/pack_data_one.h
@@ -0,0 +1,19 @@
+/* Just a few to make sure it's working, the rest is tested already */
+static const char *packed_objects_one[] = {
+ "9fcf811e00fa469688943a9152c16d4ee90fb9a9",
+ "a93f42a5b5e9de40fa645a9ff1e276a021c9542b",
+ "12bf5f3e3470d90db177ccf1b5e8126409377fc6",
+ "ed1ea164cdbe3c4b200fb4fa19861ea90eaee222",
+ "dfae6ed8f6dd8acc3b40a31811ea316239223559",
+ "aefe66d192771201e369fde830530f4475beec30",
+ "775e4b4c1296e9e3104f2a36ca9cf9356a130959",
+ "412ec4e4a6a7419bc1be00561fe474e54cb499fe",
+ "236e7579fed7763be77209efb8708960982f3cb3",
+ "09fe9364461cf60dd1c46b0e9545b1e47bb1a297",
+ "d76d8a6390d1cf32138d98a91b1eb7e0275a12f5",
+ "d0fdf2dcff2f548952eec536ccc6d266550041bc",
+ "a20d733a9fa79fa5b4cbb9639864f93325ec27a6",
+ "785d3fe8e7db5ade2c2242fecd46c32a7f4dc59f",
+ "4d8d0fd9cb6045075385701c3f933ec13345e9c4",
+ "0cfd861bd547b6520d1fc2e190e8359e0a9c9b90"
+};
diff --git a/tests-clar/odb/packed_one.c b/tests-clar/odb/packed_one.c
new file mode 100644
index 000000000..a064829dd
--- /dev/null
+++ b/tests-clar/odb/packed_one.c
@@ -0,0 +1,58 @@
+#include "clar_libgit2.h"
+#include "odb.h"
+#include "pack_data_one.h"
+#include "pack.h"
+
+static git_odb *_odb;
+
+void test_odb_packed_one__initialize(void)
+{
+ git_odb_backend *backend = NULL;
+
+ cl_git_pass(git_odb_new(&_odb));
+ cl_git_pass(git_odb_backend_one_pack(&backend, cl_fixture("testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx")));
+ cl_git_pass(git_odb_add_backend(_odb, backend, 1));
+}
+
+void test_odb_packed_one__cleanup(void)
+{
+ git_odb_free(_odb);
+}
+
+void test_odb_packed_one__mass_read(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(packed_objects_one); ++i) {
+ git_oid id;
+ git_odb_object *obj;
+
+ cl_git_pass(git_oid_fromstr(&id, packed_objects_one[i]));
+ cl_assert(git_odb_exists(_odb, &id) == 1);
+ cl_git_pass(git_odb_read(&obj, _odb, &id));
+
+ git_odb_object_free(obj);
+ }
+}
+
+void test_odb_packed_one__read_header_0(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(packed_objects_one); ++i) {
+ git_oid id;
+ git_odb_object *obj;
+ size_t len;
+ git_otype type;
+
+ cl_git_pass(git_oid_fromstr(&id, packed_objects_one[i]));
+
+ cl_git_pass(git_odb_read(&obj, _odb, &id));
+ cl_git_pass(git_odb_read_header(&len, &type, _odb, &id));
+
+ cl_assert(obj->raw.len == len);
+ cl_assert(obj->raw.type == type);
+
+ git_odb_object_free(obj);
+ }
+}
diff --git a/tests-clar/refs/branches/foreach.c b/tests-clar/refs/branches/foreach.c
index 794233cc9..aca11ecd9 100644
--- a/tests-clar/refs/branches/foreach.c
+++ b/tests-clar/refs/branches/foreach.c
@@ -47,7 +47,7 @@ static void assert_retrieval(unsigned int flags, unsigned int expected_count)
void test_refs_branches_foreach__retrieve_all_branches(void)
{
- assert_retrieval(GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, 11);
+ assert_retrieval(GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, 13);
}
void test_refs_branches_foreach__retrieve_remote_branches(void)
@@ -57,7 +57,7 @@ void test_refs_branches_foreach__retrieve_remote_branches(void)
void test_refs_branches_foreach__retrieve_local_branches(void)
{
- assert_retrieval(GIT_BRANCH_LOCAL, 9);
+ assert_retrieval(GIT_BRANCH_LOCAL, 11);
}
struct expectations {
@@ -125,3 +125,28 @@ void test_refs_branches_foreach__retrieve_remote_symbolic_HEAD_when_present(void
assert_branch_has_been_found(exp, "nulltoken/HEAD");
assert_branch_has_been_found(exp, "nulltoken/HEAD");
}
+
+static int branch_list_interrupt_cb(
+ const char *branch_name, git_branch_t branch_type, void *payload)
+{
+ int *count;
+
+ GIT_UNUSED(branch_type);
+ GIT_UNUSED(branch_name);
+
+ count = (int *)payload;
+ (*count)++;
+
+ return (*count == 5);
+}
+
+void test_refs_branches_foreach__can_cancel(void)
+{
+ int count = 0;
+
+ cl_assert_equal_i(GIT_EUSER,
+ git_branch_foreach(repo, GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE,
+ branch_list_interrupt_cb, &count));
+
+ cl_assert_equal_i(5, count);
+}
diff --git a/tests-clar/refs/foreachglob.c b/tests-clar/refs/foreachglob.c
index b024d36d4..054846fe6 100644
--- a/tests-clar/refs/foreachglob.c
+++ b/tests-clar/refs/foreachglob.c
@@ -45,8 +45,8 @@ static void assert_retrieval(const char *glob, unsigned int flags, int expected_
void test_refs_foreachglob__retrieve_all_refs(void)
{
- /* 7 heads (including one packed head) + 1 note + 2 remotes + 6 tags */
- assert_retrieval("*", GIT_REF_LISTALL, 18);
+ /* 8 heads (including one packed head) + 1 note + 2 remotes + 6 tags */
+ assert_retrieval("*", GIT_REF_LISTALL, 20);
}
void test_refs_foreachglob__retrieve_remote_branches(void)
@@ -56,7 +56,7 @@ void test_refs_foreachglob__retrieve_remote_branches(void)
void test_refs_foreachglob__retrieve_local_branches(void)
{
- assert_retrieval("refs/heads/*", GIT_REF_LISTALL, 9);
+ assert_retrieval("refs/heads/*", GIT_REF_LISTALL, 11);
}
void test_refs_foreachglob__retrieve_partially_named_references(void)
@@ -68,3 +68,25 @@ void test_refs_foreachglob__retrieve_partially_named_references(void)
assert_retrieval("*test*", GIT_REF_LISTALL, 4);
}
+
+
+static int interrupt_cb(const char *reference_name, void *payload)
+{
+ int *count = (int *)payload;
+
+ GIT_UNUSED(reference_name);
+
+ (*count)++;
+
+ return (*count == 11);
+}
+
+void test_refs_foreachglob__can_cancel(void)
+{
+ int count = 0;
+
+ cl_assert_equal_i(GIT_EUSER, git_reference_foreach_glob(
+ repo, "*", GIT_REF_LISTALL, interrupt_cb, &count) );
+
+ cl_assert_equal_i(11, count);
+}
diff --git a/tests-clar/refs/read.c b/tests-clar/refs/read.c
index 1948e0a56..f33658754 100644
--- a/tests-clar/refs/read.c
+++ b/tests-clar/refs/read.c
@@ -193,6 +193,30 @@ void test_refs_read__loose_first(void)
git_reference_free(reference);
}
+void test_refs_read__chomped(void)
+{
+ git_reference *test, *chomped;
+
+ cl_git_pass(git_reference_lookup(&test, g_repo, "refs/heads/test"));
+ cl_git_pass(git_reference_lookup(&chomped, g_repo, "refs/heads/chomped"));
+ cl_git_pass(git_oid_cmp(git_reference_oid(test), git_reference_oid(chomped)));
+
+ git_reference_free(test);
+ git_reference_free(chomped);
+}
+
+void test_refs_read__trailing(void)
+{
+ git_reference *test, *trailing;
+
+ cl_git_pass(git_reference_lookup(&test, g_repo, "refs/heads/test"));
+ cl_git_pass(git_reference_lookup(&trailing, g_repo, "refs/heads/trailing"));
+ cl_git_pass(git_oid_cmp(git_reference_oid(test), git_reference_oid(trailing)));
+
+ git_reference_free(test);
+ git_reference_free(trailing);
+}
+
void test_refs_read__unfound_return_ENOTFOUND(void)
{
git_reference *reference;
diff --git a/tests-clar/repo/message.c b/tests-clar/repo/message.c
new file mode 100644
index 000000000..4a6f13b9d
--- /dev/null
+++ b/tests-clar/repo/message.c
@@ -0,0 +1,47 @@
+#include "clar_libgit2.h"
+#include "buffer.h"
+#include "refs.h"
+#include "posix.h"
+
+static git_repository *_repo;
+static git_buf _path;
+static char *_actual;
+
+void test_repo_message__initialize(void)
+{
+ _repo = cl_git_sandbox_init("testrepo.git");
+}
+
+void test_repo_message__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+ git_buf_free(&_path);
+ git__free(_actual);
+ _actual = NULL;
+}
+
+void test_repo_message__none(void)
+{
+ cl_assert_equal_i(GIT_ENOTFOUND, git_repository_message(NULL, 0, _repo));
+}
+
+void test_repo_message__message(void)
+{
+ const char expected[] = "Test\n\nThis is a test of the emergency broadcast system\n";
+ ssize_t len;
+
+ cl_git_pass(git_buf_joinpath(&_path, git_repository_path(_repo), "MERGE_MSG"));
+ cl_git_mkfile(git_buf_cstr(&_path), expected);
+
+ len = git_repository_message(NULL, 0, _repo);
+ cl_assert(len > 0);
+ _actual = git__malloc(len + 1);
+ cl_assert(_actual != NULL);
+
+ cl_assert(git_repository_message(_actual, len, _repo) > 0);
+ _actual[len] = '\0';
+ cl_assert_equal_s(expected, _actual);
+
+ cl_git_pass(p_unlink(git_buf_cstr(&_path)));
+ cl_assert_equal_i(GIT_ENOTFOUND, git_repository_message(NULL, 0, _repo));
+}
diff --git a/tests-clar/resources/config/config14 b/tests-clar/resources/config/config14
new file mode 100644
index 000000000..ef2198c45
--- /dev/null
+++ b/tests-clar/resources/config/config14
@@ -0,0 +1,4 @@
+[a]
+ b=c
+[d]
+ e = f
diff --git a/tests-clar/resources/testrepo.git/refs/heads/chomped b/tests-clar/resources/testrepo.git/refs/heads/chomped
new file mode 100644
index 000000000..0166a7f92
--- /dev/null
+++ b/tests-clar/resources/testrepo.git/refs/heads/chomped
@@ -0,0 +1 @@
+e90810b8df3e80c413d903f631643c716887138d \ No newline at end of file
diff --git a/tests-clar/resources/testrepo.git/refs/heads/trailing b/tests-clar/resources/testrepo.git/refs/heads/trailing
new file mode 100644
index 000000000..2a4a6e62f
--- /dev/null
+++ b/tests-clar/resources/testrepo.git/refs/heads/trailing
@@ -0,0 +1 @@
+e90810b8df3e80c413d903f631643c716887138d
diff --git a/tests-clar/status/worktree.c b/tests-clar/status/worktree.c
index 6e21e44bf..2abf36833 100644
--- a/tests-clar/status/worktree.c
+++ b/tests-clar/status/worktree.c
@@ -530,7 +530,7 @@ void test_status_worktree__bracket_in_filename(void)
cl_git_pass(git_repository_init(&repo, "with_bracket", 0));
cl_git_mkfile("with_bracket/" FILE_WITH_BRACKET, "I have a bracket in my name\n");
-
+
/* file is new to working directory */
memset(&result, 0, sizeof(result));
@@ -578,7 +578,7 @@ void test_status_worktree__bracket_in_filename(void)
cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_BRACKET));
cl_assert(status_flags == GIT_STATUS_INDEX_NEW);
-
+
/* Create file without bracket */
cl_git_mkfile("with_bracket/" FILE_WITHOUT_BRACKET, "I have no bracket in my name!\n");
@@ -591,7 +591,7 @@ void test_status_worktree__bracket_in_filename(void)
error = git_status_file(&status_flags, repo, FILE_WITH_BRACKET);
cl_git_fail(error);
- cl_assert(error == GIT_EAMBIGUOUS);
+ cl_assert_equal_i(GIT_EAMBIGUOUS, error);
git_index_free(index);
git_repository_free(repo);
@@ -769,6 +769,31 @@ void test_status_worktree__disable_pathspec_match(void)
cl_git_pass(
git_status_foreach_ext(repo, &opts, cb_status__expected_path, NULL)
);
-
+
git_repository_free(repo);
}
+
+
+static int cb_status__interrupt(const char *p, unsigned int s, void *payload)
+{
+ volatile int *count = (int *)payload;
+
+ GIT_UNUSED(p);
+ GIT_UNUSED(s);
+
+ (*count)++;
+
+ return (*count == 8);
+}
+
+void test_status_worktree__interruptable_foreach(void)
+{
+ int count = 0;
+ git_repository *repo = cl_git_sandbox_init("status");
+
+ cl_assert_equal_i(
+ GIT_EUSER, git_status_foreach(repo, cb_status__interrupt, &count)
+ );
+
+ cl_assert_equal_i(8, count);
+}