Commit dbccfc20 by Edward Thomson

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.
parent 3eba9181
...@@ -41,6 +41,12 @@ typedef int GIT_CALLBACK(git_odb_foreach_cb)(const git_oid *id, void *payload); ...@@ -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. */ /** Options for configuring a loose object backend. */
typedef struct { typedef struct {
unsigned int version; /**< version for the 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; } git_odb_options;
/* The current version of the diff options structure */ /* The current version of the diff options structure */
......
...@@ -87,6 +87,8 @@ struct git_odb_stream { ...@@ -87,6 +87,8 @@ struct git_odb_stream {
unsigned int mode; unsigned int mode;
void *hash_ctx; void *hash_ctx;
git_oid_t oid_type;
git_object_size_t declared_size; git_object_size_t declared_size;
git_object_size_t received_bytes; git_object_size_t received_bytes;
......
...@@ -485,6 +485,9 @@ static void normalize_options( ...@@ -485,6 +485,9 @@ static void normalize_options(
memcpy(opts, given_opts, sizeof(git_odb_options)); memcpy(opts, given_opts, sizeof(git_odb_options));
else else
memcpy(opts, &init, sizeof(git_odb_options)); 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) int git_odb_new(git_odb **out, const git_odb_options *opts)
...@@ -1023,7 +1026,7 @@ int git_odb_exists_prefix( ...@@ -1023,7 +1026,7 @@ int git_odb_exists_prefix(
if (len < GIT_OID_MINPREFIXLEN) if (len < GIT_OID_MINPREFIXLEN)
return git_odb__error_ambiguous("prefix length too short"); 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 (git_odb_exists(db, short_id)) {
if (out) if (out)
git_oid_cpy(out, short_id); git_oid_cpy(out, short_id);
...@@ -1052,11 +1055,13 @@ int git_odb_expand_ids( ...@@ -1052,11 +1055,13 @@ int git_odb_expand_ids(
git_odb_expand_id *ids, git_odb_expand_id *ids,
size_t count) size_t count)
{ {
size_t i; size_t hex_size, i;
GIT_ASSERT_ARG(db); GIT_ASSERT_ARG(db);
GIT_ASSERT_ARG(ids); GIT_ASSERT_ARG(ids);
hex_size = git_oid_hexsize(db->options.oid_type);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
git_odb_expand_id *query = &ids[i]; git_odb_expand_id *query = &ids[i];
int error = GIT_EAMBIGUOUS; int error = GIT_EAMBIGUOUS;
...@@ -1065,13 +1070,13 @@ int git_odb_expand_ids( ...@@ -1065,13 +1070,13 @@ int git_odb_expand_ids(
query->type = GIT_OBJECT_ANY; query->type = GIT_OBJECT_ANY;
/* if we have a short OID, expand it first */ /* 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; git_oid actual_id;
error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false); error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false);
if (!error) { if (!error) {
git_oid_cpy(&query->id, &actual_id); 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( ...@@ -1079,7 +1084,7 @@ int git_odb_expand_ids(
* now we ought to have a 40-char OID, either because we've expanded it * 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. * 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; git_object_t actual_type;
error = odb_otype_fast(&actual_type, db, &query->id); error = odb_otype_fast(&actual_type, db, &query->id);
...@@ -1099,7 +1104,7 @@ int git_odb_expand_ids( ...@@ -1099,7 +1104,7 @@ int git_odb_expand_ids(
/* the object is missing or ambiguous */ /* the object is missing or ambiguous */
case GIT_ENOTFOUND: case GIT_ENOTFOUND:
case GIT_EAMBIGUOUS: case GIT_EAMBIGUOUS:
git_oid_clear(&query->id, GIT_OID_SHA1); git_oid_clear(&query->id, db->options.oid_type);
query->length = 0; query->length = 0;
query->type = 0; query->type = 0;
break; break;
...@@ -1207,7 +1212,7 @@ int git_odb__read_header_or_object( ...@@ -1207,7 +1212,7 @@ int git_odb__read_header_or_object(
error = odb_read_header_1(len_p, type_p, db, id, true); error = odb_read_header_1(len_p, type_p, db, id, true);
if (error == GIT_ENOTFOUND) 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 */ /* we found the header; return early */
if (!error) if (!error)
...@@ -1277,7 +1282,7 @@ static int odb_read_1( ...@@ -1277,7 +1282,7 @@ static int odb_read_1(
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
if (git_odb__strict_hash_verification) { 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; goto out;
if (!git_oid_equal(id, &hashed)) { 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) ...@@ -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); error = odb_read_1(out, db, id, true);
if (error == GIT_ENOTFOUND) 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; return error;
} }
...@@ -1418,7 +1423,7 @@ static int read_prefix_1(git_odb_object **out, git_odb *db, ...@@ -1418,7 +1423,7 @@ static int read_prefix_1(git_odb_object **out, git_odb *db,
if (git_odb__strict_hash_verification) { if (git_odb__strict_hash_verification) {
git_oid hash; 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; goto out;
if (!git_oid_equal(&found_full_oid, &hash)) { if (!git_oid_equal(&found_full_oid, &hash)) {
...@@ -1451,13 +1456,15 @@ int git_odb_read_prefix( ...@@ -1451,13 +1456,15 @@ int git_odb_read_prefix(
GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(out);
GIT_ASSERT_ARG(db); GIT_ASSERT_ARG(db);
hex_size = git_oid_hexsize(db->options.oid_type);
if (len < GIT_OID_MINPREFIXLEN) if (len < GIT_OID_MINPREFIXLEN)
return git_odb__error_ambiguous("prefix length too short"); return git_odb__error_ambiguous("prefix length too short");
if (len > GIT_OID_SHA1_HEXSIZE) if (len > hex_size)
len = GIT_OID_SHA1_HEXSIZE; len = hex_size;
if (len == GIT_OID_SHA1_HEXSIZE) { if (len == hex_size) {
*out = git_cache_get_raw(odb_cache(db), short_id); *out = git_cache_get_raw(odb_cache(db), short_id);
if (*out != NULL) if (*out != NULL)
return 0; return 0;
...@@ -1517,7 +1524,7 @@ int git_odb_write( ...@@ -1517,7 +1524,7 @@ int git_odb_write(
GIT_ASSERT_ARG(oid); GIT_ASSERT_ARG(oid);
GIT_ASSERT_ARG(db); 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; return error;
if (git_oid_is_zero(oid)) if (git_oid_is_zero(oid))
...@@ -1618,10 +1625,11 @@ int git_odb_open_wstream( ...@@ -1618,10 +1625,11 @@ int git_odb_open_wstream(
ctx = git__malloc(sizeof(git_hash_ctx)); ctx = git__malloc(sizeof(git_hash_ctx));
GIT_ERROR_CHECK_ALLOC(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) (error = hash_header(ctx, size, type)) < 0)
goto done; goto done;
(*stream)->oid_type = db->options.oid_type;
(*stream)->hash_ctx = ctx; (*stream)->hash_ctx = ctx;
(*stream)->declared_size = size; (*stream)->declared_size = size;
(*stream)->received_bytes = 0; (*stream)->received_bytes = 0;
...@@ -1665,7 +1673,7 @@ int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream) ...@@ -1665,7 +1673,7 @@ int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream)
"stream_finalize_write()"); "stream_finalize_write()");
git_hash_final(out->id, stream->hash_ctx); 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)) if (git_odb__freshen(stream->backend->odb, out))
return 0; return 0;
......
...@@ -122,6 +122,7 @@ GIT_INLINE(int) git_oid__cmp(const git_oid *a, const git_oid *b) ...@@ -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_INLINE(void) git_oid__cpy_prefix(
git_oid *out, const git_oid *id, size_t len) git_oid *out, const git_oid *id, size_t len)
{ {
out->type = id->type;
memcpy(&out->id, id->id, (len + 1) / 2); memcpy(&out->id, id->id, (len + 1) / 2);
if (len & 1) if (len & 1)
......
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