summaryrefslogtreecommitdiff
path: root/src/odb.c
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2016-03-09 11:00:27 +0100
committerVicent Marti <tanoku@gmail.com>2016-03-09 11:00:27 +0100
commit9a7866500545be7d06f1230c0c5109d669c4113a (patch)
tree3e9ab8009cc7dcddc8dd3e75ec1f1ea3230b5b39 /src/odb.c
parentc68044a8797d6eac5c8468dd5bec53d07b3ad66c (diff)
downloadlibgit2-9a7866500545be7d06f1230c0c5109d669c4113a.tar.gz
odb: Handle corner cases in `git_odb_expand_ids`
The old implementation had two issues: 1. OIDs that were too short as to be ambiguous were not being handled properly. 2. If the last OID to expand in the array was missing from the ODB, we would leak a `GIT_ENOTFOUND` error code from the function.
Diffstat (limited to 'src/odb.c')
-rw-r--r--src/odb.c49
1 files changed, 27 insertions, 22 deletions
diff --git a/src/odb.c b/src/odb.c
index 90336c082..9c35fd0f9 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -748,54 +748,59 @@ int git_odb_expand_ids(
size_t count)
{
size_t len, i;
- int error;
assert(db && ids);
for (i = 0; i < count; i++) {
git_odb_expand_id *query = &ids[i];
- git_oid *actual_id = NULL, tmp;
+ git_oid actual_id;
git_otype query_type = (query->type == GIT_OBJ_ANY) ? 0 : query->type;
git_otype actual_type = 0;
+ int error = GIT_EAMBIGUOUS;
/* if we were given a full object ID, simply look it up */
if (query->length >= GIT_OID_HEXSZ) {
error = git_odb_read_header(&len, &actual_type, db, &query->id);
+ git_oid_cpy(&actual_id, &query->id);
}
- /* otherwise, resolve the short id to full, then (optionally)
- * read the header.
+ /*
+ * otherwise, resolve the short id to full if it's long enough, then
+ * (optionally) read the header
*/
else if (query->length >= GIT_OID_MINPREFIXLEN) {
- error = odb_exists_prefix_1(&tmp,
- db, &query->id, query->length, false);
-
- if (!error) {
- actual_id = &tmp;
- error = git_odb_read_header(&len, &actual_type, db, &tmp);
- }
+ error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false);
+ if (!error)
+ error = git_odb_read_header(&len, &actual_type, db, &actual_id);
}
- if (error < 0 && error != GIT_ENOTFOUND && error != GIT_EAMBIGUOUS)
- break;
-
- if (error == 0 && (query_type == actual_type || !query_type)) {
- if (actual_id)
- git_oid_cpy(&query->id, actual_id);
+ /* Ensure that the looked up type matches the type we were expecting */
+ if (query_type && query_type != actual_type)
+ error = GIT_ENOTFOUND;
+ switch (error) {
+ case 0:
+ git_oid_cpy(&query->id, &actual_id);
query->length = GIT_OID_HEXSZ;
query->type = actual_type;
- } else {
+ break;
+
+ /* the object is missing or ambiguous */
+ case GIT_ENOTFOUND:
+ case GIT_EAMBIGUOUS:
memset(&query->id, 0, sizeof(git_oid));
query->length = 0;
query->type = 0;
+ break;
+
+ /* something went very wrong with the ODB; bail hard */
+ default:
+ return error;
}
}
- if (!error)
- giterr_clear();
-
- return error;
+ giterr_clear();
+ return 0;
}
int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id)