summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2014-05-12 14:38:39 -0700
committerRussell Belfer <rb@github.com>2014-05-15 14:11:19 -0700
commit575f107704255254f52d197240d55f2030af0454 (patch)
treeaf5149788297f3e9ec17992b342a3005eab36e31
parent88b1b36dfcc6b406f2b6f21e0e042071984b3b90 (diff)
downloadlibgit2-rb/object-parse-flexibility.tar.gz
Add lax parsing for commit and tag objectsrb/object-parse-flexibility
This changes the behavior of object parsing for commits and tags so that even when bad data is found inside the object, we will continue to try to parse as much of the object as we can. The existing functions (`git_object_lookup` for example) will still delete the partially parsed object before returning an error, but this also adds a new function `git_object_lookup_lax` that will still return the error, but will also return the object with the partial data (if we got far enough along in the parsing process to even create the base object).
-rw-r--r--include/git2/object.h73
-rw-r--r--src/commit.c92
-rw-r--r--src/commit.h2
-rw-r--r--src/diff_file.c2
-rw-r--r--src/diff_tform.c2
-rw-r--r--src/object.c380
-rw-r--r--src/object.h45
-rw-r--r--src/odb.c2
-rw-r--r--src/odb_loose.c2
-rw-r--r--src/oid.c26
-rw-r--r--src/signature.c40
-rw-r--r--src/signature.h1
-rw-r--r--src/tag.c203
-rw-r--r--src/util.h6
-rw-r--r--tests/commit/parse.c76
-rw-r--r--tests/object/raw/type2string.c22
-rw-r--r--tests/odb/loose.c2
17 files changed, 569 insertions, 407 deletions
diff --git a/include/git2/object.h b/include/git2/object.h
index 9b13d824e..cd67711e8 100644
--- a/include/git2/object.h
+++ b/include/git2/object.h
@@ -33,17 +33,18 @@ GIT_BEGIN_DECL
* The special value 'GIT_OBJ_ANY' may be passed to let
* the method guess the object's type.
*
- * @param object pointer to the looked-up object
+ * @param out Pointer in which to store the looked-up object (must be
+ * freed by the caller when done)
* @param repo the repository to look up the object
* @param id the unique identifier for the object
* @param type the type of the object
* @return 0 or an error code
*/
GIT_EXTERN(int) git_object_lookup(
- git_object **object,
- git_repository *repo,
- const git_oid *id,
- git_otype type);
+ git_object **out,
+ git_repository *repo,
+ const git_oid *id,
+ git_otype type);
/**
* Lookup a reference to one of the objects in a repository,
@@ -65,7 +66,8 @@ GIT_EXTERN(int) git_object_lookup(
* The special value 'GIT_OBJ_ANY' may be passed to let
* the method guess the object's type.
*
- * @param object_out pointer where to store the looked-up object
+ * @param out Pointer in which to store the looked-up object (must be
+ * freed by the caller when done)
* @param repo the repository to look up the object
* @param id a short identifier for the object
* @param len the length of the short identifier
@@ -73,28 +75,56 @@ GIT_EXTERN(int) git_object_lookup(
* @return 0 or an error code
*/
GIT_EXTERN(int) git_object_lookup_prefix(
- git_object **object_out,
- git_repository *repo,
- const git_oid *id,
- size_t len,
- git_otype type);
+ git_object **out,
+ git_repository *repo,
+ const git_oid *id,
+ size_t len,
+ git_otype type);
/**
* Lookup an object that represents a tree entry.
*
- * @param out buffer that receives a pointer to the object (which must be freed
- * by the caller)
+ * @param out Pointer in which to store the looked-up object (must be
+ * freed by the caller when done)
* @param treeish root object that can be peeled to a tree
* @param path relative path from the root object to the desired object
* @param type type of object desired
* @return 0 on success, or an error code
*/
GIT_EXTERN(int) git_object_lookup_bypath(
- git_object **out,
- const git_object *treeish,
- const char *path,
- git_otype type);
+ git_object **out,
+ const git_object *treeish,
+ const char *path,
+ git_otype type);
+
+/**
+ * Look up object by partial or full OID and type, trying to return the
+ * object even if a parse error is encountered.
+ *
+ * Unlike other APIs to look up objects, this tries to return a
+ * `git_object` even if the data is not well-formatted, so long as the
+ * basic object type can still be determined from the raw data.
+ *
+ * If the object does not parse correctly, this will still return an error
+ * code, but it will also set the `out` parameter to an object with as
+ * much data filled in as possible. The resulting object may return NULL
+ * for properties that should not be NULL or other strange things.
+ *
+ * @param out Pointer in which to store the looked-up object (must be
+ * freed by the caller when done)
+ * @param repo the repository to look up the object
+ * @param id a short identifier for the object
+ * @param len the length of the short identifier
+ * @param type the type of the object
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_object_lookup_lax(
+ git_object **out,
+ git_repository *repo,
+ const git_oid *id,
+ size_t len,
+ git_otype type);
/**
* Get the id (SHA1) of a repository object
@@ -169,12 +199,13 @@ GIT_EXTERN(void) git_object_free(git_object *object);
GIT_EXTERN(const char *) git_object_type2string(git_otype type);
/**
- * Convert a string object type representation to it's git_otype.
+ * Convert a string object type representation to its git_otype.
*
- * @param str the string to convert.
- * @return the corresponding git_otype.
+ * @param str The string to convert.
+ * @param len Length of str (or 0 for unspecified but NUL-terminated input)
+ * @return The corresponding `git_otype` of `GIT_OBJ_BAD` if no match.
*/
-GIT_EXTERN(git_otype) git_object_string2type(const char *str);
+GIT_EXTERN(git_otype) git_object_string2type(const char *str, size_t len);
/**
* Determine if the given git_otype is a valid loose object type.
diff --git a/src/commit.c b/src/commit.c
index 227d5c4a5..1388cb3f5 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -328,87 +328,41 @@ int git_commit_amend(
return error;
}
-int git_commit__parse(void *_commit, git_odb_object *odb_obj)
+int git_commit__parse(void *obj, git_odb_object *odb_obj)
{
- git_commit *commit = _commit;
- 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;
- size_t header_len;
-
- buffer = buffer_start;
+ int error = 0;
+ const char *start = git_odb_object_data(odb_obj);
+ const char *end = start + git_odb_object_size(odb_obj);
+ const char *body = NULL;
+ git_commit *commit = obj;
+ git_object_parse_t parser[] = {
+ { "tree", 4, GIT_PARSE_OID, { .id = &commit->tree_id } },
+ { "parent", 6, GIT_PARSE_OID_ARRAY, { .ids = &commit->parent_ids } },
+ { "author", 6, GIT_PARSE_SIGNATURE, { .sig = &commit->author } },
+ { "committer", 9, GIT_PARSE_SIGNATURE, { .sig = &commit->committer } },
+ { NULL, 0, GIT_PARSE_MODE_OPTIONAL },
+ { "encoding", 8, GIT_PARSE_TO_EOL, { .text = &commit->message_encoding } },
+ { NULL, 0, GIT_PARSE_BODY, { .body = &body } },
+ };
/* 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;
-
- /*
- * TODO: commit grafts!
- */
-
- while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) {
- git_oid *new_id = git_array_alloc(commit->parent_ids);
- GITERR_CHECK_ALLOC(new_id);
-
- git_oid_cpy(new_id, &parent_id);
- }
-
- commit->author = git__malloc(sizeof(git_signature));
- GITERR_CHECK_ALLOC(commit->author);
-
- if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0)
- return -1;
-
- /* Always parse the committer; we need the commit time */
- commit->committer = git__malloc(sizeof(git_signature));
- GITERR_CHECK_ALLOC(commit->committer);
-
- if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0)
- return -1;
-
- /* 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;
+ error = git_object__parse_lines(GIT_OBJ_COMMIT, parser, start, end);
- if (git__prefixcmp(buffer, "encoding ") == 0) {
- buffer += strlen("encoding ");
-
- commit->message_encoding = git__strndup(buffer, eoln - buffer);
- GITERR_CHECK_ALLOC(commit->message_encoding);
+ /* strdup raw version of header data and commit message */
+ if (body != NULL) {
+ if (body > start) {
+ commit->raw_header = git__strndup(start, (body - 1) - start);
+ GITERR_CHECK_ALLOC(commit->raw_header);
}
- if (eoln < buffer_end && *eoln == '\n')
- ++eoln;
- buffer = eoln;
- }
-
- header_len = buffer - buffer_start;
- commit->raw_header = git__strndup(buffer_start, header_len);
- GITERR_CHECK_ALLOC(commit->raw_header);
-
- /* point "buffer" to data after header, +1 for the final LF */
- buffer = buffer_start + header_len + 1;
-
- /* extract commit message */
- if (buffer <= buffer_end) {
- commit->raw_message = git__strndup(buffer, buffer_end - buffer);
+ commit->raw_message = git__strndup(body, end - body);
GITERR_CHECK_ALLOC(commit->raw_message);
}
- return 0;
-
-bad_buffer:
- giterr_set(GITERR_OBJECT, "Failed to parse bad commit object");
- return -1;
+ return error;
}
#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
diff --git a/src/commit.h b/src/commit.h
index efb080b50..45d7e29e3 100644
--- a/src/commit.h
+++ b/src/commit.h
@@ -17,7 +17,7 @@
struct git_commit {
git_object object;
- git_array_t(git_oid) parent_ids;
+ git_oid_array parent_ids;
git_oid tree_id;
git_signature *author;
diff --git a/src/diff_file.c b/src/diff_file.c
index f2a1d5099..a53dfab91 100644
--- a/src/diff_file.c
+++ b/src/diff_file.c
@@ -240,7 +240,7 @@ static int diff_file_content_load_blob(git_diff_file_content *fc)
if (odb_obj != NULL) {
error = git_object__from_odb_object(
- (git_object **)&fc->blob, fc->repo, odb_obj, GIT_OBJ_BLOB);
+ (git_object **)&fc->blob, fc->repo, odb_obj, GIT_OBJ_BLOB, true);
git_odb_object_free(odb_obj);
} else {
error = git_blob_lookup(
diff --git a/src/diff_tform.c b/src/diff_tform.c
index a2dab0ae2..4d5359edc 100644
--- a/src/diff_tform.c
+++ b/src/diff_tform.c
@@ -508,7 +508,7 @@ static int similarity_sig(
if (info->odb_obj != NULL)
error = git_object__from_odb_object(
(git_object **)&info->blob, info->repo,
- info->odb_obj, GIT_OBJ_BLOB);
+ info->odb_obj, GIT_OBJ_BLOB, true);
else
error = git_blob_lookup(&info->blob, info->repo, &file->id);
diff --git a/src/object.c b/src/object.c
index 93068b85f..2e0f0e5d4 100644
--- a/src/object.c
+++ b/src/object.c
@@ -13,6 +13,7 @@
#include "tree.h"
#include "blob.h"
#include "tag.h"
+#include "signature.h"
static const int OBJECT_BASE_SIZE = 4096;
@@ -48,26 +49,36 @@ static git_object_def git_objects_table[] = {
{ "REF_DELTA", 0, NULL, NULL },
};
+static int git_object__match_cache(git_otype type, git_otype cached)
+{
+ if (type == GIT_OBJ_ANY || type == cached)
+ return 0;
+
+ giterr_set(
+ GITERR_INVALID,
+ "Requested object type (%s) does not match type in ODB (%s)",
+ git_object_type2string(type), git_object_type2string(cached));
+ return GIT_ENOTFOUND;
+}
+
int git_object__from_odb_object(
- git_object **object_out,
+ git_object **out,
git_repository *repo,
git_odb_object *odb_obj,
- git_otype type)
+ git_otype type,
+ bool lax)
{
int error;
size_t object_size;
git_object_def *def;
git_object *object = NULL;
- assert(object_out);
- *object_out = NULL;
+ assert(out);
+ *out = NULL;
/* Validate type match */
- if (type != GIT_OBJ_ANY && type != odb_obj->cached.type) {
- giterr_set(GITERR_INVALID,
- "The requested type does not match the type in the ODB");
- return GIT_ENOTFOUND;
- }
+ if ((error = git_object__match_cache(type, odb_obj->cached.type)) < 0)
+ return error;
if ((object_size = git_object__size(odb_obj->cached.type)) == 0) {
giterr_set(GITERR_INVALID, "The requested type is invalid");
@@ -87,10 +98,14 @@ int git_object__from_odb_object(
def = &git_objects_table[odb_obj->cached.type];
assert(def->free && def->parse);
- if ((error = def->parse(object, odb_obj)) < 0)
- def->free(object);
- else
- *object_out = git_cache_store_parsed(&repo->objects, object);
+ if ((error = def->parse(object, odb_obj)) < 0) {
+ if (lax) /* do not put invalid objects into cache */
+ *out = object;
+ else
+ def->free(object);
+ } else {
+ *out = git_cache_store_parsed(&repo->objects, object);
+ }
return error;
}
@@ -106,27 +121,33 @@ void git_object__free(void *obj)
git_objects_table[type].free(obj);
}
-int git_object_lookup_prefix(
- git_object **object_out,
+static int object_lookup(
+ git_object **out,
git_repository *repo,
const git_oid *id,
size_t len,
- git_otype type)
+ git_otype type,
+ bool lax)
{
- git_object *object = NULL;
+ int error = 0;
git_odb *odb = NULL;
git_odb_object *odb_obj = NULL;
- int error = 0;
- assert(repo && object_out && id);
+ assert(repo && out && id);
if (len < GIT_OID_MINPREFIXLEN) {
- giterr_set(GITERR_OBJECT, "Ambiguous lookup - OID prefix is too short");
+ giterr_set(GITERR_OBJECT,
+ "Ambiguous lookup - OID prefix is too short (%d)", (int)len);
return GIT_EAMBIGUOUS;
}
- error = git_repository_odb__weakptr(&odb, repo);
- if (error < 0)
+ if (type != GIT_OBJ_ANY && !git_object__size(type)) {
+ giterr_set(
+ GITERR_INVALID, "The requested type (%d) is invalid", (int)type);
+ return GIT_ENOTFOUND;
+ }
+
+ if ((error = git_repository_odb__weakptr(&odb, repo)) < 0)
return error;
if (len > GIT_OID_HEXSZ)
@@ -135,77 +156,88 @@ int git_object_lookup_prefix(
if (len == GIT_OID_HEXSZ) {
git_cached_obj *cached = NULL;
- /* We want to match the full id : we can first look up in the cache,
- * since there is no need to check for non ambiguousity
- */
+ /* Full id: first look in cache, since there is no ambiguity */
cached = git_cache_get_any(&repo->objects, id);
- if (cached != NULL) {
- if (cached->flags == GIT_CACHE_STORE_PARSED) {
- object = (git_object *)cached;
-
- if (type != GIT_OBJ_ANY && type != object->cached.type) {
- git_object_free(object);
- giterr_set(GITERR_INVALID,
- "The requested type does not match the type in ODB");
- return GIT_ENOTFOUND;
- }
-
- *object_out = object;
- return 0;
- } else if (cached->flags == GIT_CACHE_STORE_RAW) {
- odb_obj = (git_odb_object *)cached;
- } else {
- assert(!"Wrong caching type in the global object cache");
- }
- } else {
- /* Object was not found in the cache, let's explore the backends.
- * We could just use git_odb_read_unique_short_oid,
- * it is the same cost for packed and loose object backends,
- * but it may be much more costly for sqlite and hiredis.
- */
+
+ if (!cached)
+ /* Object not found in cache, so search backends */
error = git_odb_read(&odb_obj, odb, id);
+ else if (cached->flags == GIT_CACHE_STORE_PARSED) {
+ if ((error = git_object__match_cache(type, cached->type)) < 0)
+ git_object_free((git_object *)cached);
+ else
+ *out = (git_object *)cached;
+ return error;
}
+ else if (cached->flags == GIT_CACHE_STORE_RAW)
+ odb_obj = (git_odb_object *)cached;
+ else
+ assert(!"Wrong caching type in the global object cache");
} else {
- git_oid short_oid;
+ git_oid short_oid = {{0}};
- /* We copy the first len*4 bits from id and fill the remaining with 0s */
+ /* Copy first len*4 bits from id and fill the remaining with 0s */
memcpy(short_oid.id, id->id, (len + 1) / 2);
if (len % 2)
short_oid.id[len / 2] &= 0xF0;
- memset(short_oid.id + (len + 1) / 2, 0, (GIT_OID_HEXSZ - len) / 2);
-
- /* If len < GIT_OID_HEXSZ (a strict short oid was given), we have
- * 2 options :
- * - We always search in the cache first. If we find that short oid is
- * ambiguous, we can stop. But in all the other cases, we must then
- * explore all the backends (to find an object if there was match,
- * or to check that oid is not ambiguous if we have found 1 match in
- * the cache)
- * - We never explore the cache, go right to exploring the backends
- * We chose the latter : we explore directly the backends.
+
+ /* If len < GIT_OID_HEXSZ (short oid), we have 2 options:
+ *
+ * - We always search in the cache first. If we find that short
+ * oid is ambiguous, we can stop. But in all the other cases, we
+ * must then explore all the backends (to find an object if
+ * there was match, or to check that oid is not ambiguous if we
+ * have found 1 match in the cache)
+ *
+ * - We never explore the cache, go right to exploring the
+ * backends We chose the latter : we explore directly the
+ * backends.
*/
error = git_odb_read_prefix(&odb_obj, odb, &short_oid, len);
}
- if (error < 0)
- return error;
-
- error = git_object__from_odb_object(object_out, repo, odb_obj, type);
+ if (!error) {
+ error = git_object__from_odb_object(out, repo, odb_obj, type, lax);
- git_odb_object_free(odb_obj);
+ git_odb_object_free(odb_obj);
+ }
return error;
}
-int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type) {
- return git_object_lookup_prefix(object_out, repo, id, GIT_OID_HEXSZ, type);
+int git_object_lookup(
+ git_object **out,
+ git_repository *repo,
+ const git_oid *id,
+ git_otype type)
+{
+ return object_lookup(out, repo, id, GIT_OID_HEXSZ, type, false);
+}
+
+int git_object_lookup_prefix(
+ git_object **out,
+ git_repository *repo,
+ const git_oid *id,
+ size_t len,
+ git_otype type)
+{
+ return object_lookup(out, repo, id, len, type, false);
+}
+
+int git_object_lookup_lax(
+ git_object **out,
+ git_repository *repo,
+ const git_oid *id,
+ size_t len,
+ git_otype type)
+{
+ return object_lookup(out, repo, id, len, type, true);
}
void git_object_free(git_object *object)
{
if (object == NULL)
return;
-
git_cached_obj_decref(object);
}
@@ -235,16 +267,21 @@ const char *git_object_type2string(git_otype type)
return git_objects_table[type].str;
}
-git_otype git_object_string2type(const char *str)
+git_otype git_object_string2type(const char *str, size_t len)
{
size_t i;
if (!str || !*str)
return GIT_OBJ_BAD;
+ if (!len)
+ len = strlen(str);
+
+ for (i = 0; i < ARRAY_SIZE(git_objects_table); i++) {
+ size_t typelen = strlen(git_objects_table[i].str);
- for (i = 0; i < ARRAY_SIZE(git_objects_table); i++)
- if (!strcmp(str, git_objects_table[i].str))
+ if (len >= typelen && !memcmp(str, git_objects_table[i].str, len))
return (git_otype)i;
+ }
return GIT_OBJ_BAD;
}
@@ -364,28 +401,25 @@ int git_object_dup(git_object **dest, git_object *source)
}
int git_object_lookup_bypath(
- git_object **out,
- const git_object *treeish,
- const char *path,
- git_otype type)
+ git_object **out,
+ const git_object *treeish,
+ const char *path,
+ git_otype type)
{
- int error = -1;
- git_tree *tree = NULL;
+ int error = 0;
+ git_object *tree = NULL;
git_tree_entry *entry = NULL;
assert(out && treeish && path);
- if ((error = git_object_peel((git_object**)&tree, treeish, GIT_OBJ_TREE)) < 0 ||
- (error = git_tree_entry_bypath(&entry, tree, path)) < 0)
- {
+ if ((error = git_object_peel(&tree, treeish, GIT_OBJ_TREE)) < 0 ||
+ (error = git_tree_entry_bypath(&entry, (git_tree *)tree, path)) < 0)
goto cleanup;
- }
- if (type != GIT_OBJ_ANY && git_tree_entry_type(entry) != type)
- {
- giterr_set(GITERR_OBJECT,
- "object at path '%s' is not of the asked-for type %d",
- path, type);
+ if (type != GIT_OBJ_ANY && git_tree_entry_type(entry) != type) {
+ giterr_set(
+ GITERR_OBJECT, "object at path '%s' is not a %s (%d)",
+ path, git_object_type2string(type), type);
error = GIT_EINVALIDSPEC;
goto cleanup;
}
@@ -394,7 +428,8 @@ int git_object_lookup_bypath(
cleanup:
git_tree_entry_free(entry);
- git_tree_free(tree);
+ git_object_free(tree);
+
return error;
}
@@ -440,3 +475,170 @@ int git_object_short_id(git_buf *out, const git_object *obj)
return error;
}
+static int object_parse_error(
+ git_otype otype, git_object_parse_t *item, const char *msg)
+{
+ const char *typestr = git_object_type2string(otype);
+
+ if (item->tag)
+ giterr_set(GITERR_OBJECT, "Failed to parse %s - %s '%s'",
+ typestr, msg, item->tag);
+ else
+ giterr_set(GITERR_OBJECT, "Failed to parse %s - %s", typestr, msg);
+
+ return -1;
+}
+
+static int object_parse_line(
+ git_otype otype,
+ git_object_parse_t *item,
+ const char *buf,
+ const char *eol,
+ int error)
+{
+ size_t len;
+ const char *msg = NULL;
+
+ buf += item->taglen + 1;
+
+ if (eol <= buf) {
+ msg = "insufficient data for";
+ goto done;
+ } else
+ len = (size_t)(eol - buf);
+
+ switch (item->type) {
+ case GIT_PARSE_OID:
+ case GIT_PARSE_OID_ARRAY: {
+ git_oid *id = (item->type == GIT_PARSE_OID) ?
+ item->value.id : git_array_alloc(*item->value.ids);
+
+ if (!id)
+ msg = "out of memory";
+ else if (len < GIT_OID_HEXSZ)
+ msg = "insufficient data for";
+ else if (git_oid_fromstr(id, buf) < 0)
+ msg = "invalid OID in";
+ else if (len > GIT_OID_HEXSZ + 1)
+ msg = "extra data after";
+ else if (buf[GIT_OID_HEXSZ] != '\n')
+ msg = "improper termination for";
+ break;
+ }
+ case GIT_PARSE_OTYPE:
+ if ((*item->value.otype = git_object_string2type(buf, len)) ==
+ GIT_OBJ_BAD)
+ msg = "invalid value for";
+ break;
+ case GIT_PARSE_SIGNATURE:
+ *item->value.sig = git__calloc(1, sizeof(git_signature));
+ if (!*item->value.sig)
+ msg = "out of memory";
+ else if (git_signature__parse(
+ *item->value.sig, &buf, eol + 1, NULL, '\n') < 0)
+ msg = "invalid signature for";
+ break;
+ case GIT_PARSE_TO_EOL:
+ if (eol[-1] == '\r')
+ --len;
+ if ((*item->value.text = git__strndup(buf, len)) == NULL)
+ msg = "out of memory";
+ break;
+ default:
+ msg = "unexpected parse type";
+ break;
+ }
+
+done:
+ if (msg && !error)
+ error = object_parse_error(otype, item, msg);
+ return error;
+}
+
+int git_object__parse_lines(
+ git_otype otype,
+ git_object_parse_t *parse,
+ const char *buf,
+ const char *buf_end)
+{
+ int error = 0;
+ bool optional = false;
+ char *eol;
+ git_object_parse_t *scan = parse, *next = parse + 1;
+ size_t len;
+
+ /* process required and optional lines */
+ for (; buf < buf_end && scan->type > GIT_PARSE_BODY; scan = (next++)) {
+ len = buf_end - buf;
+
+ if (scan->type == GIT_PARSE_MODE_OPTIONAL) {
+ optional = true;
+ continue;
+ }
+
+ if (git__iseol(buf, buf_end - buf))
+ goto body;
+
+ if ((eol = memchr(buf, '\n', buf_end - buf)) == NULL) {
+ if (!error)
+ error = object_parse_error(otype, scan, "unterminated line");
+ break;
+ }
+ len = (size_t)(eol - buf);
+
+ if (len > scan->taglen &&
+ !memcmp(scan->tag, buf, scan->taglen) &&
+ buf[scan->taglen] == ' ')
+ {
+ error = object_parse_line(otype, scan, buf, eol, error);
+
+ if (scan->type == GIT_PARSE_OID_ARRAY) /* don't advance yet */
+ next = scan;
+ }
+ else if (optional)
+ /* for now, skip this tag - eventually search tags? */
+ next = scan;
+ else if (scan->type == GIT_PARSE_OID_ARRAY)
+ continue;
+ else if (!error)
+ error = object_parse_error(
+ otype, scan, "missing required field");
+
+ buf = eol + 1; /* advance to next line */
+ }
+
+body:
+
+ if (scan->type > GIT_PARSE_BODY) {
+ if (!optional && !error)
+ error = object_parse_error
+ (otype, scan, "missing required field");
+
+ while (scan->type > GIT_PARSE_BODY)
+ scan++;
+ }
+
+ if (scan->type > GIT_PARSE_BODY)
+ return error;
+
+ while (buf < buf_end && !git__iseol(buf, buf_end - buf)) {
+ if ((eol = memchr(buf, '\n', buf_end - buf)) == NULL)
+ buf = buf_end;
+ else
+ buf = eol + 1;
+ }
+
+ if (buf < buf_end)
+ buf += (*buf == '\n') ? 1 : 2;
+ else {
+ buf = buf_end;
+
+ if (!error && scan->type != GIT_PARSE_BODY_OPTIONAL)
+ error = object_parse_error(otype, scan, "missing message body");
+ }
+
+ if (scan->value.body)
+ *scan->value.body = buf;
+
+ return error;
+}
diff --git a/src/object.h b/src/object.h
index d187c55b7..47f82f36d 100644
--- a/src/object.h
+++ b/src/object.h
@@ -7,6 +7,9 @@
#ifndef INCLUDE_object_h__
#define INCLUDE_object_h__
+#include "common.h"
+#include "array.h"
+
/** Base git object for inheritance */
struct git_object {
git_cached_obj cached;
@@ -17,15 +20,49 @@ struct git_object {
void git_object__free(void *object);
int git_object__from_odb_object(
- git_object **object_out,
+ git_object **out,
git_repository *repo,
git_odb_object *odb_obj,
- git_otype type);
+ git_otype type,
+ bool lax);
int git_object__resolve_to_type(git_object **obj, git_otype type);
-int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header);
-
void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid);
+enum {
+ GIT_PARSE_BODY_OPTIONAL = -2,
+ GIT_PARSE_BODY = -1,
+ GIT_PARSE_MODE_OPTIONAL = 0,
+ GIT_PARSE_OID = 1,
+ GIT_PARSE_OID_ARRAY = 2,
+ GIT_PARSE_OTYPE = 3,
+ GIT_PARSE_SIGNATURE = 4,
+ GIT_PARSE_TO_EOL = 5,
+};
+
+typedef git_array_t(git_oid) git_oid_array;
+
+typedef struct {
+ const char *tag;
+ size_t taglen;
+ int type;
+ union {
+ git_oid *id;
+ git_otype *otype;
+ char **text;
+ git_signature **sig;
+ git_oid_array *ids;
+ const char **body;
+ } value;
+} git_object_parse_t;
+
+/* parse tagged lines followed by blank line and message body */
+int git_object__parse_lines(
+ git_otype type,
+ git_object_parse_t *parse,
+ const char *buf,
+ const char *buf_end);
+
#endif
+
diff --git a/src/odb.c b/src/odb.c
index 20a3f6c6e..6e8ce3d1d 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -778,7 +778,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
}
if (error && error != GIT_PASSTHROUGH) {
- if (!reads)
+ if (!reads || error == GIT_ENOTFOUND)
return git_odb__error_notfound("no match for id", id);
return error;
}
diff --git a/src/odb_loose.c b/src/odb_loose.c
index b2e8bed4d..4e23a9629 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -129,7 +129,7 @@ static size_t get_object_header(obj_hdr *hdr, unsigned char *data)
typename[used] = 0;
if (used == 0)
return 0;
- hdr->type = git_object_string2type(typename);
+ hdr->type = git_object_string2type(typename, used);
used++; /* consume the space */
/*
diff --git a/src/oid.c b/src/oid.c
index b640cadd1..be4d857cf 100644
--- a/src/oid.c
+++ b/src/oid.c
@@ -122,32 +122,6 @@ char *git_oid_tostr(char *out, size_t n, const git_oid *oid)
return out;
}
-int git_oid__parse(
- git_oid *oid, const char **buffer_out,
- const char *buffer_end, const char *header)
-{
- const size_t sha_len = GIT_OID_HEXSZ;
- const size_t header_len = strlen(header);
-
- const char *buffer = *buffer_out;
-
- if (buffer + (header_len + sha_len + 1) > buffer_end)
- return -1;
-
- if (memcmp(buffer, header, header_len) != 0)
- return -1;
-
- if (buffer[header_len + sha_len] != '\n')
- return -1;
-
- if (git_oid_fromstr(oid, buffer + header_len) < 0)
- return -1;
-
- *buffer_out = buffer + (header_len + sha_len + 1);
-
- return 0;
-}
-
void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid)
{
char hex_oid[GIT_OID_HEXSZ];
diff --git a/src/signature.c b/src/signature.c
index 2545b7519..f6d50c8ba 100644
--- a/src/signature.c
+++ b/src/signature.c
@@ -11,7 +11,7 @@
#include "git2/common.h"
#include "posix.h"
-void git_signature_free(git_signature *sig)
+void git_signature__clear(git_signature *sig)
{
if (sig == NULL)
return;
@@ -20,6 +20,11 @@ void git_signature_free(git_signature *sig)
sig->name = NULL;
git__free(sig->email);
sig->email = NULL;
+}
+
+void git_signature_free(git_signature *sig)
+{
+ git_signature__clear(sig);
git__free(sig);
}
@@ -176,22 +181,39 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
}
email_start = git__memrchr(buffer, '<', buffer_end - buffer);
- email_end = git__memrchr(buffer, '>', buffer_end - buffer);
+ if (!email_start) {
+ /* just stop now with everything as name */
+ sig->name = extract_trimmed(buffer, buffer_end - buffer);
+ sig->email = git__strdup("");
+ *buffer_out = buffer_end + 1;
+ return signature_error("missing e-mail");
+ }
- if (!email_start || !email_end || email_end <= email_start)
+ sig->name = extract_trimmed(buffer, email_start - buffer);
+ email_start += 1;
+
+ email_end = git__memrchr(email_start, '>', buffer_end - email_start);
+ if (!email_end) {
+ sig->email = extract_trimmed(email_start, buffer_end - email_start);
return signature_error("malformed e-mail");
+ }
- email_start += 1;
- sig->name = extract_trimmed(buffer, email_start - buffer - 1);
sig->email = extract_trimmed(email_start, email_end - email_start);
/* Do we even have a time at the end of the signature? */
- if (email_end + 2 < buffer_end) {
+ if (email_end != NULL && email_end + 2 < buffer_end) {
const char *time_start = email_end + 2;
const char *time_end;
- if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0)
- return signature_error("invalid Unix timestamp");
+ if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0) {
+ /* set timestamp to max value */
+ sig->when.time = (uint64_t)-1L;
+
+ /* skip over invalid timestamp data */
+ time_end = time_start;
+ while (git__isspace(*time_end)) ++time_end;
+ while (*time_end && !git__isspace(*time_end)) ++time_end;
+ }
/* do we have a timezone? */
if (time_end + 1 < buffer_end) {
@@ -202,7 +224,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
if ((tz_start[0] != '-' && tz_start[0] != '+') ||
git__strtol32(&offset, tz_start + 1, &tz_end, 10) < 0) {
- //malformed timezone, just assume it's zero
+ /* malformed timezone, just assume it's zero */
offset = 0;
}
diff --git a/src/signature.h b/src/signature.h
index 24655cbf5..b2cfe2c6e 100644
--- a/src/signature.h
+++ b/src/signature.h
@@ -12,6 +12,7 @@
#include "repository.h"
#include <time.h>
+void git_signature__clear(git_signature *sig);
int git_signature__parse(git_signature *sig, const char **buffer_out, const char *buffer_end, const char *header, char ender);
void git_signature__writebuf(git_buf *buf, const char *header, const git_signature *sig);
diff --git a/src/tag.c b/src/tag.c
index d7b531d34..438a03b6f 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -59,104 +59,33 @@ const char *git_tag_message(const git_tag *t)
return t->message;
}
-static int tag_error(const char *str)
+static int tag_parse(git_tag *tag, const char *buf, const char *buf_end)
{
- giterr_set(GITERR_TAG, "Failed to parse tag. %s", str);
- return -1;
-}
-
-static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
-{
- static const char *tag_types[] = {
- NULL, "commit\n", "tree\n", "blob\n", "tag\n"
+ int error = 0;
+ const char *body = NULL;
+ git_object_parse_t parser[] = {
+ { "object", 6, GIT_PARSE_OID, { .id = &tag->target } },
+ { "type", 4, GIT_PARSE_OTYPE, { .otype = &tag->type } },
+ { NULL, 0, GIT_PARSE_MODE_OPTIONAL },
+ { "tag", 3, GIT_PARSE_TO_EOL, { .text = &tag->tag_name } },
+ { "tagger", 6, GIT_PARSE_SIGNATURE, { .sig = &tag->tagger } },
+ { NULL, 0, GIT_PARSE_BODY_OPTIONAL, { .body = &body } },
};
- unsigned int i;
- size_t text_len;
- char *search;
-
- if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0)
- return tag_error("Object field invalid");
-
- if (buffer + 5 >= buffer_end)
- return tag_error("Object too short");
-
- if (memcmp(buffer, "type ", 5) != 0)
- return tag_error("Type field not found");
- buffer += 5;
-
- tag->type = GIT_OBJ_BAD;
-
- for (i = 1; i < ARRAY_SIZE(tag_types); ++i) {
- size_t type_length = strlen(tag_types[i]);
-
- if (buffer + type_length >= buffer_end)
- return tag_error("Object too short");
-
- if (memcmp(buffer, tag_types[i], type_length) == 0) {
- tag->type = i;
- buffer += type_length;
- break;
- }
- }
-
- if (tag->type == GIT_OBJ_BAD)
- return tag_error("Invalid object type");
-
- if (buffer + 4 >= buffer_end)
- return tag_error("Object too short");
-
- if (memcmp(buffer, "tag ", 4) != 0)
- return tag_error("Tag field not found");
-
- buffer += 4;
-
- search = memchr(buffer, '\n', buffer_end - buffer);
- if (search == NULL)
- return tag_error("Object too short");
-
- text_len = search - buffer;
-
- tag->tag_name = git__malloc(text_len + 1);
- GITERR_CHECK_ALLOC(tag->tag_name);
-
- memcpy(tag->tag_name, buffer, text_len);
- tag->tag_name[text_len] = '\0';
-
- buffer = search + 1;
+ error = git_object__parse_lines(GIT_OBJ_TAG, parser, buf, buf_end);
- tag->tagger = NULL;
- if (buffer < buffer_end && *buffer != '\n') {
- tag->tagger = git__malloc(sizeof(git_signature));
- GITERR_CHECK_ALLOC(tag->tagger);
-
- if (git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ", '\n') < 0)
- return -1;
- }
-
- tag->message = NULL;
- if (buffer < buffer_end) {
- if( *buffer != '\n' )
- return tag_error("No new line before message");
-
- text_len = buffer_end - ++buffer;
-
- tag->message = git__malloc(text_len + 1);
+ if (body != NULL && body < buf_end) {
+ tag->message = git__strndup(body, buf_end - body);
GITERR_CHECK_ALLOC(tag->message);
-
- memcpy(tag->message, buffer, text_len);
- tag->message[text_len] = '\0';
}
- return 0;
+ return error;
}
-int git_tag__parse(void *_tag, git_odb_object *odb_obj)
+int git_tag__parse(void *tag, git_odb_object *odb_obj)
{
- git_tag *tag = _tag;
const char *buffer = git_odb_object_data(odb_obj);
const char *buffer_end = buffer + git_odb_object_size(odb_obj);
-
return tag_parse(tag, buffer, buffer_end);
}
@@ -196,12 +125,12 @@ static int retrieve_tag_reference_oid(
}
static int write_tag_annotation(
- git_oid *oid,
- git_repository *repo,
- const char *tag_name,
- const git_object *target,
- const git_signature *tagger,
- const char *message)
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_object *target,
+ const git_signature *tagger,
+ const char *message)
{
git_buf tag = GIT_BUF_INIT;
git_odb *odb;
@@ -231,14 +160,14 @@ on_error:
}
static int git_tag_create__internal(
- git_oid *oid,
- git_repository *repo,
- const char *tag_name,
- const git_object *target,
- const git_signature *tagger,
- const char *message,
- int allow_ref_overwrite,
- int create_tag_annotation)
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_object *target,
+ const git_signature *tagger,
+ const char *message,
+ int allow_ref_overwrite,
+ int create_tag_annotation)
{
git_reference *new_ref = NULL;
git_buf ref_name = GIT_BUF_INIT;
@@ -320,77 +249,70 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
int error;
git_odb *odb;
git_odb_stream *stream;
- git_odb_object *target_obj;
-
- git_reference *new_ref = NULL;
+ git_odb_object *target_obj = NULL;
git_buf ref_name = GIT_BUF_INIT;
+ size_t buflen;
assert(oid && buffer);
memset(&tag, 0, sizeof(tag));
-
- if (git_repository_odb__weakptr(&odb, repo) < 0)
- return -1;
+ buflen = strlen(buffer);
/* validate the buffer */
- if (tag_parse(&tag, buffer, buffer + strlen(buffer)) < 0)
- return -1;
+ if ((error = tag_parse(&tag, buffer, buffer + buflen)) < 0)
+ goto cleanup;
/* validate the target */
- if (git_odb_read(&target_obj, odb, &tag.target) < 0)
- goto on_error;
+ if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
+ (error = git_odb_read(&target_obj, odb, &tag.target)) < 0)
+ goto cleanup;
if (tag.type != target_obj->cached.type) {
giterr_set(GITERR_TAG, "The type for the given target is invalid");
- goto on_error;
+ error = -1;
+ goto cleanup;
}
error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag.tag_name);
if (error < 0 && error != GIT_ENOTFOUND)
- goto on_error;
-
- /* We don't need these objects after this */
- git_signature_free(tag.tagger);
- git__free(tag.tag_name);
- git__free(tag.message);
- git_odb_object_free(target_obj);
+ goto cleanup;
/** Ensure the tag name doesn't conflict with an already existing
* reference unless overwriting has explictly been requested **/
- if (error == 0 && !allow_ref_overwrite) {
+ if (!error && !allow_ref_overwrite) {
giterr_set(GITERR_TAG, "Tag already exists");
- return GIT_EEXISTS;
+ error = GIT_EEXISTS;
+ goto cleanup;
}
/* write the buffer */
- if ((error = git_odb_open_wstream(
- &stream, odb, strlen(buffer), GIT_OBJ_TAG)) < 0)
- return error;
+ if (!(error = git_odb_open_wstream(&stream, odb, buflen, GIT_OBJ_TAG))) {
- if (!(error = git_odb_stream_write(stream, buffer, strlen(buffer))))
- error = git_odb_stream_finalize_write(oid, stream);
+ if (!(error = git_odb_stream_write(stream, buffer, buflen)))
+ error = git_odb_stream_finalize_write(oid, stream);
- git_odb_stream_free(stream);
-
- if (error < 0) {
- git_buf_free(&ref_name);
- return error;
+ git_odb_stream_free(stream);
}
- error = git_reference_create(
- &new_ref, repo, ref_name.ptr, oid, allow_ref_overwrite, NULL, NULL);
+ /* update the reference */
+ if (!error) {
+ git_reference *new_ref = NULL;
- git_reference_free(new_ref);
- git_buf_free(&ref_name);
+ error = git_reference_create(
+ &new_ref, repo, ref_name.ptr, oid,
+ allow_ref_overwrite, NULL, NULL);
- return error;
+ git_reference_free(new_ref);
+ }
-on_error:
+cleanup:
git_signature_free(tag.tagger);
git__free(tag.tag_name);
git__free(tag.message);
git_odb_object_free(target_obj);
- return -1;
+ git_buf_free(&ref_name);
+
+ return error;
}
int git_tag_delete(git_repository *repo, const char *tag_name)
@@ -403,11 +325,10 @@ int git_tag_delete(git_repository *repo, const char *tag_name)
git_buf_free(&ref_name);
- if (error < 0)
- return error;
+ if (!error)
+ error = git_reference_delete(tag_ref);
- if ((error = git_reference_delete(tag_ref)) == 0)
- git_reference_free(tag_ref);
+ git_reference_free(tag_ref);
return error;
}
diff --git a/src/util.h b/src/util.h
index 6fb2dc0f4..8d300987f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -322,6 +322,12 @@ GIT_INLINE(bool) git__iswildcard(int c)
return (c == '*' || c == '?' || c == '[');
}
+GIT_INLINE(bool) git__iseol(const char *ptr, size_t len)
+{
+ char c = *ptr;
+ return (c == '\n' || (c == '\r' && len > 1 && *(ptr + 1) == '\n'));
+}
+
/*
* Parse a string value as a boolean, just like Core Git does.
*
diff --git a/tests/commit/parse.c b/tests/commit/parse.c
index 41e162440..00e763d9c 100644
--- a/tests/commit/parse.c
+++ b/tests/commit/parse.c
@@ -22,50 +22,62 @@ typedef struct {
} parse_test_case;
static parse_test_case passing_header_cases[] = {
- { "parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "parent " },
- { "tree 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree " },
- { "random_heading 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "random_heading " },
- { "stuck_heading05452d6349abcd67aa396dfb28660d765d8b2a36\n", "stuck_heading" },
- { "tree 5F4BEFFC0759261D015AA63A3A85613FF2F235DE\n", "tree " },
- { "tree 1A669B8AB81B5EB7D9DB69562D34952A38A9B504\n", "tree " },
- { "tree 5B20DCC6110FCC75D31C6CEDEBD7F43ECA65B503\n", "tree " },
- { "tree 173E7BF00EA5C33447E99E6C1255954A13026BE4\n", "tree " },
+ { "parent 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "parent" },
+ { "tree 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree" },
+ { "random_heading 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "random_heading" },
+ { "tree 5F4BEFFC0759261D015AA63A3A85613FF2F235DE\n", "tree" },
+ { "tree 1A669B8AB81B5EB7D9DB69562D34952A38A9B504\n", "tree" },
+ { "tree 5B20DCC6110FCC75D31C6CEDEBD7F43ECA65B503\n", "tree" },
+ { "tree 173E7BF00EA5C33447E99E6C1255954A13026BE4\n", "tree" },
{ NULL, NULL }
};
static parse_test_case failing_header_cases[] = {
- { "parent 05452d6349abcd67aa396dfb28660d765d8b2a36", "parent " },
- { "05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree " },
- { "parent05452d6349abcd67aa396dfb28660d765d8b2a6a\n", "parent " },
- { "parent 05452d6349abcd67aa396dfb280d765d8b2a6\n", "parent " },
- { "tree 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree " },
- { "parent 0545xd6349abcd67aa396dfb28660d765d8b2a36\n", "parent " },
- { "parent 0545xd6349abcd67aa396dfb28660d765d8b2a36FF\n", "parent " },
- { "", "tree " },
+ { "parent 05452d6349abcd67aa396dfb28660d765d8b2a36", "parent" },
+ { "05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree" },
+ { "parent05452d6349abcd67aa396dfb28660d765d8b2a6a\n", "parent" },
+ { "parent 05452d6349abcd67aa396dfb280d765d8b2a6\n", "parent" },
+ { "tree 05452d6349abcd67aa396dfb28660d765d8b2a36\n", "tree" },
+ { "parent 0545xd6349abcd67aa396dfb28660d765d8b2a36\n", "parent" },
+ { "parent 0545xd6349abcd67aa396dfb28660d765d8b2a36FF\n", "parent" },
+ { "", "tree" },
{ "", "" },
+ { "stuck_heading05452d6349abcd67aa396dfb28660d765d8b2a36\n", "stuck_heading" },
{ NULL, NULL }
};
void test_commit_parse__header(void)
{
- git_oid oid;
+ git_oid oid, exp;
+ git_object_parse_t template[2] = {
+ { NULL, 0, GIT_PARSE_OID, { .id = &oid } },
+ { NULL, 0, GIT_PARSE_BODY_OPTIONAL },
+ };
+ parse_test_case *test;
- parse_test_case *testcase;
- for (testcase = passing_header_cases; testcase->line != NULL; testcase++)
- {
- const char *line = testcase->line;
+ for (test = passing_header_cases; test->line != NULL; test++) {
+ const char *line = test->line;
const char *line_end = line + strlen(line);
- cl_git_pass(git_oid__parse(&oid, &line, line_end, testcase->header));
- cl_assert(line == line_end);
+ template[0].tag = test->header;
+ template[0].taglen = strlen(test->header);
+
+ cl_git_pass(git_object__parse_lines(
+ GIT_OBJ_COMMIT, template, line, line_end));
+
+ cl_git_pass(git_oid_fromstr(&exp, line + strlen(test->header) + 1));
+ cl_assert(git_oid_equal(&exp, &oid));
}
- for (testcase = failing_header_cases; testcase->line != NULL; testcase++)
- {
- const char *line = testcase->line;
+ for (test = failing_header_cases; test->line != NULL; test++) {
+ const char *line = test->line;
const char *line_end = line + strlen(line);
- cl_git_fail(git_oid__parse(&oid, &line, line_end, testcase->header));
+ template[0].tag = test->header;
+ template[0].taglen = strlen(test->header);
+
+ cl_git_fail(git_object__parse_lines(
+ GIT_OBJ_COMMIT, template, line, line_end));
}
}
@@ -152,12 +164,13 @@ void test_commit_parse__signature(void)
size_t len = strlen(passcase->string);
struct git_signature person = {0};
- cl_git_pass(git_signature__parse(&person, &str, str + len, passcase->header, '\n'));
+ cl_git_pass(git_signature__parse(
+ &person, &str, str + len, passcase->header, '\n'));
cl_assert_equal_s(passcase->name, person.name);
cl_assert_equal_s(passcase->email, person.email);
cl_assert_equal_i((int)passcase->time, (int)person.when.time);
cl_assert_equal_i(passcase->offset, person.when.offset);
- git__free(person.name); git__free(person.email);
+ git_signature__clear(&person);
}
for (failcase = failing_signature_cases; failcase->string != NULL; failcase++)
@@ -165,8 +178,9 @@ void test_commit_parse__signature(void)
const char *str = failcase->string;
size_t len = strlen(failcase->string);
git_signature person = {0};
- cl_git_fail(git_signature__parse(&person, &str, str + len, failcase->header, '\n'));
- git__free(person.name); git__free(person.email);
+ cl_git_fail(git_signature__parse(
+ &person, &str, str + len, failcase->header, '\n'));
+ git_signature__clear(&person);
}
}
diff --git a/tests/object/raw/type2string.c b/tests/object/raw/type2string.c
index a3585487f..45045a062 100644
--- a/tests/object/raw/type2string.c
+++ b/tests/object/raw/type2string.c
@@ -23,17 +23,17 @@ void test_object_raw_type2string__convert_type_to_string(void)
void test_object_raw_type2string__convert_string_to_type(void)
{
- cl_assert(git_object_string2type(NULL) == GIT_OBJ_BAD);
- cl_assert(git_object_string2type("") == GIT_OBJ_BAD);
- cl_assert(git_object_string2type("commit") == GIT_OBJ_COMMIT);
- cl_assert(git_object_string2type("tree") == GIT_OBJ_TREE);
- cl_assert(git_object_string2type("blob") == GIT_OBJ_BLOB);
- cl_assert(git_object_string2type("tag") == GIT_OBJ_TAG);
- cl_assert(git_object_string2type("OFS_DELTA") == GIT_OBJ_OFS_DELTA);
- cl_assert(git_object_string2type("REF_DELTA") == GIT_OBJ_REF_DELTA);
-
- cl_assert(git_object_string2type("CoMmIt") == GIT_OBJ_BAD);
- cl_assert(git_object_string2type("hohoho") == GIT_OBJ_BAD);
+ cl_assert(git_object_string2type(NULL, 0) == GIT_OBJ_BAD);
+ cl_assert(git_object_string2type("", 0) == GIT_OBJ_BAD);
+ cl_assert(git_object_string2type("commit", 0) == GIT_OBJ_COMMIT);
+ cl_assert(git_object_string2type("tree", 0) == GIT_OBJ_TREE);
+ cl_assert(git_object_string2type("blob", 0) == GIT_OBJ_BLOB);
+ cl_assert(git_object_string2type("tag", 0) == GIT_OBJ_TAG);
+ cl_assert(git_object_string2type("OFS_DELTA", 0) == GIT_OBJ_OFS_DELTA);
+ cl_assert(git_object_string2type("REF_DELTA", 0) == GIT_OBJ_REF_DELTA);
+
+ cl_assert(git_object_string2type("CoMmIt", 0) == GIT_OBJ_BAD);
+ cl_assert(git_object_string2type("hohoho", 0) == GIT_OBJ_BAD);
}
void test_object_raw_type2string__check_type_is_loose(void)
diff --git a/tests/odb/loose.c b/tests/odb/loose.c
index c91927c4a..da5518990 100644
--- a/tests/odb/loose.c
+++ b/tests/odb/loose.c
@@ -24,7 +24,7 @@ static void write_object_files(object_data *d)
static void cmp_objects(git_rawobj *o, object_data *d)
{
- cl_assert(o->type == git_object_string2type(d->type));
+ cl_assert(o->type == git_object_string2type(d->type, 0));
cl_assert(o->len == d->dlen);
if (o->len > 0)