Commit fe2ee3a0 by Edward Thomson

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.
parent 62044992
......@@ -28,11 +28,18 @@ int lg2_index_pack(git_repository *repo, int argc, char **argv)
return EXIT_FAILURE;
}
if (git_indexer_new(&idx, ".", 0, NULL, NULL) < 0) {
#ifdef GIT_EXPERIMENTAL_SHA256
error = git_indexer_new(&idx, ".", git_repository_oid_type(repo), NULL);
#else
error = git_indexer_new(&idx, ".", 0, NULL, NULL);
#endif
if (error < 0) {
puts("bad idx");
return -1;
}
if ((fd = open(argv[1], 0)) < 0) {
perror("open");
return -1;
......
......@@ -39,7 +39,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
* to do.
*/
for (i = 0; i < ARRAY_SIZE(types); i++) {
if (git_object__from_raw(&object, (const char *) data, size, types[i]) < 0)
if (git_object__from_raw(&object, (const char *) data, size, types[i], GIT_OID_SHA1) < 0)
continue;
git_object_free(object);
object = NULL;
......
......@@ -67,6 +67,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
git_str path = GIT_STR_INIT;
git_oid oid;
bool append_hash = false;
int error;
if (size == 0)
return 0;
......@@ -82,7 +83,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
abort();
}
if (git_indexer_new(&indexer, ".", 0, odb, NULL) < 0) {
#ifdef GIT_EXPERIMENTAL_SHA256
error = git_indexer_new(&indexer, ".", GIT_OID_SHA1, NULL);
#else
error = git_indexer_new(&indexer, ".", 0, odb, NULL);
#endif
if (error < 0) {
fprintf(stderr, "Failed to create the indexer: %s\n",
git_error_last()->message);
abort();
......
......@@ -62,6 +62,19 @@ typedef int GIT_CALLBACK(git_indexer_progress_cb)(const git_indexer_progress *st
typedef struct git_indexer_options {
unsigned int version;
#ifdef GIT_EXPERIMENTAL_SHA256
/** permissions to use creating packfile or 0 for defaults */
unsigned int mode;
/**
* object database from which to read base objects when
* fixing thin packs. This can be NULL if there are no thin
* packs; if a thin pack is encountered, an error will be
* returned if there are bases missing.
*/
git_odb *odb;
#endif
/** progress_cb function to call with progress information */
git_indexer_progress_cb progress_cb;
......@@ -87,6 +100,21 @@ GIT_EXTERN(int) git_indexer_options_init(
git_indexer_options *opts,
unsigned int version);
#ifdef GIT_EXPERIMENTAL_SHA256
/**
* Create a new indexer instance
*
* @param out where to store the indexer instance
* @param path to the directory where the packfile should be stored
* @param oid_type the oid type to use for objects
* @return 0 or an error code.
*/
GIT_EXTERN(int) git_indexer_new(
git_indexer **out,
const char *path,
git_oid_t oid_type,
git_indexer_options *opts);
#else
/**
* Create a new indexer instance
*
......@@ -106,6 +134,7 @@ GIT_EXTERN(int) git_indexer_new(
unsigned int mode,
git_odb *odb,
git_indexer_options *opts);
#endif
/**
* Add data to the indexer
......
......@@ -225,6 +225,7 @@ GIT_EXTERN(int) git_object_peel(
*/
GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source);
#ifdef GIT_EXPERIMENTAL_SHA256
/**
* Analyzes a buffer of raw object content and determines its validity.
* Tree, commit, and tag objects will be parsed and ensured that they
......@@ -238,14 +239,39 @@ GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source);
* @param valid Output pointer to set with validity of the object content
* @param buf The contents to validate
* @param len The length of the buffer
* @param type The type of the object in the buffer
* @param object_type The type of the object in the buffer
* @param oid_type The object ID type for the OIDs in the given buffer
* @return 0 on success or an error code
*/
GIT_EXTERN(int) git_object_rawcontent_is_valid(
int *valid,
const char *buf,
size_t len,
git_object_t type);
git_object_t object_type,
git_oid_t oid_type);
#else
/**
* Analyzes a buffer of raw object content and determines its validity.
* Tree, commit, and tag objects will be parsed and ensured that they
* are valid, parseable content. (Blobs are always valid by definition.)
* An error message will be set with an informative message if the object
* is not valid.
*
* @warning This function is experimental and its signature may change in
* the future.
*
* @param valid Output pointer to set with validity of the object content
* @param buf The contents to validate
* @param len The length of the buffer
* @param object_type The type of the object in the buffer
* @return 0 on success or an error code
*/
GIT_EXTERN(int) git_object_rawcontent_is_valid(
int *valid,
const char *buf,
size_t len,
git_object_t object_type);
#endif
/** @} */
GIT_END_DECL
......
......@@ -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;
}
}
......
......@@ -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;
......
......@@ -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(
......
......@@ -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;
}
......
......@@ -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
......@@ -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;
}
......
......@@ -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 */
......
......@@ -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;
......
......@@ -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,
......
......@@ -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;
......
......@@ -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)
......
......@@ -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);
......
......@@ -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 */
......
......@@ -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
......@@ -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;
......
......@@ -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
......
......@@ -287,7 +287,7 @@ static int parse_commit(git_commit **out, const char *buffer)
fake_odb_object.buffer = (char *)buffer;
fake_odb_object.cached.size = strlen(fake_odb_object.buffer);
error = git_commit__parse(commit, &fake_odb_object);
error = git_commit__parse(commit, &fake_odb_object, GIT_OID_SHA1);
*out = commit;
return error;
......
#include "clar_libgit2.h"
#include "repository.h"
#ifdef GIT_EXPERIMENTAL_SHA256
static git_repository *g_repo;
#endif
void test_object_lookup256__initialize(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
g_repo = cl_git_sandbox_init("testrepo_256.git");
#endif
}
void test_object_lookup256__cleanup(void)
{
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_sandbox_cleanup();
#endif
}
void test_object_lookup256__lookup_wrong_type_returns_enotfound(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *commit = "4d46d9719e425ef2dfb5bfba098d0b62e21b2b92d0731892eef70db0870e3744";
git_oid oid;
git_object *object;
cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256));
cl_assert_equal_i(
GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_TAG));
#endif
}
void test_object_lookup256__lookup_nonexisting_returns_enotfound(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *unknown = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
git_oid oid;
git_object *object;
cl_git_pass(git_oid__fromstr(&oid, unknown, GIT_OID_SHA256));
cl_assert_equal_i(
GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_ANY));
#endif
}
void test_object_lookup256__lookup_wrong_type_by_abbreviated_id_returns_enotfound(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *commit = "4d46d97";
git_oid oid;
git_object *object;
cl_git_pass(git_oid__fromstrn(&oid, commit, strlen(commit), GIT_OID_SHA256));
cl_assert_equal_i(
GIT_ENOTFOUND, git_object_lookup_prefix(&object, g_repo, &oid, strlen(commit), GIT_OBJECT_TAG));
#endif
}
void test_object_lookup256__lookup_wrong_type_eventually_returns_enotfound(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *commit = "4d46d9719e425ef2dfb5bfba098d0b62e21b2b92d0731892eef70db0870e3744";
git_oid oid;
git_object *object;
cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256));
cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT));
git_object_free(object);
cl_assert_equal_i(
GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_TAG));
#endif
}
void test_object_lookup256__lookup_corrupt_object_returns_error(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *commit = "5ca8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26848",
*file = "objects/5c/a8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26848";
git_str path = GIT_STR_INIT, contents = GIT_STR_INIT;
git_oid oid;
git_object *object;
size_t i;
cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256));
cl_git_pass(git_str_joinpath(&path, git_repository_path(g_repo), file));
cl_git_pass(git_futils_readbuffer(&contents, path.ptr));
/* Corrupt and try to read the object */
for (i = 0; i < contents.size; i++) {
contents.ptr[i] ^= 0x1;
cl_git_pass(git_futils_writebuffer(&contents, path.ptr, O_RDWR, 0644));
cl_git_fail(git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT));
contents.ptr[i] ^= 0x1;
}
/* Restore original content and assert we can read the object */
cl_git_pass(git_futils_writebuffer(&contents, path.ptr, O_RDWR, 0644));
cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT));
git_object_free(object);
git_str_dispose(&path);
git_str_dispose(&contents);
#endif
}
void test_object_lookup256__lookup_object_with_wrong_hash_returns_error(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
const char *oldloose = "objects/5c/a8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26848",
*newloose = "objects/5c/a8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26840",
*commit = "5ca8959deb2b8327458e0344523eb1ddeeef4bce03e35864640b452f84d26840";
git_str oldpath = GIT_STR_INIT, newpath = GIT_STR_INIT;
git_object *object;
git_oid oid;
cl_git_pass(git_oid__fromstr(&oid, commit, GIT_OID_SHA256));
/* Copy object to another location with wrong hash */
cl_git_pass(git_str_joinpath(&oldpath, git_repository_path(g_repo), oldloose));
cl_git_pass(git_str_joinpath(&newpath, git_repository_path(g_repo), newloose));
cl_git_pass(git_futils_cp(oldpath.ptr, newpath.ptr, 0644));
/* Verify that lookup fails due to a hashsum mismatch */
cl_git_fail_with(GIT_EMISMATCH, git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT));
/* Disable verification and try again */
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0));
cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJECT_COMMIT));
cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1));
git_object_free(object);
git_str_dispose(&oldpath);
git_str_dispose(&newpath);
#endif
}
......@@ -14,7 +14,7 @@ static void assert_tag_parses(const char *data, size_t datalen,
if (!datalen)
datalen = strlen(data);
cl_git_pass(git_object__from_raw((git_object **) &tag, data, datalen, GIT_OBJECT_TAG));
cl_git_pass(git_object__from_raw((git_object **) &tag, data, datalen, GIT_OBJECT_TAG, GIT_OID_SHA1));
cl_assert_equal_i(tag->type, GIT_OBJECT_TAG);
if (expected_oid) {
......@@ -54,7 +54,7 @@ static void assert_tag_fails(const char *data, size_t datalen)
git_object *object;
if (!datalen)
datalen = strlen(data);
cl_git_fail(git_object__from_raw(&object, data, datalen, GIT_OBJECT_TAG));
cl_git_fail(git_object__from_raw(&object, data, datalen, GIT_OBJECT_TAG, GIT_OID_SHA1));
}
void test_object_tag_parse__valid_tag_parses(void)
......
......@@ -26,7 +26,7 @@ static void assert_tree_parses(const char *data, size_t datalen,
if (!datalen)
datalen = strlen(data);
cl_git_pass(git_object__from_raw((git_object **) &tree, data, datalen, GIT_OBJECT_TREE));
cl_git_pass(git_object__from_raw((git_object **) &tree, data, datalen, GIT_OBJECT_TREE, GIT_OID_SHA1));
cl_assert_equal_i(git_tree_entrycount(tree), expected_nentries);
......@@ -51,7 +51,7 @@ static void assert_tree_fails(const char *data, size_t datalen)
git_object *object;
if (!datalen)
datalen = strlen(data);
cl_git_fail(git_object__from_raw(&object, data, datalen, GIT_OBJECT_TREE));
cl_git_fail(git_object__from_raw(&object, data, datalen, GIT_OBJECT_TREE, GIT_OID_SHA1));
}
void test_object_tree_parse__single_blob_parses(void)
......
#include "clar_libgit2.h"
#define VALID_COMMIT "tree bdd24e358576f1baa275df98cdcaf3ac9a3f4233\n" \
"parent d6d956f1d66210bfcd0484166befab33b5987a39\n" \
"author Edward Thomson <ethomson@edwardthomson.com> 1638286404 -0500\n" \
"committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
"\n" \
"commit go here.\n"
#define VALID_TREE "100644 HEADER\0\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
#define INVALID_COMMIT "tree bdd24e358576f1baa275df98cdcaf3ac9a3f4233\n" \
"parent d6d956f1d66210bfcd0484166befab33b5987a39\n" \
"committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
"\n" \
"commit go here.\n"
#define INVALID_TREE "100644 HEADER \x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
void test_object_validate__valid(void)
#define VALID_COMMIT_SHA1 \
"tree bdd24e358576f1baa275df98cdcaf3ac9a3f4233\n" \
"parent d6d956f1d66210bfcd0484166befab33b5987a39\n" \
"author Edward Thomson <ethomson@edwardthomson.com> 1638286404 -0500\n" \
"committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
"\n" \
"commit go here.\n"
#define VALID_TREE_SHA1 \
"100644 HEADER\0\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
#define INVALID_COMMIT_SHA1 \
"tree bdd24e358576f1baa275df98cdcaf3ac9a3f4233\n" \
"parent d6d956f1d66210bfcd0484166befab33b5987a39\n" \
"committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
"\n" \
"commit go here.\n"
#define INVALID_TREE_SHA1 \
"100644 HEADER \x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
#define VALID_COMMIT_SHA256 \
"tree d0fc7f52dc42358506e7f3f3be72f5271994abb104b9397ab3e19bb42361504d\n" \
"parent 652412419a24ba62a1d897f40aeb80eecbf873797b04a1bbb8d71918653ef65b\n" \
"author Edward Thomson <ethomson@edwardthomson.com> 1638286404 -0500\n" \
"committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
"\n" \
"commit go here.\n"
#define VALID_TREE_SHA256 \
"100644 HEADER\0\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
#define INVALID_COMMIT_SHA256 \
"tree d0fc7f52dc42358506e7f3f3be72f5271994abb104b9397ab3e19bb42361504d\n" \
"parent 652412419a24ba62a1d897f40aeb80eecbf873797b04a1bbb8d71918653ef65b\n" \
"committer Edward Thomson <ethomson@edwardthomson.com> 1638324642 -0500\n" \
"\n" \
"commit go here.\n"
#define INVALID_TREE_SHA256 \
"100644 HEADER \x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42\x42"
#ifdef GIT_EXPERIMENTAL_SHA256
# define sha1_rawcontent_is_valid(v, c, l, t) \
git_object_rawcontent_is_valid(v, c, l, t, GIT_OID_SHA1)
#else
# define sha1_rawcontent_is_valid(v, c, l, t) \
git_object_rawcontent_is_valid(v, c, l, t)
#endif
void test_object_validate__valid_sha1(void)
{
int valid;
cl_git_pass(sha1_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_BLOB));
cl_assert_equal_i(1, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_BLOB));
cl_assert_equal_i(1, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, VALID_COMMIT_SHA1, CONST_STRLEN(VALID_COMMIT_SHA1), GIT_OBJECT_COMMIT));
cl_assert_equal_i(1, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, VALID_TREE_SHA1, CONST_STRLEN(VALID_TREE_SHA1), GIT_OBJECT_TREE));
cl_assert_equal_i(1, valid);
}
void test_object_validate__cannot_parse_sha256_as_sha1(void)
{
int valid;
cl_git_pass(sha1_rawcontent_is_valid(&valid, VALID_COMMIT_SHA256, CONST_STRLEN(INVALID_COMMIT_SHA256), GIT_OBJECT_COMMIT));
cl_assert_equal_i(0, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, INVALID_TREE_SHA256, CONST_STRLEN(INVALID_TREE_SHA256), GIT_OBJECT_TREE));
cl_assert_equal_i(0, valid);
}
void test_object_validate__invalid_sha1(void)
{
int valid;
cl_git_pass(git_object_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_BLOB));
cl_git_pass(sha1_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_COMMIT));
cl_assert_equal_i(0, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_COMMIT));
cl_assert_equal_i(0, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, INVALID_COMMIT_SHA1, CONST_STRLEN(INVALID_COMMIT_SHA1), GIT_OBJECT_COMMIT));
cl_assert_equal_i(0, valid);
cl_git_pass(sha1_rawcontent_is_valid(&valid, INVALID_TREE_SHA1, CONST_STRLEN(INVALID_TREE_SHA1), GIT_OBJECT_TREE));
cl_assert_equal_i(0, valid);
}
void test_object_validate__valid_sha256(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
int valid;
cl_git_pass(git_object_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_BLOB, GIT_OID_SHA256));
cl_assert_equal_i(1, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_BLOB));
cl_git_pass(git_object_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_BLOB, GIT_OID_SHA256));
cl_assert_equal_i(1, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_COMMIT, CONST_STRLEN(VALID_COMMIT), GIT_OBJECT_COMMIT));
cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_COMMIT_SHA256, CONST_STRLEN(VALID_COMMIT_SHA256), GIT_OBJECT_COMMIT, GIT_OID_SHA256));
cl_assert_equal_i(1, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_TREE, CONST_STRLEN(VALID_TREE), GIT_OBJECT_TREE));
cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_TREE_SHA256, CONST_STRLEN(VALID_TREE_SHA256), GIT_OBJECT_TREE, GIT_OID_SHA256));
cl_assert_equal_i(1, valid);
#endif
}
void test_object_validate__invalid(void)
void test_object_validate__invalid_sha256(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
int valid;
cl_git_pass(git_object_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_COMMIT));
cl_git_pass(git_object_rawcontent_is_valid(&valid, "", 0, GIT_OBJECT_COMMIT, GIT_OID_SHA256));
cl_assert_equal_i(0, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_COMMIT, GIT_OID_SHA256));
cl_assert_equal_i(0, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, "foobar", 0, GIT_OBJECT_COMMIT));
cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_COMMIT_SHA256, CONST_STRLEN(INVALID_COMMIT_SHA256), GIT_OBJECT_COMMIT, GIT_OID_SHA256));
cl_assert_equal_i(0, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_COMMIT, CONST_STRLEN(INVALID_COMMIT), GIT_OBJECT_COMMIT));
cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_TREE_SHA256, CONST_STRLEN(INVALID_TREE_SHA256), GIT_OBJECT_TREE, GIT_OID_SHA256));
cl_assert_equal_i(0, valid);
#endif
}
void test_object_validate__cannot_parse_sha1_as_sha256(void)
{
#ifndef GIT_EXPERIMENTAL_SHA256
cl_skip();
#else
int valid;
cl_git_pass(git_object_rawcontent_is_valid(&valid, VALID_COMMIT_SHA1, CONST_STRLEN(INVALID_COMMIT_SHA1), GIT_OBJECT_COMMIT, GIT_OID_SHA256));
cl_assert_equal_i(0, valid);
cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_TREE, CONST_STRLEN(INVALID_TREE), GIT_OBJECT_TREE));
cl_git_pass(git_object_rawcontent_is_valid(&valid, INVALID_TREE_SHA1, CONST_STRLEN(INVALID_TREE_SHA1), GIT_OBJECT_TREE, GIT_OID_SHA256));
cl_assert_equal_i(0, valid);
#endif
}
......@@ -100,7 +100,12 @@ void test_pack_indexer__out_of_order(void)
git_indexer *idx = 0;
git_indexer_progress stats = { 0 };
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
cl_git_pass(git_indexer_append(
idx, out_of_order_pack, out_of_order_pack_len, &stats));
cl_git_pass(git_indexer_commit(idx, &stats));
......@@ -117,7 +122,12 @@ void test_pack_indexer__missing_trailer(void)
git_indexer *idx = 0;
git_indexer_progress stats = { 0 };
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
cl_git_pass(git_indexer_append(
idx, missing_trailer_pack, missing_trailer_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats));
......@@ -133,7 +143,12 @@ void test_pack_indexer__leaky(void)
git_indexer *idx = 0;
git_indexer_progress stats = { 0 };
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
cl_git_pass(git_indexer_append(
idx, leaky_pack, leaky_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats));
......@@ -151,6 +166,7 @@ void test_pack_indexer__fix_thin(void)
git_repository *repo;
git_odb *odb;
git_oid id, should_id;
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
cl_git_pass(git_repository_init(&repo, "thin.git", true));
cl_git_pass(git_repository_odb(&odb, repo));
......@@ -160,7 +176,13 @@ void test_pack_indexer__fix_thin(void)
git_oid__fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18", GIT_OID_SHA1);
cl_assert_equal_oid(&should_id, &id);
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, NULL));
#ifdef GIT_EXPERIMENTAL_SHA256
opts.odb = odb;
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, &opts));
#endif
cl_git_pass(git_indexer_append(idx, thin_pack, thin_pack_len, &stats));
cl_git_pass(git_indexer_commit(idx, &stats));
......@@ -192,7 +214,12 @@ void test_pack_indexer__fix_thin(void)
cl_git_pass(p_stat(name, &st));
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
read = p_read(fd, buffer, sizeof(buffer));
cl_assert(read != -1);
p_close(fd);
......@@ -216,6 +243,7 @@ void test_pack_indexer__corrupt_length(void)
git_repository *repo;
git_odb *odb;
git_oid id, should_id;
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
cl_git_pass(git_repository_init(&repo, "thin.git", true));
cl_git_pass(git_repository_odb(&odb, repo));
......@@ -225,7 +253,13 @@ void test_pack_indexer__corrupt_length(void)
git_oid__fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18", GIT_OID_SHA1);
cl_assert_equal_oid(&should_id, &id);
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, NULL));
#ifdef GIT_EXPERIMENTAL_SHA256
opts.odb = odb;
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, &opts));
#endif
cl_git_pass(git_indexer_append(
idx, corrupt_thin_pack, corrupt_thin_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats));
......@@ -246,7 +280,12 @@ void test_pack_indexer__incomplete_pack_fails_with_strict(void)
opts.verify = 1;
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, &opts));
#endif
cl_git_pass(git_indexer_append(
idx, incomplete_pack, incomplete_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats));
......@@ -266,7 +305,12 @@ void test_pack_indexer__out_of_order_with_connectivity_checks(void)
opts.verify = 1;
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, &opts));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, &opts));
#endif
cl_git_pass(git_indexer_append(
idx, out_of_order_pack, out_of_order_pack_len, &stats));
cl_git_pass(git_indexer_commit(idx, &stats));
......@@ -309,7 +353,12 @@ void test_pack_indexer__no_tmp_files(void)
git_str_dispose(&path);
cl_assert(git_str_len(&first_tmp_file) == 0);
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
git_indexer_free(idx);
cl_git_pass(git_str_sets(&path, clar_sandbox_path()));
......
......@@ -104,7 +104,12 @@ void test_pack_packbuilder__create_pack(void)
seed_packbuilder();
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&_indexer, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&_indexer, ".", 0, NULL, NULL));
#endif
cl_git_pass(git_packbuilder_foreach(_packbuilder, feed_indexer, &stats));
cl_git_pass(git_indexer_commit(_indexer, &stats));
......@@ -244,7 +249,13 @@ void test_pack_packbuilder__foreach(void)
git_indexer *idx;
seed_packbuilder();
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
cl_git_pass(git_packbuilder_foreach(_packbuilder, foreach_cb, idx));
cl_git_pass(git_indexer_commit(idx, &_stats));
git_indexer_free(idx);
......@@ -262,7 +273,13 @@ void test_pack_packbuilder__foreach_with_cancel(void)
git_indexer *idx;
seed_packbuilder();
#ifdef GIT_EXPERIMENTAL_SHA256
cl_git_pass(git_indexer_new(&idx, ".", GIT_OID_SHA1, NULL));
#else
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
#endif
cl_git_fail_with(
git_packbuilder_foreach(_packbuilder, foreach_cancel_cb, idx), -1111);
git_indexer_free(idx);
......
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