diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2014-11-19 18:42:29 +0100 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2014-11-22 18:55:22 +0100 |
commit | 753e17b0f518c2510848a9dd73cc45e4c6df1a8a (patch) | |
tree | 39b27d69fa709024ba8b786c04bc66264d9cd97b /src | |
parent | 4d86caec599ab760b523a026040bc4f40f8338c9 (diff) | |
download | libgit2-cmn/peeling-errors.tar.gz |
peel: reject bad queries with EINVALIDSPECcmn/peeling-errors
There are some combination of objects and target types which we know
cannot be fulfilled. Return EINVALIDSPEC for those to signify that there
is a mismatch in the user-provided data and what the object model is
capable of satisfying.
If we start at a tag and in the course of peeling find out that we
cannot reach a particular type, we return EPEEL.
Diffstat (limited to 'src')
-rw-r--r-- | src/object.c | 39 | ||||
-rw-r--r-- | src/revwalk.c | 2 |
2 files changed, 34 insertions, 7 deletions
diff --git a/src/object.c b/src/object.c index 93068b85f..1073559fd 100644 --- a/src/object.c +++ b/src/object.c @@ -277,10 +277,8 @@ static int dereference_object(git_object **dereferenced, git_object *obj) return git_tag_target(dereferenced, (git_tag*)obj); case GIT_OBJ_BLOB: - return GIT_ENOTFOUND; - case GIT_OBJ_TREE: - return GIT_EAMBIGUOUS; + return GIT_EPEEL; default: return GIT_EINVALIDSPEC; @@ -303,6 +301,32 @@ static int peel_error(int error, const git_oid *oid, git_otype type) return error; } +static int check_type_combination(git_otype type, git_otype target) +{ + if (type == target) + return 0; + + switch (type) { + case GIT_OBJ_BLOB: + case GIT_OBJ_TREE: + /* a blob or tree can never be peeled to anything but themselves */ + return GIT_EINVALIDSPEC; + break; + case GIT_OBJ_COMMIT: + /* a commit can only be peeled to a tree */ + if (target != GIT_OBJ_TREE && target != GIT_OBJ_ANY) + return GIT_EINVALIDSPEC; + break; + case GIT_OBJ_TAG: + /* a tag may point to anything, so we let anything through */ + break; + default: + return GIT_EINVALIDSPEC; + } + + return 0; +} + int git_object_peel( git_object **peeled, const git_object *object, @@ -313,15 +337,18 @@ int git_object_peel( assert(object && peeled); - if (git_object_type(object) == target_type) - return git_object_dup(peeled, (git_object *)object); - assert(target_type == GIT_OBJ_TAG || target_type == GIT_OBJ_COMMIT || target_type == GIT_OBJ_TREE || target_type == GIT_OBJ_BLOB || target_type == GIT_OBJ_ANY); + if ((error = check_type_combination(git_object_type(object), target_type)) < 0) + return peel_error(error, git_object_id(object), target_type); + + if (git_object_type(object) == target_type) + return git_object_dup(peeled, (git_object *)object); + source = (git_object *)object; while (!(error = dereference_object(&deref, source))) { diff --git a/src/revwalk.c b/src/revwalk.c index 4dca7599a..e44385d48 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -124,7 +124,7 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, error = git_object_peel(&obj, oobj, GIT_OBJ_COMMIT); git_object_free(oobj); - if (error == GIT_ENOTFOUND) { + if (error == GIT_ENOTFOUND || error == GIT_EINVALIDSPEC || error == GIT_EPEEL) { /* If this comes from e.g. push_glob("tags"), ignore this */ if (from_glob) return 0; |