odb: accept an oid type in options Allow the object database to take an oid type that it supports. This oid type will be used to validate the objects that the backends provide.
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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
diff --git a/include/git2/odb.h b/include/git2/odb.h
index 12b5fc7..0952a1b 100644
--- a/include/git2/odb.h
+++ b/include/git2/odb.h
@@ -41,6 +41,12 @@ typedef int GIT_CALLBACK(git_odb_foreach_cb)(const git_oid *id, void *payload);
/** Options for configuring a loose object backend. */
typedef struct {
unsigned int version; /**< version for the struct */
+
+ /**
+ * Type of object IDs to use for this object database, or
+ * 0 for default (currently SHA1).
+ */
+ git_oid_t oid_type;
} git_odb_options;
/* The current version of the diff options structure */
diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h
index 5ad777b..d93ac73 100644
--- a/include/git2/odb_backend.h
+++ b/include/git2/odb_backend.h
@@ -87,6 +87,8 @@ struct git_odb_stream {
unsigned int mode;
void *hash_ctx;
+ git_oid_t oid_type;
+
git_object_size_t declared_size;
git_object_size_t received_bytes;
diff --git a/src/libgit2/odb.c b/src/libgit2/odb.c
index f979859..4e2e07a 100644
--- a/src/libgit2/odb.c
+++ b/src/libgit2/odb.c
@@ -485,6 +485,9 @@ static void normalize_options(
memcpy(opts, given_opts, sizeof(git_odb_options));
else
memcpy(opts, &init, sizeof(git_odb_options));
+
+ if (!opts->oid_type)
+ opts->oid_type = GIT_OID_DEFAULT;
}
int git_odb_new(git_odb **out, const git_odb_options *opts)
@@ -1023,7 +1026,7 @@ int git_odb_exists_prefix(
if (len < GIT_OID_MINPREFIXLEN)
return git_odb__error_ambiguous("prefix length too short");
- if (len >= GIT_OID_SHA1_HEXSIZE) {
+ if (len >= git_oid_hexsize(db->options.oid_type)) {
if (git_odb_exists(db, short_id)) {
if (out)
git_oid_cpy(out, short_id);
@@ -1052,11 +1055,13 @@ int git_odb_expand_ids(
git_odb_expand_id *ids,
size_t count)
{
- size_t i;
+ size_t hex_size, i;
GIT_ASSERT_ARG(db);
GIT_ASSERT_ARG(ids);
+ hex_size = git_oid_hexsize(db->options.oid_type);
+
for (i = 0; i < count; i++) {
git_odb_expand_id *query = &ids[i];
int error = GIT_EAMBIGUOUS;
@@ -1065,13 +1070,13 @@ int git_odb_expand_ids(
query->type = GIT_OBJECT_ANY;
/* if we have a short OID, expand it first */
- if (query->length >= GIT_OID_MINPREFIXLEN && query->length < GIT_OID_SHA1_HEXSIZE) {
+ if (query->length >= GIT_OID_MINPREFIXLEN && query->length < hex_size) {
git_oid actual_id;
error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false);
if (!error) {
git_oid_cpy(&query->id, &actual_id);
- query->length = GIT_OID_SHA1_HEXSIZE;
+ query->length = (unsigned short)hex_size;
}
}
@@ -1079,7 +1084,7 @@ int git_odb_expand_ids(
* now we ought to have a 40-char OID, either because we've expanded it
* or because the user passed a full OID. Ensure its type is right.
*/
- if (query->length >= GIT_OID_SHA1_HEXSIZE) {
+ if (query->length >= hex_size) {
git_object_t actual_type;
error = odb_otype_fast(&actual_type, db, &query->id);
@@ -1099,7 +1104,7 @@ int git_odb_expand_ids(
/* the object is missing or ambiguous */
case GIT_ENOTFOUND:
case GIT_EAMBIGUOUS:
- git_oid_clear(&query->id, GIT_OID_SHA1);
+ git_oid_clear(&query->id, db->options.oid_type);
query->length = 0;
query->type = 0;
break;
@@ -1207,7 +1212,7 @@ int git_odb__read_header_or_object(
error = odb_read_header_1(len_p, type_p, db, id, true);
if (error == GIT_ENOTFOUND)
- return git_odb__error_notfound("cannot read header for", id, GIT_OID_SHA1_HEXSIZE);
+ return git_odb__error_notfound("cannot read header for", id, git_oid_hexsize(db->options.oid_type));
/* we found the header; return early */
if (!error)
@@ -1277,7 +1282,7 @@ static int odb_read_1(
return GIT_ENOTFOUND;
if (git_odb__strict_hash_verification) {
- if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type, GIT_OID_SHA1)) < 0)
+ if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type, db->options.oid_type)) < 0)
goto out;
if (!git_oid_equal(id, &hashed)) {
@@ -1321,7 +1326,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
error = odb_read_1(out, db, id, true);
if (error == GIT_ENOTFOUND)
- return git_odb__error_notfound("no match for id", id, GIT_OID_SHA1_HEXSIZE);
+ return git_odb__error_notfound("no match for id", id, git_oid_hexsize(id->type));
return error;
}
@@ -1418,7 +1423,7 @@ static int read_prefix_1(git_odb_object **out, git_odb *db,
if (git_odb__strict_hash_verification) {
git_oid hash;
- if ((error = git_odb_hash(&hash, raw.data, raw.len, raw.type, GIT_OID_SHA1)) < 0)
+ if ((error = git_odb_hash(&hash, raw.data, raw.len, raw.type, db->options.oid_type)) < 0)
goto out;
if (!git_oid_equal(&found_full_oid, &hash)) {
@@ -1451,13 +1456,15 @@ int git_odb_read_prefix(
GIT_ASSERT_ARG(out);
GIT_ASSERT_ARG(db);
+ hex_size = git_oid_hexsize(db->options.oid_type);
+
if (len < GIT_OID_MINPREFIXLEN)
return git_odb__error_ambiguous("prefix length too short");
- if (len > GIT_OID_SHA1_HEXSIZE)
- len = GIT_OID_SHA1_HEXSIZE;
+ if (len > hex_size)
+ len = hex_size;
- if (len == GIT_OID_SHA1_HEXSIZE) {
+ if (len == hex_size) {
*out = git_cache_get_raw(odb_cache(db), short_id);
if (*out != NULL)
return 0;
@@ -1517,7 +1524,7 @@ int git_odb_write(
GIT_ASSERT_ARG(oid);
GIT_ASSERT_ARG(db);
- if ((error = git_odb_hash(oid, data, len, type, GIT_OID_SHA1)) < 0)
+ if ((error = git_odb_hash(oid, data, len, type, db->options.oid_type)) < 0)
return error;
if (git_oid_is_zero(oid))
@@ -1618,10 +1625,11 @@ int git_odb_open_wstream(
ctx = git__malloc(sizeof(git_hash_ctx));
GIT_ERROR_CHECK_ALLOC(ctx);
- if ((error = git_hash_ctx_init(ctx, GIT_HASH_ALGORITHM_SHA1)) < 0 ||
+ if ((error = git_hash_ctx_init(ctx, git_oid_algorithm(db->options.oid_type))) < 0 ||
(error = hash_header(ctx, size, type)) < 0)
goto done;
+ (*stream)->oid_type = db->options.oid_type;
(*stream)->hash_ctx = ctx;
(*stream)->declared_size = size;
(*stream)->received_bytes = 0;
@@ -1665,7 +1673,7 @@ int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream)
"stream_finalize_write()");
git_hash_final(out->id, stream->hash_ctx);
- out->type = GIT_OID_SHA1;
+ out->type = stream->oid_type;
if (git_odb__freshen(stream->backend->odb, out))
return 0;
diff --git a/src/libgit2/oid.h b/src/libgit2/oid.h
index 5b467cb..ede9a16 100644
--- a/src/libgit2/oid.h
+++ b/src/libgit2/oid.h
@@ -122,6 +122,7 @@ GIT_INLINE(int) git_oid__cmp(const git_oid *a, const git_oid *b)
GIT_INLINE(void) git_oid__cpy_prefix(
git_oid *out, const git_oid *id, size_t len)
{
+ out->type = id->type;
memcpy(&out->id, id->id, (len + 1) / 2);
if (len & 1)