Unverified Commit 50186ce8 by Edward Thomson Committed by GitHub

Merge pull request #4374 from pks-t/pks/pack-file-verify

Pack file verification
parents 8856337b 261267e0
...@@ -48,7 +48,7 @@ int index_pack(git_repository *repo, int argc, char **argv) ...@@ -48,7 +48,7 @@ int index_pack(git_repository *repo, int argc, char **argv)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (git_indexer_new(&idx, ".", 0, NULL, NULL, NULL) < 0) { if (git_indexer_new(&idx, ".", 0, NULL, NULL) < 0) {
puts("bad idx"); puts("bad idx");
return -1; return -1;
} }
......
...@@ -15,6 +15,33 @@ GIT_BEGIN_DECL ...@@ -15,6 +15,33 @@ GIT_BEGIN_DECL
typedef struct git_indexer git_indexer; typedef struct git_indexer git_indexer;
typedef struct git_indexer_options {
unsigned int version;
/** progress_cb function to call with progress information */
git_transfer_progress_cb progress_cb;
/** progress_cb_payload payload for the progress callback */
void *progress_cb_payload;
/** Do connectivity checks for the received pack */
unsigned char verify;
} git_indexer_options;
#define GIT_INDEXER_OPTIONS_VERSION 1
#define GIT_INDEXER_OPTIONS_INIT { GIT_INDEXER_OPTIONS_VERSION }
/**
* Initializes a `git_indexer_options` with default values. Equivalent to
* creating an instance with GIT_INDEXER_OPTIONS_INIT.
*
* @param opts the `git_indexer_options` struct to initialize.
* @param version Version of struct; pass `GIT_INDEXER_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_indexer_init_options(
git_indexer_options *opts,
unsigned int version);
/** /**
* Create a new indexer instance * Create a new indexer instance
* *
...@@ -24,16 +51,15 @@ typedef struct git_indexer git_indexer; ...@@ -24,16 +51,15 @@ typedef struct git_indexer git_indexer;
* @param odb object database from which to read base objects when * @param odb object database from which to read base objects when
* fixing thin packs. Pass NULL if no thin pack is expected (an error * fixing thin packs. Pass NULL if no thin pack is expected (an error
* will be returned if there are bases missing) * will be returned if there are bases missing)
* @param progress_cb function to call with progress information * @param opts Optional structure containing additional options. See
* @param progress_cb_payload payload for the progress callback * `git_indexer_options` above.
*/ */
GIT_EXTERN(int) git_indexer_new( GIT_EXTERN(int) git_indexer_new(
git_indexer **out, git_indexer **out,
const char *path, const char *path,
unsigned int mode, unsigned int mode,
git_odb *odb, git_odb *odb,
git_transfer_progress_cb progress_cb, git_indexer_options *opts);
void *progress_cb_payload);
/** /**
* Add data to the indexer * Add data to the indexer
......
...@@ -19,34 +19,54 @@ ...@@ -19,34 +19,54 @@
const void *git_blob_rawcontent(const git_blob *blob) const void *git_blob_rawcontent(const git_blob *blob)
{ {
assert(blob); assert(blob);
return git_odb_object_data(blob->odb_object); if (blob->raw)
return blob->data.raw.data;
else
return git_odb_object_data(blob->data.odb);
} }
git_off_t git_blob_rawsize(const git_blob *blob) git_off_t git_blob_rawsize(const git_blob *blob)
{ {
assert(blob); assert(blob);
return (git_off_t)git_odb_object_size(blob->odb_object); if (blob->raw)
return blob->data.raw.size;
else
return (git_off_t)git_odb_object_size(blob->data.odb);
} }
int git_blob__getbuf(git_buf *buffer, git_blob *blob) int git_blob__getbuf(git_buf *buffer, git_blob *blob)
{ {
return git_buf_set( return git_buf_set(
buffer, buffer,
git_odb_object_data(blob->odb_object), git_blob_rawcontent(blob),
git_odb_object_size(blob->odb_object)); git_blob_rawsize(blob));
} }
void git_blob__free(void *blob) void git_blob__free(void *_blob)
{ {
git_odb_object_free(((git_blob *)blob)->odb_object); git_blob *blob = (git_blob *) _blob;
if (!blob->raw)
git_odb_object_free(blob->data.odb);
git__free(blob); git__free(blob);
} }
int git_blob__parse(void *blob, git_odb_object *odb_obj) int git_blob__parse_raw(void *_blob, const char *data, size_t size)
{ {
git_blob *blob = (git_blob *) _blob;
assert(blob);
blob->raw = 1;
blob->data.raw.data = data;
blob->data.raw.size = size;
return 0;
}
int git_blob__parse(void *_blob, git_odb_object *odb_obj)
{
git_blob *blob = (git_blob *) _blob;
assert(blob); assert(blob);
git_cached_obj_incref((git_cached_obj *)odb_obj); git_cached_obj_incref((git_cached_obj *)odb_obj);
((git_blob *)blob)->odb_object = odb_obj; blob->raw = 0;
blob->data.odb = odb_obj;
return 0; return 0;
} }
...@@ -372,8 +392,8 @@ int git_blob_is_binary(const git_blob *blob) ...@@ -372,8 +392,8 @@ int git_blob_is_binary(const git_blob *blob)
assert(blob); assert(blob);
git_buf_attach_notowned(&content, blob->odb_object->buffer, git_buf_attach_notowned(&content, git_blob_rawcontent(blob),
min(blob->odb_object->cached.size, min(git_blob_rawsize(blob),
GIT_FILTER_BYTES_TO_CHECK_NUL)); GIT_FILTER_BYTES_TO_CHECK_NUL));
return git_buf_text_is_binary(&content); return git_buf_text_is_binary(&content);
} }
......
...@@ -16,11 +16,20 @@ ...@@ -16,11 +16,20 @@
struct git_blob { struct git_blob {
git_object object; git_object object;
git_odb_object *odb_object;
union {
git_odb_object *odb;
struct {
const char *data;
git_off_t size;
} raw;
} data;
unsigned int raw:1;
}; };
void git_blob__free(void *blob); void git_blob__free(void *blob);
int git_blob__parse(void *blob, git_odb_object *obj); 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__getbuf(git_buf *buffer, git_blob *blob); int git_blob__getbuf(git_buf *buffer, git_blob *blob);
extern int git_blob__create_from_paths( extern int git_blob__create_from_paths(
......
...@@ -383,11 +383,11 @@ int git_commit_amend( ...@@ -383,11 +383,11 @@ int git_commit_amend(
return error; return error;
} }
int git_commit__parse(void *_commit, git_odb_object *odb_obj) int git_commit__parse_raw(void *_commit, const char *data, size_t size)
{ {
git_commit *commit = _commit; git_commit *commit = _commit;
const char *buffer_start = git_odb_object_data(odb_obj), *buffer; const char *buffer_start = data, *buffer;
const char *buffer_end = buffer_start + git_odb_object_size(odb_obj); const char *buffer_end = buffer_start + size;
git_oid parent_id; git_oid parent_id;
size_t header_len; size_t header_len;
git_signature dummy_sig; git_signature dummy_sig;
...@@ -477,6 +477,13 @@ bad_buffer: ...@@ -477,6 +477,13 @@ bad_buffer:
return -1; return -1;
} }
int git_commit__parse(void *_commit, git_odb_object *odb_obj)
{
return git_commit__parse_raw(_commit,
git_odb_object_data(odb_obj),
git_odb_object_size(odb_obj));
}
#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \ #define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
_rvalue git_commit_##_name(const git_commit *commit) \ _rvalue git_commit_##_name(const git_commit *commit) \
{\ {\
......
...@@ -35,5 +35,6 @@ struct git_commit { ...@@ -35,5 +35,6 @@ struct git_commit {
void git_commit__free(void *commit); void git_commit__free(void *commit);
int git_commit__parse(void *commit, git_odb_object *obj); int git_commit__parse(void *commit, git_odb_object *obj);
int git_commit__parse_raw(void *commit, const char *data, size_t size);
#endif #endif
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "repository.h" #include "repository.h"
#include "commit.h" #include "commit.h"
#include "hash.h"
#include "tree.h" #include "tree.h"
#include "blob.h" #include "blob.h"
#include "oid.h" #include "oid.h"
...@@ -19,38 +20,86 @@ ...@@ -19,38 +20,86 @@
bool git_object__strict_input_validation = true; bool git_object__strict_input_validation = true;
extern int git_odb_hash(git_oid *out, const void *data, size_t len, git_otype type);
typedef struct { typedef struct {
const char *str; /* type name string */ const char *str; /* type name string */
size_t size; /* size in bytes of the object structure */ size_t size; /* size in bytes of the object structure */
int (*parse)(void *self, git_odb_object *obj); int (*parse)(void *self, git_odb_object *obj);
int (*parse_raw)(void *self, const char *data, size_t size);
void (*free)(void *self); void (*free)(void *self);
} git_object_def; } git_object_def;
static git_object_def git_objects_table[] = { static git_object_def git_objects_table[] = {
/* 0 = GIT_OBJ__EXT1 */ /* 0 = GIT_OBJ__EXT1 */
{ "", 0, NULL, NULL }, { "", 0, NULL, NULL, NULL },
/* 1 = GIT_OBJ_COMMIT */ /* 1 = GIT_OBJ_COMMIT */
{ "commit", sizeof(git_commit), git_commit__parse, git_commit__free }, { "commit", sizeof(git_commit), git_commit__parse, git_commit__parse_raw, git_commit__free },
/* 2 = GIT_OBJ_TREE */ /* 2 = GIT_OBJ_TREE */
{ "tree", sizeof(git_tree), git_tree__parse, git_tree__free }, { "tree", sizeof(git_tree), git_tree__parse, git_tree__parse_raw, git_tree__free },
/* 3 = GIT_OBJ_BLOB */ /* 3 = GIT_OBJ_BLOB */
{ "blob", sizeof(git_blob), git_blob__parse, git_blob__free }, { "blob", sizeof(git_blob), git_blob__parse, git_blob__parse_raw, git_blob__free },
/* 4 = GIT_OBJ_TAG */ /* 4 = GIT_OBJ_TAG */
{ "tag", sizeof(git_tag), git_tag__parse, git_tag__free }, { "tag", sizeof(git_tag), git_tag__parse, git_tag__parse_raw, git_tag__free },
/* 5 = GIT_OBJ__EXT2 */ /* 5 = GIT_OBJ__EXT2 */
{ "", 0, NULL, NULL }, { "", 0, NULL, NULL, NULL },
/* 6 = GIT_OBJ_OFS_DELTA */ /* 6 = GIT_OBJ_OFS_DELTA */
{ "OFS_DELTA", 0, NULL, NULL }, { "OFS_DELTA", 0, NULL, NULL, NULL },
/* 7 = GIT_OBJ_REF_DELTA */ /* 7 = GIT_OBJ_REF_DELTA */
{ "REF_DELTA", 0, NULL, NULL }, { "REF_DELTA", 0, NULL, NULL, NULL },
}; };
int git_object__from_raw(
git_object **object_out,
const char *data,
size_t size,
git_otype type)
{
git_object_def *def;
git_object *object;
size_t object_size;
int error;
assert(object_out);
*object_out = NULL;
/* Validate type match */
if (type != GIT_OBJ_BLOB && type != GIT_OBJ_TREE && type != GIT_OBJ_COMMIT && type != GIT_OBJ_TAG) {
giterr_set(GITERR_INVALID, "the requested type is invalid");
return GIT_ENOTFOUND;
}
if ((object_size = git_object__size(type)) == 0) {
giterr_set(GITERR_INVALID, "the requested type is invalid");
return GIT_ENOTFOUND;
}
/* Allocate and initialize base object */
object = git__calloc(1, object_size);
GITERR_CHECK_ALLOC(object);
object->cached.flags = GIT_CACHE_STORE_PARSED;
object->cached.type = type;
git_odb_hash(&object->cached.oid, data, size, type);
/* Parse raw object data */
def = &git_objects_table[type];
assert(def->free && def->parse_raw);
if ((error = def->parse_raw(object, data, size)) < 0)
def->free(object);
git_cached_obj_incref(object);
*object_out = object;
return 0;
}
int git_object__from_odb_object( int git_object__from_odb_object(
git_object **object_out, git_object **object_out,
git_repository *repo, git_repository *repo,
......
...@@ -22,6 +22,17 @@ struct git_object { ...@@ -22,6 +22,17 @@ struct git_object {
/* fully free the object; internal method, DO NOT EXPORT */ /* fully free the object; internal method, DO NOT EXPORT */
void git_object__free(void *object); void git_object__free(void *object);
/*
* Parse object from raw data. Note that the resulting object is
* tied to the lifetime of the data, as some objects simply point
* into it.
*/
int git_object__from_raw(
git_object **object_out,
const char *data,
size_t size,
git_otype type);
int git_object__from_odb_object( int git_object__from_odb_object(
git_object **object_out, git_object **object_out,
git_repository *repo, git_repository *repo,
......
...@@ -519,6 +519,7 @@ static int pack_backend__writepack(struct git_odb_writepack **out, ...@@ -519,6 +519,7 @@ static int pack_backend__writepack(struct git_odb_writepack **out,
git_transfer_progress_cb progress_cb, git_transfer_progress_cb progress_cb,
void *progress_payload) void *progress_payload)
{ {
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
struct pack_backend *backend; struct pack_backend *backend;
struct pack_writepack *writepack; struct pack_writepack *writepack;
...@@ -526,13 +527,16 @@ static int pack_backend__writepack(struct git_odb_writepack **out, ...@@ -526,13 +527,16 @@ static int pack_backend__writepack(struct git_odb_writepack **out,
*out = NULL; *out = NULL;
opts.progress_cb = progress_cb;
opts.progress_cb_payload = progress_payload;
backend = (struct pack_backend *)_backend; backend = (struct pack_backend *)_backend;
writepack = git__calloc(1, sizeof(struct pack_writepack)); writepack = git__calloc(1, sizeof(struct pack_writepack));
GITERR_CHECK_ALLOC(writepack); GITERR_CHECK_ALLOC(writepack);
if (git_indexer_new(&writepack->indexer, if (git_indexer_new(&writepack->indexer,
backend->pack_folder, 0, odb, progress_cb, progress_payload) < 0) { backend->pack_folder, 0, odb, &opts) < 0) {
git__free(writepack); git__free(writepack);
return -1; return -1;
} }
......
...@@ -41,6 +41,12 @@ struct pack_write_context { ...@@ -41,6 +41,12 @@ struct pack_write_context {
git_transfer_progress *stats; git_transfer_progress *stats;
}; };
struct walk_object {
git_oid id;
unsigned int uninteresting:1,
seen:1;
};
#ifdef GIT_THREADS #ifdef GIT_THREADS
#define GIT_PACKBUILDER__MUTEX_OP(pb, mtx, op) do { \ #define GIT_PACKBUILDER__MUTEX_OP(pb, mtx, op) do { \
...@@ -143,7 +149,7 @@ int git_packbuilder_new(git_packbuilder **out, git_repository *repo) ...@@ -143,7 +149,7 @@ int git_packbuilder_new(git_packbuilder **out, git_repository *repo)
if (!pb->walk_objects) if (!pb->walk_objects)
goto on_error; goto on_error;
git_pool_init(&pb->object_pool, sizeof(git_walk_object)); git_pool_init(&pb->object_pool, sizeof(struct walk_object));
pb->repo = repo; pb->repo = repo;
pb->nr_threads = 1; /* do not spawn any thread by default */ pb->nr_threads = 1; /* do not spawn any thread by default */
...@@ -1382,6 +1388,7 @@ int git_packbuilder_write( ...@@ -1382,6 +1388,7 @@ int git_packbuilder_write(
git_transfer_progress_cb progress_cb, git_transfer_progress_cb progress_cb,
void *progress_cb_payload) void *progress_cb_payload)
{ {
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
git_indexer *indexer; git_indexer *indexer;
git_transfer_progress stats; git_transfer_progress stats;
struct pack_write_context ctx; struct pack_write_context ctx;
...@@ -1389,8 +1396,11 @@ int git_packbuilder_write( ...@@ -1389,8 +1396,11 @@ int git_packbuilder_write(
PREPARE_PACK; PREPARE_PACK;
opts.progress_cb = progress_cb;
opts.progress_cb_payload = progress_cb_payload;
if (git_indexer_new( if (git_indexer_new(
&indexer, path, mode, pb->odb, progress_cb, progress_cb_payload) < 0) &indexer, path, mode, pb->odb, &opts) < 0)
return -1; return -1;
if (!git_repository__cvar(&t, pb->repo, GIT_CVAR_FSYNCOBJECTFILES) && t) if (!git_repository__cvar(&t, pb->repo, GIT_CVAR_FSYNCOBJECTFILES) && t)
...@@ -1513,9 +1523,9 @@ size_t git_packbuilder_written(git_packbuilder *pb) ...@@ -1513,9 +1523,9 @@ size_t git_packbuilder_written(git_packbuilder *pb)
return pb->nr_written; return pb->nr_written;
} }
int lookup_walk_object(git_walk_object **out, git_packbuilder *pb, const git_oid *id) static int lookup_walk_object(struct walk_object **out, git_packbuilder *pb, const git_oid *id)
{ {
git_walk_object *obj; struct walk_object *obj;
obj = git_pool_mallocz(&pb->object_pool, 1); obj = git_pool_mallocz(&pb->object_pool, 1);
if (!obj) { if (!obj) {
...@@ -1529,11 +1539,11 @@ int lookup_walk_object(git_walk_object **out, git_packbuilder *pb, const git_oid ...@@ -1529,11 +1539,11 @@ int lookup_walk_object(git_walk_object **out, git_packbuilder *pb, const git_oid
return 0; return 0;
} }
static int retrieve_object(git_walk_object **out, git_packbuilder *pb, const git_oid *id) static int retrieve_object(struct walk_object **out, git_packbuilder *pb, const git_oid *id)
{ {
int error; int error;
khiter_t pos; khiter_t pos;
git_walk_object *obj; struct walk_object *obj;
pos = git_oidmap_lookup_index(pb->walk_objects, id); pos = git_oidmap_lookup_index(pb->walk_objects, id);
if (git_oidmap_valid_index(pb->walk_objects, pos)) { if (git_oidmap_valid_index(pb->walk_objects, pos)) {
...@@ -1552,7 +1562,7 @@ static int retrieve_object(git_walk_object **out, git_packbuilder *pb, const git ...@@ -1552,7 +1562,7 @@ static int retrieve_object(git_walk_object **out, git_packbuilder *pb, const git
static int mark_blob_uninteresting(git_packbuilder *pb, const git_oid *id) static int mark_blob_uninteresting(git_packbuilder *pb, const git_oid *id)
{ {
int error; int error;
git_walk_object *obj; struct walk_object *obj;
if ((error = retrieve_object(&obj, pb, id)) < 0) if ((error = retrieve_object(&obj, pb, id)) < 0)
return error; return error;
...@@ -1564,7 +1574,7 @@ static int mark_blob_uninteresting(git_packbuilder *pb, const git_oid *id) ...@@ -1564,7 +1574,7 @@ static int mark_blob_uninteresting(git_packbuilder *pb, const git_oid *id)
static int mark_tree_uninteresting(git_packbuilder *pb, const git_oid *id) static int mark_tree_uninteresting(git_packbuilder *pb, const git_oid *id)
{ {
git_walk_object *obj; struct walk_object *obj;
git_tree *tree; git_tree *tree;
int error; int error;
size_t i; size_t i;
...@@ -1636,7 +1646,7 @@ int insert_tree(git_packbuilder *pb, git_tree *tree) ...@@ -1636,7 +1646,7 @@ int insert_tree(git_packbuilder *pb, git_tree *tree)
size_t i; size_t i;
int error; int error;
git_tree *subtree; git_tree *subtree;
git_walk_object *obj; struct walk_object *obj;
const char *name; const char *name;
if ((error = retrieve_object(&obj, pb, git_tree_id(tree))) < 0) if ((error = retrieve_object(&obj, pb, git_tree_id(tree))) < 0)
...@@ -1684,7 +1694,7 @@ int insert_tree(git_packbuilder *pb, git_tree *tree) ...@@ -1684,7 +1694,7 @@ int insert_tree(git_packbuilder *pb, git_tree *tree)
return error; return error;
} }
int insert_commit(git_packbuilder *pb, git_walk_object *obj) int insert_commit(git_packbuilder *pb, struct walk_object *obj)
{ {
int error; int error;
git_commit *commit = NULL; git_commit *commit = NULL;
...@@ -1714,7 +1724,7 @@ int git_packbuilder_insert_walk(git_packbuilder *pb, git_revwalk *walk) ...@@ -1714,7 +1724,7 @@ int git_packbuilder_insert_walk(git_packbuilder *pb, git_revwalk *walk)
{ {
int error; int error;
git_oid id; git_oid id;
git_walk_object *obj; struct walk_object *obj;
assert(pb && walk); assert(pb && walk);
......
...@@ -52,12 +52,6 @@ typedef struct git_pobject { ...@@ -52,12 +52,6 @@ typedef struct git_pobject {
filled:1; filled:1;
} git_pobject; } git_pobject;
typedef struct {
git_oid id;
unsigned int uninteresting:1,
seen:1;
} git_walk_object;
struct git_packbuilder { struct git_packbuilder {
git_repository *repo; /* associated repository */ git_repository *repo; /* associated repository */
git_odb *odb; /* associated object database */ git_odb *odb; /* associated object database */
......
...@@ -159,6 +159,11 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) ...@@ -159,6 +159,11 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
return 0; return 0;
} }
int git_tag__parse_raw(void *_tag, const char *data, size_t size)
{
return tag_parse(_tag, data, data + size);
}
int git_tag__parse(void *_tag, git_odb_object *odb_obj) int git_tag__parse(void *_tag, git_odb_object *odb_obj)
{ {
git_tag *tag = _tag; git_tag *tag = _tag;
......
...@@ -26,5 +26,6 @@ struct git_tag { ...@@ -26,5 +26,6 @@ struct git_tag {
void git_tag__free(void *tag); void git_tag__free(void *tag);
int git_tag__parse(void *tag, git_odb_object *obj); int git_tag__parse(void *tag, git_odb_object *obj);
int git_tag__parse_raw(void *tag, const char *data, size_t size);
#endif #endif
...@@ -375,18 +375,16 @@ static int parse_mode(unsigned int *modep, const char *buffer, const char **buff ...@@ -375,18 +375,16 @@ static int parse_mode(unsigned int *modep, const char *buffer, const char **buff
return 0; return 0;
} }
int git_tree__parse(void *_tree, git_odb_object *odb_obj) int git_tree__parse_raw(void *_tree, const char *data, size_t size)
{ {
git_tree *tree = _tree; git_tree *tree = _tree;
const char *buffer; const char *buffer;
const char *buffer_end; const char *buffer_end;
if (git_odb_object_dup(&tree->odb_obj, odb_obj) < 0) buffer = data;
return -1; buffer_end = buffer + size;
buffer = git_odb_object_data(tree->odb_obj);
buffer_end = buffer + git_odb_object_size(tree->odb_obj);
tree->odb_obj = NULL;
git_array_init_to_size(tree->entries, DEFAULT_TREE_SIZE); git_array_init_to_size(tree->entries, DEFAULT_TREE_SIZE);
GITERR_CHECK_ARRAY(tree->entries); GITERR_CHECK_ARRAY(tree->entries);
...@@ -426,6 +424,21 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj) ...@@ -426,6 +424,21 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj)
return 0; return 0;
} }
int git_tree__parse(void *_tree, git_odb_object *odb_obj)
{
git_tree *tree = _tree;
if ((git_tree__parse_raw(tree,
git_odb_object_data(odb_obj),
git_odb_object_size(odb_obj))) < 0)
return -1;
if (git_odb_object_dup(&tree->odb_obj, odb_obj) < 0)
return -1;
return 0;
}
static size_t find_next_dir(const char *dirname, git_index *index, size_t start) static size_t find_next_dir(const char *dirname, git_index *index, size_t start)
{ {
size_t dirlen, i, entries = git_index_entrycount(index); size_t dirlen, i, entries = git_index_entrycount(index);
......
...@@ -41,6 +41,7 @@ GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) ...@@ -41,6 +41,7 @@ GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e)
void git_tree__free(void *tree); void git_tree__free(void *tree);
int git_tree__parse(void *tree, git_odb_object *obj); int git_tree__parse(void *tree, git_odb_object *obj);
int git_tree__parse_raw(void *_tree, const char *data, size_t size);
/** /**
* Write a tree to the given repository * Write a tree to the given repository
......
...@@ -74,6 +74,24 @@ static const unsigned char leaky_pack[] = { ...@@ -74,6 +74,24 @@ static const unsigned char leaky_pack[] = {
}; };
static const unsigned int leaky_pack_len = 33; static const unsigned int leaky_pack_len = 33;
/*
* Packfile with a three objects. The first one is a tree referencing two blobs,
* the second object is one of those blobs. The second blob is missing.
*/
unsigned char incomplete_pack[] = {
0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
0xae, 0x03, 0x78, 0x9c, 0x33, 0x34, 0x30, 0x30, 0x33, 0x31, 0x51, 0x48,
0x4a, 0x2c, 0x62, 0x08, 0x17, 0x3b, 0x15, 0xd9, 0x7e, 0xfa, 0x67, 0x6d,
0xf6, 0x56, 0x4f, 0x85, 0x7d, 0xcb, 0xd6, 0xde, 0x53, 0xd1, 0x6d, 0x7f,
0x66, 0x08, 0x91, 0x4e, 0xcb, 0xcf, 0x67, 0x50, 0xad, 0x39, 0x9a, 0xa2,
0xb3, 0x71, 0x41, 0xc8, 0x87, 0x9e, 0x13, 0xf6, 0xba, 0x53, 0xec, 0xc2,
0xfe, 0xda, 0xed, 0x9b, 0x09, 0x00, 0xe8, 0xc8, 0x19, 0xab, 0x34, 0x78,
0x9c, 0x4b, 0x4a, 0x2c, 0xe2, 0x02, 0x00, 0x03, 0x9d, 0x01, 0x40, 0x4b,
0x72, 0xa2, 0x6f, 0xb6, 0x88, 0x2d, 0x6c, 0xa5, 0x07, 0xb2, 0xa5, 0x45,
0xe8, 0xdb, 0xe6, 0x53, 0xb3, 0x52, 0xe2
};
unsigned int incomplete_pack_len = 115;
static const unsigned char base_obj[] = { 07, 076 }; static const unsigned char base_obj[] = { 07, 076 };
static const unsigned int base_obj_len = 2; static const unsigned int base_obj_len = 2;
...@@ -82,7 +100,7 @@ void test_pack_indexer__out_of_order(void) ...@@ -82,7 +100,7 @@ void test_pack_indexer__out_of_order(void)
git_indexer *idx = 0; git_indexer *idx = 0;
git_transfer_progress stats = { 0 }; git_transfer_progress stats = { 0 };
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
cl_git_pass(git_indexer_append( cl_git_pass(git_indexer_append(
idx, out_of_order_pack, out_of_order_pack_len, &stats)); idx, out_of_order_pack, out_of_order_pack_len, &stats));
cl_git_pass(git_indexer_commit(idx, &stats)); cl_git_pass(git_indexer_commit(idx, &stats));
...@@ -99,7 +117,7 @@ void test_pack_indexer__missing_trailer(void) ...@@ -99,7 +117,7 @@ void test_pack_indexer__missing_trailer(void)
git_indexer *idx = 0; git_indexer *idx = 0;
git_transfer_progress stats = { 0 }; git_transfer_progress stats = { 0 };
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
cl_git_pass(git_indexer_append( cl_git_pass(git_indexer_append(
idx, missing_trailer_pack, missing_trailer_pack_len, &stats)); idx, missing_trailer_pack, missing_trailer_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats)); cl_git_fail(git_indexer_commit(idx, &stats));
...@@ -115,7 +133,7 @@ void test_pack_indexer__leaky(void) ...@@ -115,7 +133,7 @@ void test_pack_indexer__leaky(void)
git_indexer *idx = 0; git_indexer *idx = 0;
git_transfer_progress stats = { 0 }; git_transfer_progress stats = { 0 };
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
cl_git_pass(git_indexer_append( cl_git_pass(git_indexer_append(
idx, leaky_pack, leaky_pack_len, &stats)); idx, leaky_pack, leaky_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats)); cl_git_fail(git_indexer_commit(idx, &stats));
...@@ -142,7 +160,7 @@ void test_pack_indexer__fix_thin(void) ...@@ -142,7 +160,7 @@ void test_pack_indexer__fix_thin(void)
git_oid_fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18"); git_oid_fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18");
cl_assert_equal_oid(&should_id, &id); cl_assert_equal_oid(&should_id, &id);
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, odb, NULL));
cl_git_pass(git_indexer_append(idx, thin_pack, thin_pack_len, &stats)); cl_git_pass(git_indexer_append(idx, thin_pack, thin_pack_len, &stats));
cl_git_pass(git_indexer_commit(idx, &stats)); cl_git_pass(git_indexer_commit(idx, &stats));
...@@ -175,7 +193,7 @@ void test_pack_indexer__fix_thin(void) ...@@ -175,7 +193,7 @@ void test_pack_indexer__fix_thin(void)
cl_git_pass(p_stat(name, &st)); cl_git_pass(p_stat(name, &st));
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
read = p_read(fd, buffer, sizeof(buffer)); read = p_read(fd, buffer, sizeof(buffer));
cl_assert(read != -1); cl_assert(read != -1);
p_close(fd); p_close(fd);
...@@ -208,7 +226,7 @@ void test_pack_indexer__corrupt_length(void) ...@@ -208,7 +226,7 @@ void test_pack_indexer__corrupt_length(void)
git_oid_fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18"); git_oid_fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18");
cl_assert_equal_oid(&should_id, &id); cl_assert_equal_oid(&should_id, &id);
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, odb, NULL));
cl_git_pass(git_indexer_append( cl_git_pass(git_indexer_append(
idx, corrupt_thin_pack, corrupt_thin_pack_len, &stats)); idx, corrupt_thin_pack, corrupt_thin_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats)); cl_git_fail(git_indexer_commit(idx, &stats));
...@@ -221,6 +239,46 @@ void test_pack_indexer__corrupt_length(void) ...@@ -221,6 +239,46 @@ void test_pack_indexer__corrupt_length(void)
git_repository_free(repo); git_repository_free(repo);
} }
void test_pack_indexer__incomplete_pack_fails_with_strict(void)
{
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
git_indexer *idx = 0;
git_transfer_progress stats = { 0 };
opts.verify = 1;
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, &opts));
cl_git_pass(git_indexer_append(
idx, incomplete_pack, incomplete_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats));
cl_assert_equal_i(stats.total_objects, 2);
cl_assert_equal_i(stats.received_objects, 2);
cl_assert_equal_i(stats.indexed_objects, 2);
git_indexer_free(idx);
}
void test_pack_indexer__out_of_order_with_connectivity_checks(void)
{
git_indexer_options opts = GIT_INDEXER_OPTIONS_INIT;
git_indexer *idx = 0;
git_transfer_progress stats = { 0 };
opts.verify = 1;
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, &opts));
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));
cl_assert_equal_i(stats.total_objects, 3);
cl_assert_equal_i(stats.received_objects, 3);
cl_assert_equal_i(stats.indexed_objects, 3);
git_indexer_free(idx);
}
static int find_tmp_file_recurs(void *opaque, git_buf *path) static int find_tmp_file_recurs(void *opaque, git_buf *path)
{ {
int error = 0; int error = 0;
...@@ -252,7 +310,7 @@ void test_pack_indexer__no_tmp_files(void) ...@@ -252,7 +310,7 @@ void test_pack_indexer__no_tmp_files(void)
git_buf_dispose(&path); git_buf_dispose(&path);
cl_assert(git_buf_len(&first_tmp_file) == 0); cl_assert(git_buf_len(&first_tmp_file) == 0);
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
git_indexer_free(idx); git_indexer_free(idx);
cl_git_pass(git_buf_sets(&path, clar_sandbox_path())); cl_git_pass(git_buf_sets(&path, clar_sandbox_path()));
......
...@@ -100,7 +100,7 @@ void test_pack_packbuilder__create_pack(void) ...@@ -100,7 +100,7 @@ void test_pack_packbuilder__create_pack(void)
seed_packbuilder(); seed_packbuilder();
cl_git_pass(git_indexer_new(&_indexer, ".", 0, NULL, NULL, NULL)); cl_git_pass(git_indexer_new(&_indexer, ".", 0, NULL, NULL));
cl_git_pass(git_packbuilder_foreach(_packbuilder, feed_indexer, &stats)); cl_git_pass(git_packbuilder_foreach(_packbuilder, feed_indexer, &stats));
cl_git_pass(git_indexer_commit(_indexer, &stats)); cl_git_pass(git_indexer_commit(_indexer, &stats));
...@@ -237,7 +237,7 @@ void test_pack_packbuilder__foreach(void) ...@@ -237,7 +237,7 @@ void test_pack_packbuilder__foreach(void)
git_indexer *idx; git_indexer *idx;
seed_packbuilder(); seed_packbuilder();
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
cl_git_pass(git_packbuilder_foreach(_packbuilder, foreach_cb, idx)); cl_git_pass(git_packbuilder_foreach(_packbuilder, foreach_cb, idx));
cl_git_pass(git_indexer_commit(idx, &_stats)); cl_git_pass(git_indexer_commit(idx, &_stats));
git_indexer_free(idx); git_indexer_free(idx);
...@@ -255,7 +255,7 @@ void test_pack_packbuilder__foreach_with_cancel(void) ...@@ -255,7 +255,7 @@ void test_pack_packbuilder__foreach_with_cancel(void)
git_indexer *idx; git_indexer *idx;
seed_packbuilder(); seed_packbuilder();
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL)); cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL));
cl_git_fail_with( cl_git_fail_with(
git_packbuilder_foreach(_packbuilder, foreach_cancel_cb, idx), -1111); git_packbuilder_foreach(_packbuilder, foreach_cancel_cb, idx), -1111);
git_indexer_free(idx); 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