Merge pull request #2178 from libgit2/rb/fix-short-id Fix git_odb_short_id and git_odb_exists_prefix bugs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
diff --git a/src/odb.c b/src/odb.c
index df21719..72d1506 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;
diff --git a/tests/object/shortid.c b/tests/object/shortid.c
index fa1dac0..d854cb7 100644
--- a/tests/object/shortid.c
+++ b/tests/object/shortid.c
@@ -26,6 +26,13 @@ void test_object_shortid__select(void)
cl_assert_equal_s("ce01362", shorty.ptr);
git_object_free(obj);
+ git_oid_fromstr(&full, "038d718da6a1ebbc6a7780a96ed75a70cc2ad6e2");
+ cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJ_ANY));
+ cl_git_pass(git_object_short_id(&shorty, obj));
+ cl_assert_equal_i(7, shorty.size);
+ cl_assert_equal_s("038d718", shorty.ptr);
+ git_object_free(obj);
+
git_oid_fromstr(&full, "dea509d097ce692e167dfc6a48a7a280cc5e877e");
cl_git_pass(git_object_lookup(&obj, _repo, &full, GIT_OBJ_ANY));
cl_git_pass(git_object_short_id(&shorty, obj));
diff --git a/tests/odb/loose.c b/tests/odb/loose.c
index ef7136e..c91927c 100644
--- a/tests/odb/loose.c
+++ b/tests/odb/loose.c
@@ -66,23 +66,25 @@ void test_odb_loose__cleanup(void)
void test_odb_loose__exists(void)
{
- git_oid id, id2;
+ git_oid id, id2;
git_odb *odb;
- write_object_files(&one);
+ write_object_files(&one);
cl_git_pass(git_odb_open(&odb, "test-objects"));
- cl_git_pass(git_oid_fromstr(&id, one.id));
+ cl_git_pass(git_oid_fromstr(&id, one.id));
+ cl_assert(git_odb_exists(odb, &id));
- cl_assert(git_odb_exists(odb, &id));
+ 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));
- cl_assert(git_odb_exists_prefix(&id2, odb, &id, 8));
- cl_assert(git_oid_equal(&id, &id2));
+ /* 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);
}
diff --git a/tests/resources/duplicate.git/objects/03/8d718da6a1ebbc6a7780a96ed75a70cc2ad6e2 b/tests/resources/duplicate.git/objects/03/8d718da6a1ebbc6a7780a96ed75a70cc2ad6e2
new file mode 100644
index 0000000..7350d98
Binary files /dev/null and b/tests/resources/duplicate.git/objects/03/8d718da6a1ebbc6a7780a96ed75a70cc2ad6e2 differ