summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-11-19 18:42:29 +0100
committerCarlos Martín Nieto <cmn@dwim.me>2014-11-22 18:55:22 +0100
commit753e17b0f518c2510848a9dd73cc45e4c6df1a8a (patch)
tree39b27d69fa709024ba8b786c04bc66264d9cd97b /src
parent4d86caec599ab760b523a026040bc4f40f8338c9 (diff)
downloadlibgit2-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.c39
-rw-r--r--src/revwalk.c2
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;