summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/indexer.c127
1 files changed, 78 insertions, 49 deletions
diff --git a/src/indexer.c b/src/indexer.c
index c331a4483..726667665 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -39,7 +39,8 @@ struct git_indexer {
struct git_indexer_stream {
unsigned int parsed_header :1,
opened_pack :1,
- have_stream :1;
+ have_stream :1,
+ have_delta :1;
struct git_pack_file *pack;
git_filebuf pack_file;
git_filebuf index_file;
@@ -180,39 +181,13 @@ cleanup:
}
/* Try to store the delta so we can try to resolve it later */
-static int store_delta(git_indexer_stream *idx, git_off_t entry_start, size_t entry_size, git_otype type)
+static int store_delta(git_indexer_stream *idx)
{
- git_mwindow *w = NULL;
struct delta_info *delta;
- git_rawobj obj;
- int error;
-
- assert(type == GIT_OBJ_REF_DELTA || type == GIT_OBJ_OFS_DELTA);
-
- if (type == GIT_OBJ_REF_DELTA) {
- idx->off += GIT_OID_RAWSZ;
- } else {
- git_off_t base_off;
-
- base_off = get_delta_base(idx->pack, &w, &idx->off, type, entry_start);
- git_mwindow_close(&w);
- if (base_off < 0)
- return (int)base_off;
- }
-
- error = packfile_unpack_compressed(&obj, idx->pack, &w, &idx->off, entry_size, type);
- if (error == GIT_EBUFS) {
- idx->off = entry_start;
- return GIT_EBUFS;
- } else if (error < 0){
- return -1;
- }
delta = git__calloc(1, sizeof(struct delta_info));
GITERR_CHECK_ALLOC(delta);
- delta->delta_off = entry_start;
-
- git__free(obj.data);
+ delta->delta_off = idx->entry_start;
if (git_vector_insert(&idx->deltas, delta) < 0)
return -1;
@@ -249,7 +224,44 @@ static int hash_object_stream(git_hash_ctx *ctx, git_packfile_stream *stream)
return 0;
}
-static int store_cache(git_indexer_stream *idx, git_hash_ctx *ctx, git_off_t entry_start)
+/* In order to create the packfile stream, we need to skip over the delta base description */
+static int advance_delta_offset(git_indexer_stream *idx, git_otype type)
+{
+ git_mwindow *w = NULL;
+
+ assert(type == GIT_OBJ_REF_DELTA || type == GIT_OBJ_OFS_DELTA);
+
+ if (type == GIT_OBJ_REF_DELTA) {
+ idx->off += GIT_OID_RAWSZ;
+ } else {
+ git_off_t base_off = get_delta_base(idx->pack, &w, &idx->off, type, idx->entry_start);
+ git_mwindow_close(&w);
+ if (base_off < 0)
+ return (int)base_off;
+ }
+
+ return 0;
+}
+
+/* Read from the stream and discard any output */
+static int read_object_stream(git_packfile_stream *stream)
+{
+ char buffer[4*1024];
+ ssize_t read;
+
+ assert(stream);
+
+ do {
+ read = git_packfile_stream_read(stream, buffer, sizeof(buffer));
+ } while (read > 0);
+
+ if (read < 0)
+ return (int)read;
+
+ return 0;
+}
+
+static int store_object(git_indexer_stream *idx)
{
int i;
git_oid oid;
@@ -258,8 +270,10 @@ static int store_cache(git_indexer_stream *idx, git_hash_ctx *ctx, git_off_t ent
struct entry *entry;
git_off_t entry_size;
git_mwindow *w = NULL;
- git_mwindow_file *mwf = &idx->pack->mwf;
struct git_pack_entry *pentry;
+ git_hash_ctx *ctx = &idx->hash_ctx;
+ git_mwindow_file *mwf = &idx->pack->mwf;
+ git_off_t entry_start = idx->entry_start;
entry = git__calloc(1, sizeof(*entry));
GITERR_CHECK_ALLOC(entry);
@@ -278,8 +292,10 @@ static int store_cache(git_indexer_stream *idx, git_hash_ctx *ctx, git_off_t ent
git_oid_cpy(&pentry->sha1, &oid);
pentry->offset = entry_start;
- if (git_vector_insert(&idx->pack->cache, pentry) < 0)
+ if (git_vector_insert(&idx->pack->cache, pentry) < 0) {
+ git__free(pentry);
goto on_error;
+ }
git_oid_cpy(&entry->oid, &oid);
entry->crc = crc32(0L, Z_NULL, 0);
@@ -302,7 +318,6 @@ static int store_cache(git_indexer_stream *idx, git_hash_ctx *ctx, git_off_t ent
return 0;
on_error:
- git__free(pentry);
git__free(entry);
return -1;
@@ -461,44 +476,59 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
git_mwindow_close(&w);
idx->entry_start = entry_start;
+ git_hash_ctx_init(&idx->hash_ctx);
if (type == GIT_OBJ_REF_DELTA || type == GIT_OBJ_OFS_DELTA) {
- error = store_delta(idx, entry_start, entry_size, type);
+ error = advance_delta_offset(idx, type);
if (error == GIT_EBUFS) {
idx->off = entry_start;
return 0;
}
if (error < 0)
- return error;
+ return -1;
- stats->received_objects++;
- do_progress_callback(idx, stats);
- continue;
+ idx->have_delta = 1;
+ } else {
+ idx->have_delta = 0;
+ hash_header(&idx->hash_ctx, entry_size, type);
}
- /* If we got this far, we create the stream for our object */
idx->have_stream = 1;
- git_hash_ctx_init(&idx->hash_ctx);
- hash_header(&idx->hash_ctx, entry_size, type);
- idx->entry_start = entry_start;
if (git_packfile_stream_open(stream, idx->pack, idx->off) < 0)
goto on_error;
+
}
- error = hash_object_stream(&idx->hash_ctx, stream);
- idx->off = idx->stream.curpos;
+ if (idx->have_delta) {
+ error = read_object_stream(stream);
+ } else {
+ error = hash_object_stream(&idx->hash_ctx, stream);
+ }
+
+ idx->off = stream->curpos;
if (error == GIT_EBUFS)
return 0;
+
+ /* We want to free the stream reasorces no matter what here */
+ idx->have_stream = 0;
+ git_packfile_stream_free(stream);
+
if (error < 0)
goto on_error;
- git_packfile_stream_free(&idx->stream);
- if (store_cache(idx, &idx->hash_ctx, idx->entry_start) < 0)
+ if (idx->have_delta) {
+ error = store_delta(idx);
+ } else {
+ error = store_object(idx);
+ }
+
+ if (error < 0)
goto on_error;
- stats->indexed_objects = (unsigned int)++processed;
+ if (!idx->have_delta) {
+ stats->indexed_objects = (unsigned int)++processed;
+ }
stats->received_objects++;
- idx->have_stream = 0;
do_progress_callback(idx, stats);
}
@@ -506,7 +536,6 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
return 0;
on_error:
- git_packfile_stream_free(&idx->stream);
git_mwindow_free_all(mwf);
return -1;
}