diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2022-09-21 05:09:46 -0400 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2023-02-12 22:02:00 +0000 |
commit | fe2ee3a018286b04cd0c64f84d437c7317c8f138 (patch) | |
tree | 196a29fc72ef0a27e0277b4d142cc93c28fa4cb7 /src | |
parent | 6204499242101d0f93cd7e56e259c900828e41e1 (diff) | |
download | libgit2-fe2ee3a018286b04cd0c64f84d437c7317c8f138.tar.gz |
object: lookup sha256 objects
This is much of the plumbing for the object database to support SHA256,
and for objects to be able to parse SHA256 versions of themselves.
Diffstat (limited to 'src')
-rw-r--r-- | src/cli/cmd_hash_object.c | 32 | ||||
-rw-r--r-- | src/libgit2/blob.c | 6 | ||||
-rw-r--r-- | src/libgit2/blob.h | 4 | ||||
-rw-r--r-- | src/libgit2/commit.c | 57 | ||||
-rw-r--r-- | src/libgit2/commit.h | 32 | ||||
-rw-r--r-- | src/libgit2/commit_list.c | 6 | ||||
-rw-r--r-- | src/libgit2/indexer.c | 79 | ||||
-rw-r--r-- | src/libgit2/object.c | 45 | ||||
-rw-r--r-- | src/libgit2/object.h | 3 | ||||
-rw-r--r-- | src/libgit2/odb_pack.c | 18 | ||||
-rw-r--r-- | src/libgit2/pack-objects.c | 13 | ||||
-rw-r--r-- | src/libgit2/repository.c | 5 | ||||
-rw-r--r-- | src/libgit2/tag.c | 25 | ||||
-rw-r--r-- | src/libgit2/tag.h | 4 | ||||
-rw-r--r-- | src/libgit2/tree.c | 38 | ||||
-rw-r--r-- | src/libgit2/tree.h | 4 |
16 files changed, 261 insertions, 110 deletions
diff --git a/src/cli/cmd_hash_object.c b/src/cli/cmd_hash_object.c index a64db8823..93b980d66 100644 --- a/src/cli/cmd_hash_object.c +++ b/src/cli/cmd_hash_object.c @@ -49,26 +49,37 @@ static void print_help(void) cli_opt_help_fprint(stdout, opts); } -static int hash_buf(git_odb *odb, git_str *buf, git_object_t type) +static int hash_buf( + git_odb *odb, + git_str *buf, + git_object_t object_type, + git_oid_t oid_type) { git_oid oid; if (!literally) { int valid = 0; - if (git_object_rawcontent_is_valid(&valid, buf->ptr, buf->size, type) < 0 || !valid) +#ifdef GIT_EXPERIMENTAL_SHA256 + if (git_object_rawcontent_is_valid(&valid, buf->ptr, buf->size, object_type, oid_type) < 0 || !valid) + return cli_error_git(); +#else + GIT_UNUSED(oid_type); + + if (git_object_rawcontent_is_valid(&valid, buf->ptr, buf->size, object_type) < 0 || !valid) return cli_error_git(); +#endif } if (write_object) { - if (git_odb_write(&oid, odb, buf->ptr, buf->size, type) < 0) + if (git_odb_write(&oid, odb, buf->ptr, buf->size, object_type) < 0) return cli_error_git(); } else { #ifdef GIT_EXPERIMENTAL_SHA256 - if (git_odb_hash(&oid, buf->ptr, buf->size, type, GIT_OID_SHA1) < 0) + if (git_odb_hash(&oid, buf->ptr, buf->size, object_type, GIT_OID_SHA1) < 0) return cli_error_git(); #else - if (git_odb_hash(&oid, buf->ptr, buf->size, type) < 0) + if (git_odb_hash(&oid, buf->ptr, buf->size, object_type) < 0) return cli_error_git(); #endif } @@ -83,9 +94,10 @@ int cmd_hash_object(int argc, char **argv) { git_repository *repo = NULL; git_odb *odb = NULL; + git_oid_t oid_type; git_str buf = GIT_STR_INIT; cli_opt invalid_opt; - git_object_t type = GIT_OBJECT_BLOB; + git_object_t object_type = GIT_OBJECT_BLOB; char **filename; int ret = 0; @@ -97,7 +109,7 @@ int cmd_hash_object(int argc, char **argv) return 0; } - if (type_name && (type = git_object_string2type(type_name)) == GIT_OBJECT_INVALID) + if (type_name && (object_type = git_object_string2type(type_name)) == GIT_OBJECT_INVALID) return cli_error_usage("invalid object type '%s'", type_name); if (write_object && @@ -107,6 +119,8 @@ int cmd_hash_object(int argc, char **argv) goto done; } + oid_type = git_repository_oid_type(repo); + /* * TODO: we're reading blobs, we shouldn't pull them all into main * memory, we should just stream them into the odb instead. @@ -118,7 +132,7 @@ int cmd_hash_object(int argc, char **argv) goto done; } - if ((ret = hash_buf(odb, &buf, type)) != 0) + if ((ret = hash_buf(odb, &buf, object_type, oid_type)) != 0) goto done; } else { for (filename = filenames; *filename; filename++) { @@ -127,7 +141,7 @@ int cmd_hash_object(int argc, char **argv) goto done; } - if ((ret = hash_buf(odb, &buf, type)) != 0) + if ((ret = hash_buf(odb, &buf, object_type, oid_type)) != 0) goto done; } } diff --git a/src/libgit2/blob.c b/src/libgit2/blob.c index b1680d3a8..5cfd7474b 100644 --- a/src/libgit2/blob.c +++ b/src/libgit2/blob.c @@ -52,11 +52,12 @@ void git_blob__free(void *_blob) git__free(blob); } -int git_blob__parse_raw(void *_blob, const char *data, size_t size) +int git_blob__parse_raw(void *_blob, const char *data, size_t size, git_oid_t oid_type) { git_blob *blob = (git_blob *) _blob; GIT_ASSERT_ARG(blob); + GIT_UNUSED(oid_type); blob->raw = 1; blob->data.raw.data = data; @@ -64,11 +65,12 @@ int git_blob__parse_raw(void *_blob, const char *data, size_t size) return 0; } -int git_blob__parse(void *_blob, git_odb_object *odb_obj) +int git_blob__parse(void *_blob, git_odb_object *odb_obj, git_oid_t oid_type) { git_blob *blob = (git_blob *) _blob; GIT_ASSERT_ARG(blob); + GIT_UNUSED(oid_type); git_cached_obj_incref((git_cached_obj *)odb_obj); blob->raw = 0; diff --git a/src/libgit2/blob.h b/src/libgit2/blob.h index 9a5dda225..d6c9dd99b 100644 --- a/src/libgit2/blob.h +++ b/src/libgit2/blob.h @@ -36,8 +36,8 @@ struct git_blob { } while(0) void git_blob__free(void *blob); -int git_blob__parse(void *blob, git_odb_object *obj); -int git_blob__parse_raw(void *blob, const char *data, size_t size); +int git_blob__parse(void *blob, git_odb_object *obj, git_oid_t oid_type); +int git_blob__parse_raw(void *blob, const char *data, size_t size, git_oid_t oid_type); int git_blob__getbuf(git_str *buffer, git_blob *blob); extern int git_blob__create_from_paths( diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c index 114ae6fc9..d85fefb3d 100644 --- a/src/libgit2/commit.c +++ b/src/libgit2/commit.c @@ -390,7 +390,11 @@ int git_commit_amend( return error; } -static int commit_parse(git_commit *commit, const char *data, size_t size, unsigned int flags) +static int commit_parse( + git_commit *commit, + const char *data, + size_t size, + git_commit__parse_options *opts) { const char *buffer_start = data, *buffer; const char *buffer_end = buffer_start + size; @@ -401,6 +405,7 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig GIT_ASSERT_ARG(commit); GIT_ASSERT_ARG(data); + GIT_ASSERT_ARG(opts); buffer = buffer_start; @@ -409,13 +414,14 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig GIT_ERROR_CHECK_ARRAY(commit->parent_ids); /* The tree is always the first field */ - if (!(flags & GIT_COMMIT_PARSE_QUICK)) { + if (!(opts->flags & GIT_COMMIT_PARSE_QUICK)) { if (git_object__parse_oid_header(&commit->tree_id, &buffer, buffer_end, "tree ", - GIT_OID_SHA1) < 0) + opts->oid_type) < 0) goto bad_buffer; } else { - size_t tree_len = strlen("tree ") + GIT_OID_SHA1_HEXSIZE + 1; + size_t tree_len = strlen("tree ") + git_oid_hexsize(opts->oid_type) + 1; + if (buffer + tree_len > buffer_end) goto bad_buffer; buffer += tree_len; @@ -427,14 +433,14 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig while (git_object__parse_oid_header(&parent_id, &buffer, buffer_end, "parent ", - GIT_OID_SHA1) == 0) { + opts->oid_type) == 0) { git_oid *new_id = git_array_alloc(commit->parent_ids); GIT_ERROR_CHECK_ALLOC(new_id); git_oid_cpy(new_id, &parent_id); } - if (!(flags & GIT_COMMIT_PARSE_QUICK)) { + if (!opts || !(opts->flags & GIT_COMMIT_PARSE_QUICK)) { commit->author = git__malloc(sizeof(git_signature)); GIT_ERROR_CHECK_ALLOC(commit->author); @@ -458,7 +464,7 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n')) < 0) return error; - if (flags & GIT_COMMIT_PARSE_QUICK) + if (opts && opts->flags & GIT_COMMIT_PARSE_QUICK) return 0; /* Parse add'l header entries */ @@ -503,19 +509,39 @@ bad_buffer: return GIT_EINVALID; } -int git_commit__parse_raw(void *commit, const char *data, size_t size) +int git_commit__parse( + void *commit, + git_odb_object *odb_obj, + git_oid_t oid_type) { - return commit_parse(commit, data, size, 0); + git_commit__parse_options parse_options = {0}; + parse_options.oid_type = oid_type; + + return git_commit__parse_ext(commit, odb_obj, &parse_options); } -int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags) +int git_commit__parse_raw( + void *commit, + const char *data, + size_t size, + git_oid_t oid_type) { - return commit_parse(commit, git_odb_object_data(odb_obj), git_odb_object_size(odb_obj), flags); + git_commit__parse_options parse_options = {0}; + parse_options.oid_type = oid_type; + + return commit_parse(commit, data, size, &parse_options); } -int git_commit__parse(void *_commit, git_odb_object *odb_obj) +int git_commit__parse_ext( + git_commit *commit, + git_odb_object *odb_obj, + git_commit__parse_options *parse_opts) { - return git_commit__parse_ext(_commit, odb_obj, 0); + return commit_parse( + commit, + git_odb_object_data(odb_obj), + git_odb_object_size(odb_obj), + parse_opts); } #define GIT_COMMIT_GETTER(_rvalue, _name, _return, _invalid) \ @@ -985,11 +1011,14 @@ int git_commit_create_with_signature( git_str commit = GIT_STR_INIT; git_commit *parsed; git_array_oid_t parents = GIT_ARRAY_INIT; + git_commit__parse_options parse_opts = {0}; + + parse_opts.oid_type = repo->oid_type; /* The first step is to verify that all the tree and parents exist */ parsed = git__calloc(1, sizeof(git_commit)); GIT_ERROR_CHECK_ALLOC(parsed); - if (commit_parse(parsed, commit_content, strlen(commit_content), 0) < 0) { + if (commit_parse(parsed, commit_content, strlen(commit_content), &parse_opts) < 0) { error = -1; goto cleanup; } diff --git a/src/libgit2/commit.h b/src/libgit2/commit.h index 7a2454e61..c25fee327 100644 --- a/src/libgit2/commit.h +++ b/src/libgit2/commit.h @@ -33,6 +33,16 @@ struct git_commit { char *body; }; +typedef struct { + git_oid_t oid_type; + unsigned int flags; +} git_commit__parse_options; + +typedef enum { + /** Only parse parents and committer info */ + GIT_COMMIT_PARSE_QUICK = (1 << 0) +} git_commit__parse_flags; + int git_commit__header_field( git_str *out, const git_commit *commit, @@ -56,14 +66,22 @@ int git_commit__create_buffer( size_t parent_count, const git_commit *parents[]); -void git_commit__free(void *commit); -int git_commit__parse(void *commit, git_odb_object *obj); -int git_commit__parse_raw(void *commit, const char *data, size_t size); +int git_commit__parse( + void *commit, + git_odb_object *obj, + git_oid_t oid_type); -typedef enum { - GIT_COMMIT_PARSE_QUICK = (1 << 0) /**< Only parse parents and committer info */ -} git_commit__parse_flags; +int git_commit__parse_raw( + void *commit, + const char *data, + size_t size, + git_oid_t oid_type); -int git_commit__parse_ext(git_commit *commit, git_odb_object *odb_obj, unsigned int flags); +int git_commit__parse_ext( + git_commit *commit, + git_odb_object *odb_obj, + git_commit__parse_options *parse_opts); + +void git_commit__free(void *commit); #endif diff --git a/src/libgit2/commit_list.c b/src/libgit2/commit_list.c index 511d7291f..12b329b25 100644 --- a/src/libgit2/commit_list.c +++ b/src/libgit2/commit_list.c @@ -124,13 +124,17 @@ static int commit_quick_parse( { git_oid *parent_oid; git_commit *commit; + git_commit__parse_options parse_opts = { + GIT_OID_SHA1, + GIT_COMMIT_PARSE_QUICK + }; size_t i; commit = git__calloc(1, sizeof(*commit)); GIT_ERROR_CHECK_ALLOC(commit); commit->object.repo = walk->repo; - if (git_commit__parse_ext(commit, obj, GIT_COMMIT_PARSE_QUICK) < 0) { + if (git_commit__parse_ext(commit, obj, &parse_opts) < 0) { git__free(commit); return -1; } diff --git a/src/libgit2/indexer.c b/src/libgit2/indexer.c index 98408646a..dfc326e02 100644 --- a/src/libgit2/indexer.c +++ b/src/libgit2/indexer.c @@ -42,6 +42,7 @@ struct git_indexer { have_delta :1, do_fsync :1, do_verify :1; + git_oid_t oid_type; struct git_pack_header hdr; struct git_pack_file *pack; unsigned int mode; @@ -68,7 +69,7 @@ struct git_indexer { git_odb *odb; /* Fields for calculating the packfile trailer (hash of everything before it) */ - char inbuf[GIT_OID_SHA1_SIZE]; + char inbuf[GIT_OID_MAX_SIZE]; size_t inbuf_len; git_hash_ctx trailer; }; @@ -136,12 +137,13 @@ int git_indexer_init_options(git_indexer_options *opts, unsigned int version) } #endif -int git_indexer_new( - git_indexer **out, - const char *prefix, - unsigned int mode, - git_odb *odb, - git_indexer_options *in_opts) +static int indexer_new( + git_indexer **out, + const char *prefix, + git_oid_t oid_type, + unsigned int mode, + git_odb *odb, + git_indexer_options *in_opts) { git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT; git_indexer *idx; @@ -154,6 +156,7 @@ int git_indexer_new( idx = git__calloc(1, sizeof(git_indexer)); GIT_ERROR_CHECK_ALLOC(idx); + idx->oid_type = oid_type; idx->odb = odb; idx->progress_cb = opts.progress_cb; idx->progress_payload = opts.progress_cb_payload; @@ -209,6 +212,33 @@ cleanup: return -1; } +#ifdef GIT_EXPERIMENTAL_SHA256 +int git_indexer_new( + git_indexer **out, + const char *prefix, + git_oid_t oid_type, + git_indexer_options *opts) +{ + return indexer_new( + out, + prefix, + oid_type, + opts ? opts->mode : 0, + opts ? opts->odb : NULL, + opts); +} +#else +int git_indexer_new( + git_indexer **out, + const char *prefix, + unsigned int mode, + git_odb *odb, + git_indexer_options *opts) +{ + return indexer_new(out, prefix, GIT_OID_SHA1, mode, odb, opts); +} +#endif + void git_indexer__set_fsync(git_indexer *idx, int do_fsync) { idx->do_fsync = !!do_fsync; @@ -273,7 +303,7 @@ static int advance_delta_offset(git_indexer *idx, git_object_t type) GIT_ASSERT_ARG(type == GIT_OBJECT_REF_DELTA || type == GIT_OBJECT_OFS_DELTA); if (type == GIT_OBJECT_REF_DELTA) { - idx->off += GIT_OID_SHA1_SIZE; + idx->off += git_oid_size(idx->oid_type); } else { off64_t base_off; int error = get_delta_base(&base_off, idx->pack, &w, &idx->off, type, idx->entry_start); @@ -357,7 +387,7 @@ static int check_object_connectivity(git_indexer *idx, const git_rawobj *obj) obj->type != GIT_OBJECT_TAG) return 0; - if (git_object__from_raw(&object, obj->data, obj->len, obj->type) < 0) { + if (git_object__from_raw(&object, obj->data, obj->len, obj->type, idx->oid_type) < 0) { /* * parse_raw returns EINVALID on invalid data; downgrade * that to a normal -1 error code. @@ -447,7 +477,7 @@ static int store_object(git_indexer *idx) } #ifdef GIT_EXPERIMENTAL_SHA256 - oid.type = GIT_OID_SHA1; + oid.type = idx->oid_type; #endif entry_size = idx->off - entry_start; @@ -550,7 +580,7 @@ static int hash_and_save(git_indexer *idx, git_rawobj *obj, off64_t entry_start) entry = git__calloc(1, sizeof(*entry)); GIT_ERROR_CHECK_ALLOC(entry); - if (git_odb__hashobj(&oid, obj, GIT_OID_SHA1) < 0) { + if (git_odb__hashobj(&oid, obj, idx->oid_type) < 0) { git_error_set(GIT_ERROR_INDEXER, "failed to hash object"); goto on_error; } @@ -588,30 +618,31 @@ static int do_progress_callback(git_indexer *idx, git_indexer_progress *stats) static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size) { size_t to_expell, to_keep; + size_t oid_size = git_oid_size(idx->oid_type); if (size == 0) return; /* Easy case, dump the buffer and the data minus the last 20 bytes */ - if (size >= GIT_OID_SHA1_SIZE) { + if (size >= oid_size) { git_hash_update(&idx->trailer, idx->inbuf, idx->inbuf_len); - git_hash_update(&idx->trailer, data, size - GIT_OID_SHA1_SIZE); + git_hash_update(&idx->trailer, data, size - oid_size); - data += size - GIT_OID_SHA1_SIZE; - memcpy(idx->inbuf, data, GIT_OID_SHA1_SIZE); - idx->inbuf_len = GIT_OID_SHA1_SIZE; + data += size - oid_size; + memcpy(idx->inbuf, data, oid_size); + idx->inbuf_len = oid_size; return; } /* We can just append */ - if (idx->inbuf_len + size <= GIT_OID_SHA1_SIZE) { + if (idx->inbuf_len + size <= oid_size) { memcpy(idx->inbuf + idx->inbuf_len, data, size); idx->inbuf_len += size; return; } /* We need to partially drain the buffer and then append */ - to_keep = GIT_OID_SHA1_SIZE - size; + to_keep = oid_size - size; to_expell = idx->inbuf_len - to_keep; git_hash_update(&idx->trailer, idx->inbuf, to_expell); @@ -906,7 +937,7 @@ static int index_path(git_str *path, git_indexer *idx, const char *suffix) slash--; if (git_str_grow(path, slash + 1 + strlen(prefix) + - GIT_OID_SHA1_HEXSIZE + strlen(suffix) + 1) < 0) + git_oid_hexsize(idx->oid_type) + strlen(suffix) + 1) < 0) return -1; git_str_truncate(path, slash); @@ -923,7 +954,7 @@ static int index_path(git_str *path, git_indexer *idx, const char *suffix) */ static int seek_back_trailer(git_indexer *idx) { - idx->pack->mwf.size -= GIT_OID_SHA1_SIZE; + idx->pack->mwf.size -= git_oid_size(idx->oid_type); return git_mwindow_free_all(&idx->pack->mwf); } @@ -983,7 +1014,7 @@ static int inject_object(git_indexer *idx, git_oid *id) if ((error = append_to_pack(idx, empty_checksum, checksum_size)) < 0) goto cleanup; - idx->pack->mwf.size += GIT_OID_SHA1_SIZE; + idx->pack->mwf.size += git_oid_size(idx->oid_type); pentry = git__calloc(1, sizeof(struct git_pack_entry)); GIT_ERROR_CHECK_ALLOC(pentry); @@ -1046,13 +1077,13 @@ static int fix_thin_pack(git_indexer *idx, git_indexer_progress *stats) } /* curpos now points to the base information, which is an OID */ - base_info = git_mwindow_open(&idx->pack->mwf, &w, curpos, GIT_OID_SHA1_SIZE, &left); + base_info = git_mwindow_open(&idx->pack->mwf, &w, curpos, git_oid_size(idx->oid_type), &left); if (base_info == NULL) { git_error_set(GIT_ERROR_INDEXER, "failed to map delta information"); return -1; } - git_oid__fromraw(&base, base_info, GIT_OID_SHA1); + git_oid__fromraw(&base, base_info, idx->oid_type); git_mwindow_close(&w); if (has_entry(idx, &base)) @@ -1275,7 +1306,7 @@ int git_indexer_commit(git_indexer *idx, git_indexer_progress *stats) /* Write out the object names (SHA-1 hashes) */ git_vector_foreach(&idx->objects, i, entry) { - git_filebuf_write(&index_file, &entry->oid.id, GIT_OID_SHA1_SIZE); + git_filebuf_write(&index_file, &entry->oid.id, git_oid_size(idx->oid_type)); } /* Write out the CRC32 values */ diff --git a/src/libgit2/object.c b/src/libgit2/object.c index d45465678..d87d40cf1 100644 --- a/src/libgit2/object.c +++ b/src/libgit2/object.c @@ -27,8 +27,8 @@ typedef struct { const char *str; /* type name string */ size_t size; /* size in bytes of the object structure */ - int (*parse)(void *self, git_odb_object *obj); - int (*parse_raw)(void *self, const char *data, size_t size); + int (*parse)(void *self, git_odb_object *obj, git_oid_t oid_type); + int (*parse_raw)(void *self, const char *data, size_t size, git_oid_t oid_type); void (*free)(void *self); } git_object_def; @@ -60,7 +60,8 @@ int git_object__from_raw( git_object **object_out, const char *data, size_t size, - git_object_t type) + git_object_t object_type, + git_oid_t oid_type) { git_object_def *def; git_object *object; @@ -71,12 +72,15 @@ int git_object__from_raw( *object_out = NULL; /* Validate type match */ - if (type != GIT_OBJECT_BLOB && type != GIT_OBJECT_TREE && type != GIT_OBJECT_COMMIT && type != GIT_OBJECT_TAG) { + if (object_type != GIT_OBJECT_BLOB && + object_type != GIT_OBJECT_TREE && + object_type != GIT_OBJECT_COMMIT && + object_type != GIT_OBJECT_TAG) { git_error_set(GIT_ERROR_INVALID, "the requested type is invalid"); return GIT_ENOTFOUND; } - if ((object_size = git_object__size(type)) == 0) { + if ((object_size = git_object__size(object_type)) == 0) { git_error_set(GIT_ERROR_INVALID, "the requested type is invalid"); return GIT_ENOTFOUND; } @@ -85,15 +89,15 @@ int git_object__from_raw( object = git__calloc(1, object_size); GIT_ERROR_CHECK_ALLOC(object); object->cached.flags = GIT_CACHE_STORE_PARSED; - object->cached.type = type; - if ((error = git_odb__hash(&object->cached.oid, data, size, type, GIT_OID_SHA1)) < 0) + object->cached.type = object_type; + if ((error = git_odb__hash(&object->cached.oid, data, size, object_type, oid_type)) < 0) return error; /* Parse raw object data */ - def = &git_objects_table[type]; + def = &git_objects_table[object_type]; GIT_ASSERT(def->free && def->parse_raw); - if ((error = def->parse_raw(object, data, size)) < 0) { + if ((error = def->parse_raw(object, data, size, oid_type)) < 0) { def->free(object); return error; } @@ -143,7 +147,7 @@ int git_object__from_odb_object( def = &git_objects_table[odb_obj->cached.type]; GIT_ASSERT(def->free && def->parse); - if ((error = def->parse(object, odb_obj)) < 0) { + if ((error = def->parse(object, odb_obj, repo->oid_type)) < 0) { /* * parse returns EINVALID on invalid data; downgrade * that to a normal -1 error code. @@ -357,12 +361,11 @@ static int dereference_object(git_object **dereferenced, git_object *obj) static int peel_error(int error, const git_oid *oid, git_object_t type) { const char *type_name; - char hex_oid[GIT_OID_SHA1_HEXSIZE + 1]; + char hex_oid[GIT_OID_MAX_HEXSIZE + 1]; type_name = git_object_type2string(type); - git_oid_fmt(hex_oid, oid); - hex_oid[GIT_OID_SHA1_HEXSIZE] = '\0'; + git_oid_nfmt(hex_oid, GIT_OID_MAX_HEXSIZE + 1, oid); git_error_set(GIT_ERROR_OBJECT, "the git_object of id '%s' can not be " "successfully peeled into a %s (git_object_t=%i).", hex_oid, type_name, type); @@ -576,21 +579,29 @@ int git_object_rawcontent_is_valid( int *valid, const char *buf, size_t len, - git_object_t type) + git_object_t object_type +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ) { git_object *obj = NULL; int error; +#ifndef GIT_EXPERIMENTAL_SHA256 + git_oid_t oid_type = GIT_OID_SHA1; +#endif + GIT_ASSERT_ARG(valid); GIT_ASSERT_ARG(buf); /* Blobs are always valid; don't bother parsing. */ - if (type == GIT_OBJECT_BLOB) { + if (object_type == GIT_OBJECT_BLOB) { *valid = 1; return 0; } - error = git_object__from_raw(&obj, buf, len, type); + error = git_object__from_raw(&obj, buf, len, object_type, oid_type); git_object_free(obj); if (error == 0) { @@ -611,7 +622,7 @@ int git_object__parse_oid_header( const char *header, git_oid_t oid_type) { - const size_t sha_len = GIT_OID_SHA1_HEXSIZE; + const size_t sha_len = git_oid_hexsize(oid_type); const size_t header_len = strlen(header); const char *buffer = *buffer_out; diff --git a/src/libgit2/object.h b/src/libgit2/object.h index 980e8627e..a29fdfbf3 100644 --- a/src/libgit2/object.h +++ b/src/libgit2/object.h @@ -33,7 +33,8 @@ int git_object__from_raw( git_object **object_out, const char *data, size_t size, - git_object_t type); + git_object_t object_type, + git_oid_t oid_type); int git_object__from_odb_object( git_object **object_out, diff --git a/src/libgit2/odb_pack.c b/src/libgit2/odb_pack.c index 814c0bc75..1b1d122b0 100644 --- a/src/libgit2/odb_pack.c +++ b/src/libgit2/odb_pack.c @@ -718,6 +718,7 @@ static int pack_backend__writepack(struct git_odb_writepack **out, git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT; struct pack_backend *backend; struct pack_writepack *writepack; + int error; GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(_backend); @@ -732,11 +733,20 @@ static int pack_backend__writepack(struct git_odb_writepack **out, writepack = git__calloc(1, sizeof(struct pack_writepack)); GIT_ERROR_CHECK_ALLOC(writepack); - if (git_indexer_new(&writepack->indexer, - backend->pack_folder, 0, odb, &opts) < 0) { - git__free(writepack); +#ifdef GIT_EXPERIMENTAL_SHA256 + opts.odb = odb; + + error = git_indexer_new(&writepack->indexer, + backend->pack_folder, + backend->opts.oid_type, + &opts); +#else + error = git_indexer_new(&writepack->indexer, + backend->pack_folder, 0, odb, &opts); +#endif + + if (error < 0) return -1; - } writepack->parent.backend = _backend; writepack->parent.append = pack_backend__writepack_append; diff --git a/src/libgit2/pack-objects.c b/src/libgit2/pack-objects.c index 068231649..20a5dfcbd 100644 --- a/src/libgit2/pack-objects.c +++ b/src/libgit2/pack-objects.c @@ -1407,7 +1407,18 @@ int git_packbuilder_write( opts.progress_cb = progress_cb; opts.progress_cb_payload = progress_cb_payload; - if ((error = git_indexer_new(&indexer, path, mode, pb->odb, &opts)) < 0) + /* TODO: SHA256 */ + +#ifdef GIT_EXPERIMENTAL_SHA256 + opts.mode = mode; + opts.odb = pb->odb; + + error = git_indexer_new(&indexer, path, GIT_OID_SHA1, &opts); +#else + error = git_indexer_new(&indexer, path, mode, pb->odb, &opts); +#endif + + if (error < 0) goto cleanup; if (!git_repository__configmap_lookup(&t, pb->repo, GIT_CONFIGMAP_FSYNCOBJECTFILES) && t) diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 043cfd1fd..2da6caf3a 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -1278,11 +1278,14 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo) *out = git_atomic_load(repo->_odb); if (*out == NULL) { git_str odb_path = GIT_STR_INIT; + git_odb_options odb_opts = GIT_ODB_OPTIONS_INIT; git_odb *odb; + odb_opts.oid_type = repo->oid_type; + if ((error = git_repository__item_path(&odb_path, repo, GIT_REPOSITORY_ITEM_OBJECTS)) < 0 || - (error = git_odb__new(&odb, NULL)) < 0) + (error = git_odb__new(&odb, &odb_opts)) < 0) return error; GIT_REFCOUNT_OWN(odb, repo); diff --git a/src/libgit2/tag.c b/src/libgit2/tag.c index 0a90e393c..562ec13ea 100644 --- a/src/libgit2/tag.c +++ b/src/libgit2/tag.c @@ -65,7 +65,11 @@ static int tag_error(const char *str) return GIT_EINVALID; } -static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) +static int tag_parse( + git_tag *tag, + const char *buffer, + const char *buffer_end, + git_oid_t oid_type) { static const char *tag_types[] = { NULL, "commit\n", "tree\n", "blob\n", "tag\n" @@ -76,7 +80,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) int error; if (git_object__parse_oid_header(&tag->target, - &buffer, buffer_end, "object ", GIT_OID_SHA1) < 0) + &buffer, buffer_end, "object ", oid_type) < 0) return tag_error("object field invalid"); if (buffer + 5 >= buffer_end) @@ -161,18 +165,25 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) return 0; } -int git_tag__parse_raw(void *_tag, const char *data, size_t size) +int git_tag__parse_raw( + void *_tag, + const char *data, + size_t size, + git_oid_t oid_type) { - return tag_parse(_tag, data, data + size); + return tag_parse(_tag, data, data + size, oid_type); } -int git_tag__parse(void *_tag, git_odb_object *odb_obj) +int git_tag__parse( + void *_tag, + git_odb_object *odb_obj, + git_oid_t oid_type) { git_tag *tag = _tag; const char *buffer = git_odb_object_data(odb_obj); const char *buffer_end = buffer + git_odb_object_size(odb_obj); - return tag_parse(tag, buffer, buffer_end); + return tag_parse(tag, buffer, buffer_end, oid_type); } static int retrieve_tag_reference( @@ -374,7 +385,7 @@ int git_tag_create_from_buffer(git_oid *oid, git_repository *repo, const char *b return -1; /* validate the buffer */ - if (tag_parse(&tag, buffer, buffer + strlen(buffer)) < 0) + if (tag_parse(&tag, buffer, buffer + strlen(buffer), repo->oid_type) < 0) return -1; /* validate the target */ diff --git a/src/libgit2/tag.h b/src/libgit2/tag.h index 76ae1508e..fdaaa463c 100644 --- a/src/libgit2/tag.h +++ b/src/libgit2/tag.h @@ -25,7 +25,7 @@ struct git_tag { }; void git_tag__free(void *tag); -int git_tag__parse(void *tag, git_odb_object *obj); -int git_tag__parse_raw(void *tag, const char *data, size_t size); +int git_tag__parse(void *tag, git_odb_object *obj, git_oid_t oid_type); +int git_tag__parse_raw(void *tag, const char *data, size_t size, git_oid_t oid_type); #endif diff --git a/src/libgit2/tree.c b/src/libgit2/tree.c index 9a43d585c..9293d9422 100644 --- a/src/libgit2/tree.c +++ b/src/libgit2/tree.c @@ -85,11 +85,17 @@ static git_tree_entry *alloc_entry(const char *filename, size_t filename_len, co char *filename_ptr; size_t tree_len; +#ifdef GIT_EXPERIMENTAL_SHA256 + size_t oid_size = git_oid_size(id->type); +#else + size_t oid_size = GIT_OID_SHA1_SIZE; +#endif + TREE_ENTRY_CHECK_NAMELEN(filename_len); if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) || GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) || - GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, GIT_OID_SHA1_SIZE)) + GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, oid_size)) return NULL; entry = git__calloc(1, tree_len); @@ -383,11 +389,12 @@ static int parse_mode(uint16_t *mode_out, const char *buffer, size_t buffer_len, return 0; } -int git_tree__parse_raw(void *_tree, const char *data, size_t size) +int git_tree__parse_raw(void *_tree, const char *data, size_t size, git_oid_t oid_type) { git_tree *tree = _tree; const char *buffer; const char *buffer_end; + const long oid_size = (long)git_oid_size(oid_type); buffer = data; buffer_end = buffer + size; @@ -414,35 +421,33 @@ int git_tree__parse_raw(void *_tree, const char *data, size_t size) if ((filename_len = nul - buffer) == 0 || filename_len > UINT16_MAX) return tree_parse_error("failed to parse tree: can't parse filename", NULL); - if ((buffer_end - (nul + 1)) < GIT_OID_SHA1_SIZE) + if ((buffer_end - (nul + 1)) < (long)oid_size) return tree_parse_error("failed to parse tree: can't parse OID", NULL); /* Allocate the entry */ - { - entry = git_array_alloc(tree->entries); - GIT_ERROR_CHECK_ALLOC(entry); - - entry->attr = attr; - entry->filename_len = (uint16_t)filename_len; - entry->filename = buffer; - git_oid__fromraw(&entry->oid, ((unsigned char *) buffer + filename_len + 1), GIT_OID_SHA1); - } + entry = git_array_alloc(tree->entries); + GIT_ERROR_CHECK_ALLOC(entry); + entry->attr = attr; + entry->filename_len = (uint16_t)filename_len; + entry->filename = buffer; buffer += filename_len + 1; - buffer += GIT_OID_SHA1_SIZE; + + git_oid__fromraw(&entry->oid, (unsigned char *)buffer, oid_type); + buffer += oid_size; } return 0; } -int git_tree__parse(void *_tree, git_odb_object *odb_obj) +int git_tree__parse(void *_tree, git_odb_object *odb_obj, git_oid_t oid_type) { git_tree *tree = _tree; const char *data = git_odb_object_data(odb_obj); size_t size = git_odb_object_size(odb_obj); int error; - if ((error = git_tree__parse_raw(tree, data, size)) < 0 || + if ((error = git_tree__parse_raw(tree, data, size, oid_type)) < 0 || (error = git_odb_object_dup(&tree->odb_obj, odb_obj)) < 0) return error; @@ -506,6 +511,7 @@ static int git_treebuilder__write_with_buffer( git_odb *odb; git_tree_entry *entry; git_vector entries = GIT_VECTOR_INIT; + size_t oid_size = git_oid_size(bld->repo->oid_type); git_str_clear(buf); @@ -529,7 +535,7 @@ static int git_treebuilder__write_with_buffer( git_str_printf(buf, "%o ", entry->attr); git_str_put(buf, entry->filename, entry->filename_len + 1); - git_str_put(buf, (char *)entry->oid.id, GIT_OID_SHA1_SIZE); + git_str_put(buf, (char *)entry->oid.id, oid_size); if (git_str_oom(buf)) { error = -1; diff --git a/src/libgit2/tree.h b/src/libgit2/tree.h index 0dd963ff2..5088450ab 100644 --- a/src/libgit2/tree.h +++ b/src/libgit2/tree.h @@ -41,8 +41,8 @@ GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) } void git_tree__free(void *tree); -int git_tree__parse(void *tree, git_odb_object *obj); -int git_tree__parse_raw(void *_tree, const char *data, size_t size); +int git_tree__parse(void *tree, git_odb_object *obj, git_oid_t oid_type); +int git_tree__parse_raw(void *_tree, const char *data, size_t size, git_oid_t oid_type); /** * Write a tree to the given repository |