summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/commit.c40
-rw-r--r--src/merge.c11
-rw-r--r--src/posix.h13
-rw-r--r--src/revparse.c3
-rw-r--r--src/revwalk.c72
-rw-r--r--src/strnlen.h23
-rw-r--r--src/util.h4
7 files changed, 85 insertions, 81 deletions
diff --git a/src/commit.c b/src/commit.c
index b9c21f3cd..d66cf0c6a 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -183,33 +183,15 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
const char *buffer_start = git_odb_object_data(odb_obj), *buffer;
const char *buffer_end = buffer_start + git_odb_object_size(odb_obj);
git_oid parent_id;
- uint32_t parent_count = 0;
size_t header_len;
- /* find end-of-header (counting parents as we go) */
- for (buffer = buffer_start; buffer < buffer_end; ++buffer) {
- if (!strncmp("\n\n", buffer, 2)) {
- ++buffer;
- break;
- }
- if (!strncmp("\nparent ", buffer, strlen("\nparent ")))
- ++parent_count;
- }
-
- header_len = buffer - buffer_start;
- commit->raw_header = git__strndup(buffer_start, header_len);
- GITERR_CHECK_ALLOC(commit->raw_header);
+ buffer = buffer_start;
- /* point "buffer" to header data */
- buffer = commit->raw_header;
- buffer_end = commit->raw_header + header_len;
-
- if (parent_count < 1)
- parent_count = 1;
-
- git_array_init_to_size(commit->parent_ids, parent_count);
+ /* Allocate for one, which will allow not to realloc 90% of the time */
+ git_array_init_to_size(commit->parent_ids, 1);
GITERR_CHECK_ARRAY(commit->parent_ids);
+ /* The tree is always the first field */
if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0)
goto bad_buffer;
@@ -240,6 +222,9 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
/* Parse add'l header entries */
while (buffer < buffer_end) {
const char *eoln = buffer;
+ if (buffer[-1] == '\n' && buffer[0] == '\n')
+ break;
+
while (eoln < buffer_end && *eoln != '\n')
++eoln;
@@ -255,13 +240,12 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
buffer = eoln;
}
- /* point "buffer" to data after header */
- buffer = git_odb_object_data(odb_obj);
- buffer_end = buffer + git_odb_object_size(odb_obj);
+ header_len = buffer - buffer_start;
+ commit->raw_header = git__strndup(buffer_start, header_len);
+ GITERR_CHECK_ALLOC(commit->raw_header);
- buffer += header_len;
- if (*buffer == '\n')
- ++buffer;
+ /* point "buffer" to data after header, +1 for the final LF */
+ buffer = buffer_start + header_len + 1;
/* extract commit message */
if (buffer <= buffer_end) {
diff --git a/src/merge.c b/src/merge.c
index 20cfc0e23..ac973efd0 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -2330,7 +2330,7 @@ done:
static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths)
{
- git_tree *head_tree = NULL;
+ git_index *index_repo = NULL;
git_diff *wd_diff_list = NULL;
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
int error = 0;
@@ -2341,9 +2341,6 @@ static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_inde
opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
- if ((error = git_repository_head_tree(&head_tree, repo)) < 0)
- goto done;
-
/* Workdir changes may exist iff they do not conflict with changes that
* will be applied by the merge (including conflicts). Ensure that there
* are no changes in the workdir to these paths.
@@ -2351,13 +2348,13 @@ static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_inde
opts.pathspec.count = merged_paths->length;
opts.pathspec.strings = (char **)merged_paths->contents;
- if ((error = git_diff_tree_to_workdir(&wd_diff_list, repo, head_tree, &opts)) < 0)
+ if ((error = git_diff_index_to_workdir(&wd_diff_list, repo, index_repo, &opts)) < 0)
goto done;
*conflicts = wd_diff_list->deltas.length;
done:
- git_tree_free(head_tree);
+ git_index_free(index_repo);
git_diff_free(wd_diff_list);
return error;
@@ -2400,7 +2397,7 @@ int git_merge__indexes(git_repository *repo, git_index *index_new)
/* Remove removed items from the index */
git_vector_foreach(&paths, i, path) {
- if ((e = git_index_get_bypath(index_new, path, 0)) == NULL) {
+ if (git_index_get_bypath(index_new, path, 0) == NULL) {
if ((error = git_index_remove(index_repo, path, 0)) < 0 &&
error != GIT_ENOTFOUND)
goto done;
diff --git a/src/posix.h b/src/posix.h
index 0d9be49a9..6d3a84eba 100644
--- a/src/posix.h
+++ b/src/posix.h
@@ -89,18 +89,7 @@ extern struct tm * p_gmtime_r (const time_t *timer, struct tm *result);
# include "unix/posix.h"
#endif
-#if defined(__MINGW32__) || defined(__sun) || defined(__APPLE__)
-# define NO_STRNLEN
-#endif
-
-#ifdef NO_STRNLEN
-GIT_INLINE(size_t) p_strnlen(const char *s, size_t maxlen) {
- const char *end = memchr(s, 0, maxlen);
- return end ? (size_t)(end - s) : maxlen;
-}
-#else
-# define p_strnlen strnlen
-#endif
+#include "strnlen.h"
#ifdef NO_READDIR_R
# include <dirent.h>
diff --git a/src/revparse.c b/src/revparse.c
index 5cce3be63..60872e187 100644
--- a/src/revparse.c
+++ b/src/revparse.c
@@ -490,8 +490,7 @@ static int handle_grep_syntax(git_object **out, git_repository *repo, const git_
git_revwalk_sorting(walk, GIT_SORT_TIME);
if (spec_oid == NULL) {
- // TODO: @carlosmn: The glob should be refs/* but this makes git_revwalk_next() fails
- if ((error = git_revwalk_push_glob(walk, GIT_REFS_HEADS_DIR "*")) < 0)
+ if ((error = git_revwalk_push_glob(walk, "refs/*")) < 0)
goto cleanup;
} else if ((error = git_revwalk_push(walk, spec_oid)) < 0)
goto cleanup;
diff --git a/src/revwalk.c b/src/revwalk.c
index c0a053211..628057fcd 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -110,25 +110,34 @@ static int process_commit_parents(git_revwalk *walk, git_commit_list_node *commi
return error;
}
-static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
+static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, int from_glob)
{
+ git_oid commit_id;
int error;
- git_object *obj;
- git_otype type;
+ git_object *obj, *oobj;
git_commit_list_node *commit;
- if ((error = git_object_lookup(&obj, walk->repo, oid, GIT_OBJ_ANY)) < 0)
+ if ((error = git_object_lookup(&oobj, walk->repo, oid, GIT_OBJ_ANY)) < 0)
return error;
- type = git_object_type(obj);
- git_object_free(obj);
+ error = git_object_peel(&obj, oobj, GIT_OBJ_COMMIT);
+ git_object_free(oobj);
+
+ if (error == GIT_ENOTFOUND) {
+ /* If this comes from e.g. push_glob("tags"), ignore this */
+ if (from_glob)
+ return 0;
- if (type != GIT_OBJ_COMMIT) {
- giterr_set(GITERR_INVALID, "Object is no commit object");
+ giterr_set(GITERR_INVALID, "Object is not a committish");
return -1;
}
+ if (error < 0)
+ return error;
+
+ git_oid_cpy(&commit_id, git_object_id(obj));
+ git_object_free(obj);
- commit = git_revwalk__commit_lookup(walk, oid);
+ commit = git_revwalk__commit_lookup(walk, &commit_id);
if (commit == NULL)
return -1; /* error already reported by failed lookup */
@@ -146,24 +155,24 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
int git_revwalk_push(git_revwalk *walk, const git_oid *oid)
{
assert(walk && oid);
- return push_commit(walk, oid, 0);
+ return push_commit(walk, oid, 0, false);
}
int git_revwalk_hide(git_revwalk *walk, const git_oid *oid)
{
assert(walk && oid);
- return push_commit(walk, oid, 1);
+ return push_commit(walk, oid, 1, false);
}
-static int push_ref(git_revwalk *walk, const char *refname, int hide)
+static int push_ref(git_revwalk *walk, const char *refname, int hide, int from_glob)
{
git_oid oid;
if (git_reference_name_to_id(&oid, walk->repo, refname) < 0)
return -1;
- return push_commit(walk, &oid, hide);
+ return push_commit(walk, &oid, hide, from_glob);
}
struct push_cb_data {
@@ -171,17 +180,12 @@ struct push_cb_data {
int hide;
};
-static int push_glob_cb(const char *refname, void *data_)
-{
- struct push_cb_data *data = (struct push_cb_data *)data_;
- return push_ref(data->walk, refname, data->hide);
-}
-
static int push_glob(git_revwalk *walk, const char *glob, int hide)
{
int error = 0;
git_buf buf = GIT_BUF_INIT;
- struct push_cb_data data;
+ git_reference *ref;
+ git_reference_iterator *iter;
size_t wildcard;
assert(walk && glob);
@@ -199,12 +203,20 @@ static int push_glob(git_revwalk *walk, const char *glob, int hide)
if (!glob[wildcard])
git_buf_put(&buf, "/*", 2);
- data.walk = walk;
- data.hide = hide;
+ if ((error = git_reference_iterator_glob_new(&iter, walk->repo, buf.ptr)) < 0)
+ goto out;
- error = git_reference_foreach_glob(
- walk->repo, git_buf_cstr(&buf), push_glob_cb, &data);
+ while ((error = git_reference_next(&ref, iter)) == 0) {
+ error = push_ref(walk, git_reference_name(ref), hide, true);
+ git_reference_free(ref);
+ if (error < 0)
+ break;
+ }
+ git_reference_iterator_free(iter);
+ if (error == GIT_ITEROVER)
+ error = 0;
+out:
git_buf_free(&buf);
return error;
}
@@ -224,19 +236,19 @@ int git_revwalk_hide_glob(git_revwalk *walk, const char *glob)
int git_revwalk_push_head(git_revwalk *walk)
{
assert(walk);
- return push_ref(walk, GIT_HEAD_FILE, 0);
+ return push_ref(walk, GIT_HEAD_FILE, 0, false);
}
int git_revwalk_hide_head(git_revwalk *walk)
{
assert(walk);
- return push_ref(walk, GIT_HEAD_FILE, 1);
+ return push_ref(walk, GIT_HEAD_FILE, 1, false);
}
int git_revwalk_push_ref(git_revwalk *walk, const char *refname)
{
assert(walk && refname);
- return push_ref(walk, refname, 0);
+ return push_ref(walk, refname, 0, false);
}
int git_revwalk_push_range(git_revwalk *walk, const char *range)
@@ -253,10 +265,10 @@ int git_revwalk_push_range(git_revwalk *walk, const char *range)
return GIT_EINVALIDSPEC;
}
- if ((error = push_commit(walk, git_object_id(revspec.from), 1)))
+ if ((error = push_commit(walk, git_object_id(revspec.from), 1, false)))
goto out;
- error = push_commit(walk, git_object_id(revspec.to), 0);
+ error = push_commit(walk, git_object_id(revspec.to), 0, false);
out:
git_object_free(revspec.from);
@@ -267,7 +279,7 @@ out:
int git_revwalk_hide_ref(git_revwalk *walk, const char *refname)
{
assert(walk && refname);
- return push_ref(walk, refname, 1);
+ return push_ref(walk, refname, 1, false);
}
static int revwalk_enqueue_timesort(git_revwalk *walk, git_commit_list_node *commit)
diff --git a/src/strnlen.h b/src/strnlen.h
new file mode 100644
index 000000000..007da2e55
--- /dev/null
+++ b/src/strnlen.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_strlen_h__
+#define INCLUDE_strlen_h__
+
+#if defined(__MINGW32__) || defined(__sun) || defined(__APPLE__)
+# define NO_STRNLEN
+#endif
+
+#ifdef NO_STRNLEN
+GIT_INLINE(size_t) p_strnlen(const char *s, size_t maxlen) {
+ const char *end = memchr(s, 0, maxlen);
+ return end ? (size_t)(end - s) : maxlen;
+}
+#else
+# define p_strnlen strnlen
+#endif
+
+#endif
diff --git a/src/util.h b/src/util.h
index f9de909e9..e378786d9 100644
--- a/src/util.h
+++ b/src/util.h
@@ -8,6 +8,7 @@
#define INCLUDE_util_h__
#include "common.h"
+#include "strnlen.h"
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define bitsizeof(x) (CHAR_BIT * sizeof(x))
@@ -50,8 +51,7 @@ GIT_INLINE(char *) git__strndup(const char *str, size_t n)
size_t length = 0;
char *ptr;
- while (length < n && str[length])
- ++length;
+ length = p_strnlen(str, n);
ptr = (char*)git__malloc(length + 1);