summaryrefslogtreecommitdiff
path: root/src/odb.c
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2014-03-10 10:53:39 -0700
committerRussell Belfer <rb@github.com>2014-03-10 11:34:50 -0700
commit894990788771bef6ca20398e46b217817b8e0db8 (patch)
tree70f93107a116e6a81cee68abb4b2b526fc6c760c /src/odb.c
parent9af14886a94ca4d08c7af1ba84b21cba40fce34c (diff)
downloadlibgit2-894990788771bef6ca20398e46b217817b8e0db8.tar.gz
Fix a number of git_odb_exists_prefix bugs
The git_odb_exists_prefix API was not dealing correctly when a later backend returned GIT_ENOTFOUND even if an earlier backend had found the object. Additionally, the unit tests were not properly exercising the API and had a couple mistakes in checking the results. Lastly, since the backends are not expected to behavior correctly unless all bytes of the short id are zero except for the prefix, this makes the ODB prefix APIs explicitly clear out the extra bytes so the user doesn't have to be as careful.
Diffstat (limited to 'src/odb.c')
-rw-r--r--src/odb.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/src/odb.c b/src/odb.c
index 085eda594..550951fd3 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -640,7 +640,7 @@ int git_odb_exists_prefix(
{
int error = GIT_ENOTFOUND, num_found = 0;
size_t i;
- git_oid last_found = {{0}}, found;
+ git_oid key = {{0}}, last_found = {{0}}, found;
assert(db && short_id);
@@ -659,6 +659,11 @@ int git_odb_exists_prefix(
}
}
+ /* just copy valid part of short_id */
+ memcpy(&key.id, short_id->id, (len + 1) / 2);
+ if (len & 1)
+ key.id[len / 2] &= 0xF0;
+
for (i = 0; i < db->backends.length; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend;
@@ -666,7 +671,7 @@ int git_odb_exists_prefix(
if (!b->exists_prefix)
continue;
- error = b->exists_prefix(&found, b, short_id, len);
+ error = b->exists_prefix(&found, b, &key, len);
if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
continue;
if (error)
@@ -683,11 +688,11 @@ int git_odb_exists_prefix(
}
if (!num_found)
- return git_odb__error_notfound("no match for id prefix", short_id);
+ return git_odb__error_notfound("no match for id prefix", &key);
if (out)
git_oid_cpy(out, &last_found);
- return error;
+ return 0;
}
int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id)
@@ -790,7 +795,7 @@ int git_odb_read_prefix(
{
size_t i;
int error = GIT_ENOTFOUND;
- git_oid found_full_oid = {{0}};
+ git_oid key = {{0}}, found_full_oid = {{0}};
git_rawobj raw;
void *data = NULL;
bool found = false;
@@ -809,13 +814,18 @@ int git_odb_read_prefix(
return 0;
}
+ /* just copy valid part of short_id */
+ memcpy(&key.id, short_id->id, (len + 1) / 2);
+ if (len & 1)
+ key.id[len / 2] &= 0xF0;
+
for (i = 0; i < db->backends.length; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend;
if (b->read_prefix != NULL) {
git_oid full_oid;
- error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, short_id, len);
+ error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, &key, len);
if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
continue;
@@ -836,7 +846,7 @@ int git_odb_read_prefix(
}
if (!found)
- return git_odb__error_notfound("no match for prefix", short_id);
+ return git_odb__error_notfound("no match for prefix", &key);
if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL)
return -1;