Commit 89499078 by Russell Belfer

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.
parent 9af14886
......@@ -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;
......
......@@ -73,16 +73,18 @@ void test_odb_loose__exists(void)
cl_git_pass(git_odb_open(&odb, "test-objects"));
cl_git_pass(git_oid_fromstr(&id, one.id));
cl_assert(git_odb_exists(odb, &id));
cl_assert(git_odb_exists_prefix(&id2, odb, &id, 8));
cl_assert(git_oid_equal(&id, &id2));
cl_git_pass(git_oid_fromstrp(&id, "8b137891"));
cl_git_pass(git_odb_exists_prefix(&id2, odb, &id, 8));
cl_assert_equal_i(0, git_oid_streq(&id2, one.id));
/* Test for a missing object */
cl_git_pass(git_oid_fromstr(&id, "8b137891791fe96927ad78e64b0aad7bded08baa"));
cl_assert(!git_odb_exists(odb, &id));
/* Test for a non-existant object */
cl_git_pass(git_oid_fromstr(&id2, "8b137891791fe96927ad78e64b0aad7bded08baa"));
cl_assert(!git_odb_exists(odb, &id2));
cl_assert_equal_i(GIT_ENOTFOUND, git_odb_exists_prefix(NULL, odb, &id2, 8));
cl_git_pass(git_oid_fromstrp(&id, "8b13789a"));
cl_assert_equal_i(GIT_ENOTFOUND, git_odb_exists_prefix(&id2, odb, &id, 8));
git_odb_free(odb);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment