From 3aa351ea0fa0d9e8d155801cdac1e83d3b1717c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 26 Apr 2012 15:05:07 +0200 Subject: [PATCH] error handling: move the missing parts over to the new error handling --- include/git2/errors.h | 2 + src/commit.c | 6 +- src/delta-apply.c | 15 +- src/filter.c | 4 +- src/object.c | 30 ++-- src/refspec.c | 37 ++-- src/tag.c | 220 +++++++++++------------ src/tree.c | 280 ++++++++++++++---------------- tests-clar/object/tree/frompath.c | 18 +- 9 files changed, 300 insertions(+), 312 deletions(-) diff --git a/include/git2/errors.h b/include/git2/errors.h index 325d0a615..17a701079 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -133,6 +133,8 @@ typedef enum { GITERR_INDEX, GITERR_OBJECT, GITERR_NET, + GITERR_TAG, + GITERR_TREE, } git_error_class; /** diff --git a/src/commit.c b/src/commit.c index 25db5c07b..04f37fe16 100644 --- a/src/commit.c +++ b/src/commit.c @@ -310,8 +310,10 @@ int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n) assert(commit); parent_oid = git_vector_get(&commit->parent_oids, n); - if (parent_oid == NULL) - return git__throw(GIT_ENOTFOUND, "Parent %u does not exist", n); + if (parent_oid == NULL) { + giterr_set(GITERR_INVALID, "Parent %u does not exist", n); + return GIT_ENOTFOUND; + } return git_commit_lookup(parent, commit->object.repo, parent_oid); } diff --git a/src/delta-apply.c b/src/delta-apply.c index 24eba2bda..c8c662fa8 100644 --- a/src/delta-apply.c +++ b/src/delta-apply.c @@ -51,11 +51,15 @@ int git__delta_apply( * if not we would underflow while accessing data from the * base object, resulting in data corruption or segfault. */ - if ((hdr_sz(&base_sz, &delta, delta_end) < 0) || (base_sz != base_len)) - return git__throw(GIT_ERROR, "Failed to apply delta. Base size does not match given data"); + if ((hdr_sz(&base_sz, &delta, delta_end) < 0) || (base_sz != base_len)) { + giterr_set(GITERR_INVALID, "Failed to apply delta. Base size does not match given data"); + return -1; + } - if (hdr_sz(&res_sz, &delta, delta_end) < 0) - return git__throw(GIT_ERROR, "Failed to apply delta. Base size does not match given data"); + if (hdr_sz(&res_sz, &delta, delta_end) < 0) { + giterr_set(GITERR_INVALID, "Failed to apply delta. Base size does not match given data"); + return -1; + } if ((res_dp = git__malloc(res_sz + 1)) == NULL) return GIT_ENOMEM; @@ -111,5 +115,6 @@ int git__delta_apply( fail: git__free(out->data); out->data = NULL; - return git__throw(GIT_ERROR, "Failed to apply delta"); + giterr_set(GITERR_INVALID, "Failed to apply delta"); + return -1; } diff --git a/src/filter.c b/src/filter.c index d2d113409..88ad0295f 100644 --- a/src/filter.c +++ b/src/filter.c @@ -95,8 +95,8 @@ int git_filters_load(git_vector *filters, git_repository *repo, const char *path if (error < GIT_SUCCESS) return error; } else { - return git__throw(GIT_ENOTIMPLEMENTED, - "Worktree filters are not implemented yet"); + giterr_set(GITERR_INVALID, "Worktree filters are not implemented yet"); + return GIT_ENOTIMPLEMENTED; } return (int)filters->length; diff --git a/src/object.c b/src/object.c index bb27f71c1..979fb40ca 100644 --- a/src/object.c +++ b/src/object.c @@ -68,7 +68,8 @@ static int create_object(git_object **object_out, git_otype type) break; default: - return git__throw(GIT_EINVALIDTYPE, "The given type is invalid"); + giterr_set(GITERR_INVALID, "The given type is invalid"); + return -1; } object->type = type; @@ -92,8 +93,7 @@ int git_object_lookup_prefix( assert(repo && object_out && id); if (len < GIT_OID_MINPREFIXLEN) - return git__throw(GIT_EAMBIGUOUS, - "Failed to lookup object. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN); + return GIT_EAMBIGUOUS; error = git_repository_odb__weakptr(&odb, repo); if (error < GIT_SUCCESS) @@ -110,13 +110,12 @@ int git_object_lookup_prefix( if (object != NULL) { if (type != GIT_OBJ_ANY && type != object->type) { git_object_free(object); - return git__throw(GIT_EINVALIDTYPE, - "Failed to lookup object. " - "The given type does not match the type on the ODB"); + giterr_set(GITERR_INVALID, "The given type does not match the type in ODB"); + return -1; } *object_out = object; - return GIT_SUCCESS; + return 0; } /* Object was not found in the cache, let's explore the backends. @@ -147,18 +146,19 @@ int git_object_lookup_prefix( error = git_odb_read_prefix(&odb_obj, odb, &short_oid, len); } - if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to lookup object"); + if (error < 0) + return -1; if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) { git_odb_object_free(odb_obj); - return git__throw(GIT_EINVALIDTYPE, "Failed to lookup object. The given type does not match the type on the ODB"); + giterr_set(GITERR_INVALID, "The given type does not match the type on the ODB"); + return -1; } type = odb_obj->raw.type; - if ((error = create_object(&object, type)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to lookup object"); + if (create_object(&object, type) < 0) + return -1; /* Initialize parent object */ git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid); @@ -187,13 +187,13 @@ int git_object_lookup_prefix( git_odb_object_free(odb_obj); - if (error < GIT_SUCCESS) { + if (error < 0) { git_object__free(object); - return git__rethrow(error, "Failed to lookup object"); + return -1; } *object_out = git_cache_try_store(&repo->objects, object); - return GIT_SUCCESS; + return 0; } int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type) { diff --git a/src/refspec.c b/src/refspec.c index d51fd4ceb..ab0108b8c 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -25,24 +25,21 @@ int git_refspec_parse(git_refspec *refspec, const char *str) delim = strchr(str, ':'); if (delim == NULL) { refspec->src = git__strdup(str); - if (refspec->src == NULL) - return GIT_ENOMEM; - - return GIT_SUCCESS; + GITERR_CHECK_ALLOC(refspec->src); + return 0; } refspec->src = git__strndup(str, delim - str); - if (refspec->src == NULL) - return GIT_ENOMEM; + GITERR_CHECK_ALLOC(refspec->src); refspec->dst = git__strdup(delim + 1); if (refspec->dst == NULL) { git__free(refspec->src); refspec->src = NULL; - return GIT_ENOMEM; + return -1; } - return GIT_SUCCESS; + return 0; } const char *git_refspec_src(const git_refspec *refspec) @@ -65,8 +62,10 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con size_t baselen, namelen; baselen = strlen(spec->dst); - if (outlen <= baselen) - return git__throw(GIT_EINVALIDREFNAME, "Reference name too long"); + if (outlen <= baselen) { + giterr_set(GITERR_INVALID, "Reference name too long"); + return GIT_ESHORTBUFFER; + } /* * No '*' at the end means that it's mapped to one specific local @@ -74,7 +73,7 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con */ if (spec->dst[baselen - 1] != '*') { memcpy(out, spec->dst, baselen + 1); /* include '\0' */ - return GIT_SUCCESS; + return 0; } /* There's a '*' at the end, so remove its length */ @@ -85,32 +84,34 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con namelen = strlen(name); - if (outlen <= baselen + namelen) - return git__throw(GIT_EINVALIDREFNAME, "Reference name too long"); + if (outlen <= baselen + namelen) { + giterr_set(GITERR_INVALID, "Reference name too long"); + return GIT_ESHORTBUFFER; + } memcpy(out, spec->dst, baselen); memcpy(out + baselen, name, namelen + 1); - return GIT_SUCCESS; + return 0; } int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name) { - if (git_buf_sets(out, spec->dst) < GIT_SUCCESS) - return GIT_ENOMEM; + if (git_buf_sets(out, spec->dst) < 0) + return -1; /* * No '*' at the end means that it's mapped to one specific local * branch, so no actual transformation is needed. */ if (out->size > 0 && out->ptr[out->size - 1] != '*') - return GIT_SUCCESS; + return 0; git_buf_truncate(out, out->size - 1); /* remove trailing '*' */ git_buf_puts(out, name + strlen(spec->src) - 1); if (git_buf_oom(out)) - return GIT_ENOMEM; + return -1; return 0; } diff --git a/src/tag.c b/src/tag.c index 552487986..ff22bf79f 100644 --- a/src/tag.c +++ b/src/tag.c @@ -61,6 +61,12 @@ const char *git_tag_message(git_tag *t) return t->message; } +static int tag_error(const char *str) +{ + giterr_set(GITERR_TAG, "Failed to parse tag. %s", str); + return -1; +} + int git_tag__parse_buffer(git_tag *tag, const char *buffer, size_t length) { static const char *tag_types[] = { @@ -70,18 +76,17 @@ int git_tag__parse_buffer(git_tag *tag, const char *buffer, size_t length) unsigned int i; size_t text_len; char *search; - int error; const char *buffer_end = buffer + length; - if ((error = git_oid__parse(&tag->target, &buffer, buffer_end, "object ")) < 0) - return git__rethrow(error, "Failed to parse tag. Object field invalid"); + if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0) + return tag_error("Object field invalid"); if (buffer + 5 >= buffer_end) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short"); + return tag_error("Object too short"); if (memcmp(buffer, "type ", 5) != 0) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Type field not found"); + return tag_error("Type field not found"); buffer += 5; tag->type = GIT_OBJ_BAD; @@ -90,7 +95,7 @@ int git_tag__parse_buffer(git_tag *tag, const char *buffer, size_t length) size_t type_length = strlen(tag_types[i]); if (buffer + type_length >= buffer_end) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short"); + return tag_error("Object too short"); if (memcmp(buffer, tag_types[i], type_length) == 0) { tag->type = i; @@ -100,25 +105,24 @@ int git_tag__parse_buffer(git_tag *tag, const char *buffer, size_t length) } if (tag->type == GIT_OBJ_BAD) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Invalid object type"); + return tag_error("Invalid object type"); if (buffer + 4 >= buffer_end) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short"); + return tag_error("Object too short"); if (memcmp(buffer, "tag ", 4) != 0) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Tag field not found"); + return tag_error("Tag field not found"); buffer += 4; search = memchr(buffer, '\n', buffer_end - buffer); if (search == NULL) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short"); + return tag_error("Object too short"); text_len = search - buffer; tag->tag_name = git__malloc(text_len + 1); - if (tag->tag_name == NULL) - return GIT_ENOMEM; + GITERR_CHECK_ALLOC(tag->tag_name); memcpy(tag->tag_name, buffer, text_len); tag->tag_name[text_len] = '\0'; @@ -128,27 +132,24 @@ int git_tag__parse_buffer(git_tag *tag, const char *buffer, size_t length) tag->tagger = NULL; if (*buffer != '\n') { tag->tagger = git__malloc(sizeof(git_signature)); - if (tag->tagger == NULL) - return GIT_ENOMEM; + GITERR_CHECK_ALLOC(tag->tagger); - if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ", '\n') != 0)) { - return git__rethrow(error, "Failed to parse tag"); - } + if (git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ", '\n') < 0) + return -1; } if( *buffer != '\n' ) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. No new line before message"); + return tag_error("No new line before message"); text_len = buffer_end - ++buffer; tag->message = git__malloc(text_len + 1); - if (tag->message == NULL) - return GIT_ENOMEM; + GITERR_CHECK_ALLOC(tag->message); memcpy(tag->message, buffer, text_len); tag->message[text_len] = '\0'; - return GIT_SUCCESS; + return 0; } static int retrieve_tag_reference( @@ -162,17 +163,28 @@ static int retrieve_tag_reference( *tag_reference_out = NULL; - error = git_buf_joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name); - if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to retrieve tag reference"); + if (git_buf_joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name) < 0) + return -1; error = git_reference_lookup(&tag_ref, repo, ref_name_out->ptr); if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to retrieve tag reference"); + return error; /* Be it not foundo or corrupted */ *tag_reference_out = tag_ref; - return GIT_SUCCESS; + return 0; +} + +static int retrieve_tag_reference_oid( + git_oid *oid, + git_buf *ref_name_out, + git_repository *repo, + const char *tag_name) +{ + if (git_buf_joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name) < 0) + return -1; + + return git_reference_name_to_oid(oid, repo, ref_name_out->ptr); } static int write_tag_annotation( @@ -183,7 +195,6 @@ static int write_tag_annotation( const git_signature *tagger, const char *message) { - int error = GIT_SUCCESS; git_buf tag = GIT_BUF_INIT; git_odb *odb; @@ -194,24 +205,20 @@ static int write_tag_annotation( git_buf_putc(&tag, '\n'); git_buf_puts(&tag, message); - if (git_buf_oom(&tag)) { - git_buf_free(&tag); - return git__throw(GIT_ENOMEM, "Not enough memory to build the tag data"); - } + if (git_buf_oom(&tag)) + goto on_error; - error = git_repository_odb__weakptr(&odb, repo); - if (error < GIT_SUCCESS) { - git_buf_free(&tag); - return error; - } + if (git_repository_odb__weakptr(&odb, repo) < 0) + goto on_error; + + if (git_odb_write(oid, odb, tag.ptr, tag.size, GIT_OBJ_TAG) < 0) + goto on_error; - error = git_odb_write(oid, odb, tag.ptr, tag.size, GIT_OBJ_TAG); git_buf_free(&tag); - - if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to create tag annotation"); - - return error; + return 0; +on_error: + git_buf_free(&tag); + return -1; } static int git_tag_create__internal( @@ -227,51 +234,38 @@ static int git_tag_create__internal( git_reference *new_ref = NULL; git_buf ref_name = GIT_BUF_INIT; - int error, should_update_ref = 0; - const char *errmsg = "Failed to create tag"; + int error; assert(repo && tag_name && target); assert(!create_tag_annotation || (tagger && message)); - if (git_object_owner(target) != repo) - return git__throw(GIT_EINVALIDARGS, - "The given target does not belong to this repository"); + if (git_object_owner(target) != repo) { + giterr_set(GITERR_INVALID, "The given target does not belong to this repository"); + return -1; + } - error = retrieve_tag_reference(&new_ref, &ref_name, repo, tag_name); + error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag_name); if (error < GIT_SUCCESS && error != GIT_ENOTFOUND) - goto cleanup; + return -1; /** Ensure the tag name doesn't conflict with an already existing * reference unless overwriting has explictly been requested **/ - if (new_ref != NULL) { - if (!allow_ref_overwrite) { - git_oid_cpy(oid, git_reference_oid(new_ref)); - error = GIT_EEXISTS; - errmsg = "Tag already exists"; - goto cleanup; - } else { - should_update_ref = 1; - } + if (error == 0 && !allow_ref_overwrite) { + git_buf_free(&ref_name); + giterr_set(GITERR_TAG, "Tag already exists"); + return GIT_EEXISTS; } if (create_tag_annotation) { - if ((error = write_tag_annotation(oid, repo, tag_name, target, tagger, message)) < GIT_SUCCESS) - goto cleanup; + if (write_tag_annotation(oid, repo, tag_name, target, tagger, message) < 0) + return -1; } else git_oid_cpy(oid, git_object_id(target)); - if (!should_update_ref) - error = git_reference_create_oid(&new_ref, repo, ref_name.ptr, oid, 0); - else - error = git_reference_set_oid(new_ref, oid); + error = git_reference_create_oid(&new_ref, repo, ref_name.ptr, oid, allow_ref_overwrite); -cleanup: git_reference_free(new_ref); git_buf_free(&ref_name); - - if (error < GIT_SUCCESS) - git__rethrow(error, "%s", errmsg); - return error; } @@ -300,8 +294,7 @@ int git_tag_create_lightweight( int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *buffer, int allow_ref_overwrite) { git_tag tag; - int error, should_update_ref = 0; - const char *errmsg = "Failed to create tag"; + int error; git_odb *odb; git_odb_stream *stream; git_odb_object *target_obj; @@ -313,71 +306,66 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu memset(&tag, 0, sizeof(tag)); - error = git_repository_odb__weakptr(&odb, repo); - if (error < GIT_SUCCESS) - return error; + if (git_repository_odb__weakptr(&odb, repo) < 0) + return -1; /* validate the buffer */ - if ((error = git_tag__parse_buffer(&tag, buffer, strlen(buffer))) < GIT_SUCCESS) - goto cleanup; + if (git_tag__parse_buffer(&tag, buffer, strlen(buffer)) < 0) + return -1; /* validate the target */ - if ((error = git_odb_read(&target_obj, odb, &tag.target)) < GIT_SUCCESS) - goto cleanup; + if (git_odb_read(&target_obj, odb, &tag.target) < 0) + goto on_error; if (tag.type != target_obj->raw.type) { - error = GIT_EINVALIDTYPE; - errmsg = "The type for the given target is invalid"; - goto cleanup; + giterr_set(GITERR_TAG, "The type for the given target is invalid"); + goto on_error; } - git_odb_object_free(target_obj); - - error = retrieve_tag_reference(&new_ref, &ref_name, repo, tag.tag_name); + error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag.tag_name); if (error < GIT_SUCCESS && error != GIT_ENOTFOUND) - goto cleanup; + 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); /** Ensure the tag name doesn't conflict with an already existing * reference unless overwriting has explictly been requested **/ - if (new_ref != NULL) { - if (!allow_ref_overwrite) { - git_oid_cpy(oid, git_reference_oid(new_ref)); - error = GIT_EEXISTS; - errmsg = "Tag already exists"; - goto cleanup; - } else { - should_update_ref = 1; - } + if (error == 0 && !allow_ref_overwrite) { + giterr_set(GITERR_TAG, "Tag already exists"); + return GIT_EEXISTS; } /* write the buffer */ - if ((error = git_odb_open_wstream(&stream, odb, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) - goto cleanup; + if (git_odb_open_wstream(&stream, odb, strlen(buffer), GIT_OBJ_TAG) < 0) + return -1; stream->write(stream, buffer, strlen(buffer)); error = stream->finalize_write(oid, stream); stream->free(stream); - if (error < GIT_SUCCESS) - goto cleanup; + if (error < 0) { + git_buf_free(&ref_name); + return -1; + } - if (!should_update_ref) - error = git_reference_create_oid(&new_ref, repo, ref_name.ptr, oid, 0); - else - error = git_reference_set_oid(new_ref, oid); + error = git_reference_create_oid(&new_ref, repo, ref_name.ptr, oid, allow_ref_overwrite); -cleanup: git_reference_free(new_ref); + git_buf_free(&ref_name); + + return error; + +on_error: git_signature_free(tag.tagger); git__free(tag.tag_name); git__free(tag.message); - git_buf_free(&ref_name); - - if (error < GIT_SUCCESS) - git__rethrow(error, "%s", errmsg); - - return error; + git_odb_object_free(target_obj); + return -1; } int git_tag_delete(git_repository *repo, const char *tag_name) @@ -390,8 +378,8 @@ int git_tag_delete(git_repository *repo, const char *tag_name) git_buf_free(&ref_name); - if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to delete tag"); + if (error < 0) + return -1; return git_reference_delete(tag_ref); } @@ -414,13 +402,13 @@ static int tag_list_cb(const char *tag_name, void *payload) tag_filter_data *filter; if (git__prefixcmp(tag_name, GIT_REFS_TAGS_DIR) != 0) - return GIT_SUCCESS; + return 0; filter = (tag_filter_data *)payload; if (!*filter->pattern || p_fnmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == GIT_SUCCESS) return git_vector_insert(filter->taglist, git__strdup(tag_name)); - return GIT_SUCCESS; + return 0; } int git_tag_list_match(git_strarray *tag_names, const char *pattern, git_repository *repo) @@ -438,14 +426,14 @@ int git_tag_list_match(git_strarray *tag_names, const char *pattern, git_reposit filter.pattern = pattern; error = git_reference_foreach(repo, GIT_REF_OID|GIT_REF_PACKED, &tag_list_cb, (void *)&filter); - if (error < GIT_SUCCESS) { + if (error < 0) { git_vector_free(&taglist); - return git__rethrow(error, "Failed to list tags"); + return -1; } tag_names->strings = (char **)taglist.contents; tag_names->count = taglist.length; - return GIT_SUCCESS; + return 0; } int git_tag_list(git_strarray *tag_names, git_repository *repo) diff --git a/src/tree.c b/src/tree.c index 56a722960..62b613d71 100644 --- a/src/tree.c +++ b/src/tree.c @@ -201,41 +201,38 @@ unsigned int git_tree_entrycount(git_tree *tree) return tree->entries.length; } +static int tree_error(const char *str) +{ + giterr_set(GITERR_TREE, "%s", str); + return -1; +} + static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buffer_end) { - int error = GIT_SUCCESS; - - if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS) - return GIT_ENOMEM; + if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) + return -1; while (buffer < buffer_end) { git_tree_entry *entry; int tmp; entry = git__calloc(1, sizeof(git_tree_entry)); - if (entry == NULL) { - error = GIT_ENOMEM; - break; - } + GITERR_CHECK_ALLOC(entry); - if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS) - return GIT_ENOMEM; + if (git_vector_insert(&tree->entries, entry) < 0) + return -1; - if (git__strtol32(&tmp, buffer, &buffer, 8) < GIT_SUCCESS || + if (git__strtol32(&tmp, buffer, &buffer, 8) < 0 || !buffer || !valid_attributes(tmp)) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Can't parse attributes"); + return tree_error("Failed to parse tree. Can't parse attributes"); entry->attr = tmp; - if (*buffer++ != ' ') { - error = git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Object it corrupted"); - break; - } + if (*buffer++ != ' ') + return tree_error("Failed to parse tree. Object is corrupted"); - if (memchr(buffer, 0, buffer_end - buffer) == NULL) { - error = git__throw(GIT_EOBJCORRUPTED, "Failed to parse tree. Object it corrupted"); - break; - } + if (memchr(buffer, 0, buffer_end - buffer) == NULL) + return tree_error("Failed to parse tree. Object is corrupted"); entry->filename = git__strdup(buffer); entry->filename_len = strlen(buffer); @@ -249,7 +246,7 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf buffer += GIT_OID_RAWSZ; } - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse buffer"); + return 0; } int git_tree__parse(git_tree *tree, git_odb_object *obj) @@ -280,10 +277,9 @@ static int append_entry(git_treebuilder *bld, const char *filename, const git_oi { git_tree_entry *entry; - if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL) - return GIT_ENOMEM; + entry = git__calloc(1, sizeof(git_tree_entry)); + GITERR_CHECK_ALLOC(entry); - memset(entry, 0x0, sizeof(git_tree_entry)); entry->filename = git__strdup(filename); entry->filename_len = strlen(entry->filename); @@ -291,9 +287,9 @@ static int append_entry(git_treebuilder *bld, const char *filename, const git_oi entry->attr = attributes; if (git_vector_insert(&bld->entries, entry) < 0) - return GIT_ENOMEM; + return -1; - return GIT_SUCCESS; + return 0; } static int write_tree( @@ -318,7 +314,7 @@ static int write_tree( error = git_treebuilder_create(&bld, NULL); if (bld == NULL) { - return GIT_ENOMEM; + return -1; } /* @@ -354,16 +350,13 @@ static int write_tree( char *subdir, *last_comp; subdir = git__strndup(entry->path, next_slash - entry->path); - if (subdir == NULL) { - error = GIT_ENOMEM; - goto cleanup; - } + GITERR_CHECK_ALLOC(subdir); /* Write out the subtree */ written = write_tree(&sub_oid, repo, index, subdir, i); if (written < 0) { - error = git__rethrow(written, "Failed to write subtree %s", subdir); - goto cleanup; + tree_error("Failed to write subtree"); + goto on_error; } else { i = written - 1; /* -1 because of the loop increment */ } @@ -382,51 +375,49 @@ static int write_tree( } error = append_entry(bld, last_comp, &sub_oid, S_IFDIR); git__free(subdir); - if (error < GIT_SUCCESS) { - error = git__rethrow(error, "Failed to insert dir"); - goto cleanup; + if (error < 0) { + tree_error("Failed to insert dir"); + goto on_error; } } else { error = append_entry(bld, filename, &entry->oid, entry->mode); - if (error < GIT_SUCCESS) { - error = git__rethrow(error, "Failed to insert file"); + if (error < 0) { + tree_error("Failed to insert file"); + goto on_error; } } } - error = git_treebuilder_write(oid, repo, bld); - if (error < GIT_SUCCESS) - error = git__rethrow(error, "Failed to write tree to db"); + if (git_treebuilder_write(oid, repo, bld) < 0) + goto on_error; - cleanup: git_treebuilder_free(bld); + return i; - if (error < GIT_SUCCESS) - return error; - else - return i; +on_error: + git_treebuilder_free(bld); + return -1; } int git_tree_create_fromindex(git_oid *oid, git_index *index) { + int ret; git_repository *repo; - int error; repo = (git_repository *)GIT_REFCOUNT_OWNER(index); if (repo == NULL) - return git__throw(GIT_EBAREINDEX, - "Failed to create tree. " - "The index file is not backed up by an existing repository"); + return tree_error("Failed to create tree. " + "The index file is not backed up by an existing repository"); if (index->tree != NULL && index->tree->entries >= 0) { git_oid_cpy(oid, &index->tree->oid); - return GIT_SUCCESS; + return 0; } /* The tree cache didn't help us */ - error = write_tree(oid, repo, index, "", 0); - return (error < GIT_SUCCESS) ? git__rethrow(error, "Failed to create tree") : GIT_SUCCESS; + ret = write_tree(oid, repo, index, "", 0); + return ret < 0 ? ret : 0; } static void sort_entries(git_treebuilder *bld) @@ -442,30 +433,29 @@ int git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source) assert(builder_p); bld = git__calloc(1, sizeof(git_treebuilder)); - if (bld == NULL) - return GIT_ENOMEM; + GITERR_CHECK_ALLOC(bld); if (source != NULL) source_entries = source->entries.length; - if (git_vector_init(&bld->entries, source_entries, entry_sort_cmp) < GIT_SUCCESS) { - git__free(bld); - return GIT_ENOMEM; - } + if (git_vector_init(&bld->entries, source_entries, entry_sort_cmp) < 0) + goto on_error; if (source != NULL) { for (i = 0; i < source->entries.length; ++i) { git_tree_entry *entry_src = source->entries.contents[i]; - if (append_entry(bld, entry_src->filename, &entry_src->oid, entry_src->attr) < 0) { - git_treebuilder_free(bld); - return GIT_ENOMEM; - } + if (append_entry(bld, entry_src->filename, &entry_src->oid, entry_src->attr) < 0) + goto on_error; } } *builder_p = bld; - return GIT_SUCCESS; + return 0; + +on_error: + git_treebuilder_free(bld); + return -1; } int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, const char *filename, const git_oid *id, unsigned int attributes) @@ -476,10 +466,10 @@ int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, con assert(bld && id && filename); if (!valid_attributes(attributes)) - return git__throw(GIT_ERROR, "Failed to insert entry. Invalid attributes"); + return tree_error("Failed to insert entry. Invalid attributes"); if (!valid_entry_name(filename)) - return git__throw(GIT_ERROR, "Failed to insert entry. Invalid name for a tree entry"); + return tree_error("Failed to insert entry. Invalid name for a tree entry"); pos = tree_key_search(&bld->entries, filename); @@ -488,10 +478,9 @@ int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, con if (entry->removed) entry->removed = 0; } else { - if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL) - return GIT_ENOMEM; + entry = git__calloc(1, sizeof(git_tree_entry)); + GITERR_CHECK_ALLOC(entry); - memset(entry, 0x0, sizeof(git_tree_entry)); entry->filename = git__strdup(filename); entry->filename_len = strlen(entry->filename); } @@ -501,13 +490,13 @@ int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, con if (pos == GIT_ENOTFOUND) { if (git_vector_insert(&bld->entries, entry) < 0) - return GIT_ENOMEM; + return -1; } if (entry_out != NULL) *entry_out = entry; - return GIT_SUCCESS; + return 0; } static git_tree_entry *treebuilder_get(git_treebuilder *bld, const char *filename) @@ -538,16 +527,15 @@ int git_treebuilder_remove(git_treebuilder *bld, const char *filename) git_tree_entry *remove_ptr = treebuilder_get(bld, filename); if (remove_ptr == NULL || remove_ptr->removed) - return git__throw(GIT_ENOTFOUND, "Failed to remove entry. File isn't in the tree"); + return tree_error("Failed to remove entry. File isn't in the tree"); remove_ptr->removed = 1; - return GIT_SUCCESS; + return 0; } int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld) { unsigned int i; - int error; git_buf tree = GIT_BUF_INIT; git_odb *odb; @@ -569,21 +557,22 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b git_buf_put(&tree, (char *)entry->oid.id, GIT_OID_RAWSZ); } - if (git_buf_oom(&tree)) { - git_buf_free(&tree); - return git__throw(GIT_ENOMEM, "Not enough memory to build the tree data"); - } + if (git_buf_oom(&tree)) + goto on_error; - error = git_repository_odb__weakptr(&odb, repo); - if (error < GIT_SUCCESS) { - git_buf_free(&tree); - return error; - } + if (git_repository_odb__weakptr(&odb, repo) < 0) + goto on_error; + + + if (git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE) < 0) + goto on_error; - error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE); git_buf_free(&tree); + return 0; - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write tree"); +on_error: + git_buf_free(&tree); + return -1; } void git_treebuilder_filter(git_treebuilder *bld, int (*filter)(const git_tree_entry *, void *), void *payload) @@ -631,9 +620,11 @@ static int tree_frompath( int error = GIT_SUCCESS; git_tree *subtree; - if (!*(treeentry_path->ptr + offset)) - return git__rethrow(GIT_EINVALIDPATH, + if (!*(treeentry_path->ptr + offset)) { + giterr_set(GITERR_INVALID, "Invalid relative path to a tree entry '%s'.", treeentry_path->ptr); + return -1; + } slash_pos = (char *)strchr(treeentry_path->ptr + offset, '/'); @@ -644,9 +635,11 @@ static int tree_frompath( git_object_id((const git_object *)root) ); - if (slash_pos == treeentry_path->ptr + offset) - return git__rethrow(GIT_EINVALIDPATH, + if (slash_pos == treeentry_path->ptr + offset) { + giterr_set(GITERR_INVALID, "Invalid relative path to a tree entry '%s'.", treeentry_path->ptr); + return -1; + } *slash_pos = '\0'; @@ -655,14 +648,15 @@ static int tree_frompath( if (slash_pos != NULL) *slash_pos = '/'; - if (entry == NULL) - return git__rethrow(GIT_ENOTFOUND, + if (entry == NULL) { + giterr_set(GITERR_TREE, "No tree entry can be found from " "the given tree and relative path '%s'.", treeentry_path->ptr); + return GIT_ENOTFOUND; + } - error = git_tree_lookup(&subtree, root->object.repo, &entry->oid); - if (error < GIT_SUCCESS) + if (git_tree_lookup(&subtree, root->object.repo, &entry->oid) < 0) return error; error = tree_frompath( @@ -686,7 +680,7 @@ int git_tree_get_subtree( assert(subtree && root && subtree_path); - if ((error = git_buf_sets(&buffer, subtree_path)) == GIT_SUCCESS) + if ((error = git_buf_sets(&buffer, subtree_path)) == 0) error = tree_frompath(subtree, root, &buffer, 0); git_buf_free(&buffer); @@ -722,18 +716,17 @@ static int tree_walk_post( git_buf_putc(path, '/'); if (git_buf_oom(path)) - return GIT_ENOMEM; + return -1; - error = tree_walk_post(subtree, callback, path, payload); - if (error < GIT_SUCCESS) - break; + if (tree_walk_post(subtree, callback, path, payload) < 0) + return -1; git_buf_truncate(path, path_len); git_tree_free(subtree); } } - return error; + return 0; } int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payload) @@ -747,14 +740,12 @@ int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payl break; case GIT_TREEWALK_PRE: - error = git__throw(GIT_ENOTIMPLEMENTED, - "Preorder tree walking is still not implemented"); - break; + tree_error("Preorder tree walking is still not implemented"); + return GIT_ENOTIMPLEMENTED; default: - error = git__throw(GIT_EINVALIDARGS, - "Invalid walking mode for tree walk"); - break; + giterr_set(GITERR_INVALID, "Invalid walking mode for tree walk"); + return -1; } git_buf_free(&root_path); @@ -793,7 +784,7 @@ static int signal_additions(git_tree *tree, int start, int end, git_tree_diff_cb { git_tree_diff_data diff; git_tree_entry *entry; - int i, error; + int i; if (end < 0) end = git_tree_entrycount(tree); @@ -803,12 +794,11 @@ static int signal_additions(git_tree *tree, int start, int end, git_tree_diff_cb entry = git_vector_get(&tree->entries, i); mark_add(&diff, entry); - error = cb(&diff, data); - if (error < GIT_SUCCESS) - return error; + if (cb(&diff, data) < 0) + return -1; } - return GIT_SUCCESS; + return 0; } static int signal_addition(git_tree_entry *entry, git_tree_diff_cb cb, void *data) @@ -826,7 +816,7 @@ static int signal_deletions(git_tree *tree, int start, int end, git_tree_diff_cb { git_tree_diff_data diff; git_tree_entry *entry; - int i, error; + int i; if (end < 0) end = git_tree_entrycount(tree); @@ -836,12 +826,11 @@ static int signal_deletions(git_tree *tree, int start, int end, git_tree_diff_cb entry = git_vector_get(&tree->entries, i); mark_del(&diff, entry); - error = cb(&diff, data); - if (error < GIT_SUCCESS) - return error; + if (cb(&diff, data) < 0) + return -1; } - return GIT_SUCCESS; + return 0; } static int signal_deletion(git_tree_entry *entry, git_tree_diff_cb cb, void *data) @@ -873,14 +862,14 @@ int git_tree_diff(git_tree *a, git_tree *b, git_tree_diff_cb cb, void *data) unsigned int i_a = 0, i_b = 0; /* Counters for trees a and b */ git_tree_entry *entry_a = NULL, *entry_b = NULL; git_tree_diff_data diff; - int error = GIT_SUCCESS, cmp; + int cmp; while (1) { entry_a = a == NULL ? NULL : git_vector_get(&a->entries, i_a); entry_b = b == NULL ? NULL : git_vector_get(&b->entries, i_b); if (!entry_a && !entry_b) - goto exit; + return 0; memset(&diff, 0x0, sizeof(git_tree_diff_data)); @@ -911,29 +900,28 @@ int git_tree_diff(git_tree *a, git_tree *b, git_tree_diff_cb cb, void *data) /* If they're not both dirs or both files, it's add + del */ if (S_ISDIR(entry_a->attr) != S_ISDIR(entry_b->attr)) { - if ((error = signal_addition(entry_a, cb, data)) < 0) - goto exit; - if ((error = signal_deletion(entry_b, cb, data)) < 0) - goto exit; + if (signal_addition(entry_a, cb, data) < 0) + return -1; + if (signal_deletion(entry_b, cb, data) < 0) + return -1; } /* Otherwise consider it a modification */ - if ((error = signal_modification(entry_a, entry_b, cb, data)) < 0) - goto exit; + if (signal_modification(entry_a, entry_b, cb, data) < 0) + return -1; } else if (cmp < 0) { i_a++; - if ((error = signal_deletion(entry_a, cb, data)) < 0) - goto exit; + if (signal_deletion(entry_a, cb, data) < 0) + return -1; } else if (cmp > 0) { i_b++; - if ((error = signal_addition(entry_b, cb, data)) < 0) - goto exit; + if (signal_addition(entry_b, cb, data) < 0) + return -1; } } -exit: - return error; + return 0; } struct diff_index_cbdata { @@ -978,53 +966,49 @@ static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data) git_index_entry *ientry = git_index_get(cbdata->index, cbdata->i); git_tree_entry fake_entry; git_buf fn_buf = GIT_BUF_INIT; - int cmp, error = GIT_SUCCESS; + int cmp; if (entry_is_tree(tentry)) - return GIT_SUCCESS; + return 0; + + if (!ientry) + return signal_deletion(tentry, cbdata->cb, cbdata->data); git_buf_puts(&fn_buf, root); git_buf_puts(&fn_buf, tentry->filename); - if (!ientry) { - error = signal_deletion(tentry, cbdata->cb, cbdata->data); - git_buf_free(&fn_buf); - goto exit; - } - /* Like with 'git diff-index', the index is the right side*/ cmp = strcmp(git_buf_cstr(&fn_buf), ientry->path); git_buf_free(&fn_buf); if (cmp == 0) { cbdata->i++; if (!cmp_tentry_ientry(tentry, ientry)) - goto exit; + return 0; /* modification */ make_tentry(&fake_entry, ientry); - if ((error = signal_modification(tentry, &fake_entry, cbdata->cb, cbdata->data)) < 0) - goto exit; + if (signal_modification(tentry, &fake_entry, cbdata->cb, cbdata->data) < 0) + return -1; } else if (cmp < 0) { /* deletion */ memcpy(&fake_entry, tentry, sizeof(git_tree_entry)); - if ((error = signal_deletion(tentry, cbdata->cb, cbdata->data)) < 0) - goto exit; + if (signal_deletion(tentry, cbdata->cb, cbdata->data) < 0) + return -1; } else { /* addition */ cbdata->i++; make_tentry(&fake_entry, ientry); - if ((error = signal_addition(&fake_entry, cbdata->cb, cbdata->data)) < 0) - goto exit; + if (signal_addition(&fake_entry, cbdata->cb, cbdata->data) < 0) + return -1; /* * The index has an addition. This means that we need to use * the next entry in the index without advancing the tree * walker, so call ourselves with the same tree state. */ - if ((error = diff_index_cb(root, tentry, data)) < 0) - goto exit; + if (diff_index_cb(root, tentry, data) < 0) + return -1;; } - exit: - return error; + return 0; } int git_tree_diff_index_recursive(git_tree *tree, git_index *index, git_tree_diff_cb cb, void *data) diff --git a/tests-clar/object/tree/frompath.c b/tests-clar/object/tree/frompath.c index 523a0b99e..15f0e917d 100644 --- a/tests-clar/object/tree/frompath.c +++ b/tests-clar/object/tree/frompath.c @@ -40,6 +40,12 @@ static void assert_tree_from_path(git_tree *root, const char *path, int expected git_tree_free(containing_tree); } +static void assert_tree_from_path_klass(git_tree *root, const char *path, int expected_result, const char *expected_raw_oid) +{ + assert_tree_from_path(root, path, GIT_ERROR, expected_raw_oid); + cl_assert(git_error_last()->klass == expected_result); +} + void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void) { /* Will return self if given a one path segment... */ @@ -66,10 +72,10 @@ void test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment(voi void test_object_tree_frompath__fail_when_processing_an_invalid_path(void) { - assert_tree_from_path(tree, "/", GIT_EINVALIDPATH, NULL); - assert_tree_from_path(tree, "/ab", GIT_EINVALIDPATH, NULL); - assert_tree_from_path(tree, "/ab/de", GIT_EINVALIDPATH, NULL); - assert_tree_from_path(tree, "ab/", GIT_EINVALIDPATH, NULL); - assert_tree_from_path(tree, "ab//de", GIT_EINVALIDPATH, NULL); - assert_tree_from_path(tree, "ab/de/", GIT_EINVALIDPATH, NULL); + assert_tree_from_path_klass(tree, "/", GITERR_INVALID, NULL); + assert_tree_from_path_klass(tree, "/ab", GITERR_INVALID, NULL); + assert_tree_from_path_klass(tree, "/ab/de", GITERR_INVALID, NULL); + assert_tree_from_path_klass(tree, "ab/", GITERR_INVALID, NULL); + assert_tree_from_path_klass(tree, "ab//de", GITERR_INVALID, NULL); + assert_tree_from_path_klass(tree, "ab/de/", GITERR_INVALID, NULL); }