Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/indexer.c')
-rw-r--r--src/indexer.c733
1 files changed, 295 insertions, 438 deletions
diff --git a/src/indexer.c b/src/indexer.c
index 6f735e651..2cfbd3a5a 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 the libgit2 contributors
+ * Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
@@ -17,7 +17,7 @@
#include "posix.h"
#include "pack.h"
#include "filebuf.h"
-#include "sha1.h"
+#include "oidmap.h"
#define UINT31_MAX (0x7FFFFFFF)
@@ -28,39 +28,32 @@ struct entry {
uint64_t offset_long;
};
-struct git_indexer {
- struct git_pack_file *pack;
- size_t nr_objects;
- git_vector objects;
- git_filebuf file;
- unsigned int fanout[256];
- git_oid hash;
-};
-
struct git_indexer_stream {
unsigned int parsed_header :1,
- opened_pack;
+ opened_pack :1,
+ have_stream :1,
+ have_delta :1;
struct git_pack_file *pack;
git_filebuf pack_file;
- git_filebuf index_file;
git_off_t off;
+ git_off_t entry_start;
+ git_packfile_stream stream;
size_t nr_objects;
git_vector objects;
git_vector deltas;
unsigned int fanout[256];
+ git_hash_ctx hash_ctx;
git_oid hash;
+ git_transfer_progress_callback progress_cb;
+ void *progress_payload;
+ char objbuf[8*1024];
};
struct delta_info {
git_off_t delta_off;
};
-const git_oid *git_indexer_hash(git_indexer *idx)
-{
- return &idx->hash;
-}
-
-const git_oid *git_indexer_stream_hash(git_indexer_stream *idx)
+const git_oid *git_indexer_stream_hash(const git_indexer_stream *idx)
{
return &idx->hash;
}
@@ -130,23 +123,21 @@ static int objects_cmp(const void *a, const void *b)
return git_oid_cmp(&entrya->oid, &entryb->oid);
}
-static int cache_cmp(const void *a, const void *b)
-{
- const struct git_pack_entry *ea = a;
- const struct git_pack_entry *eb = b;
-
- return git_oid_cmp(&ea->sha1, &eb->sha1);
-}
-
-int git_indexer_stream_new(git_indexer_stream **out, const char *prefix)
+int git_indexer_stream_new(
+ git_indexer_stream **out,
+ const char *prefix,
+ git_transfer_progress_callback progress_cb,
+ void *progress_payload)
{
git_indexer_stream *idx;
git_buf path = GIT_BUF_INIT;
- static const char suff[] = "/objects/pack/pack-received";
+ static const char suff[] = "/pack";
int error;
idx = git__calloc(1, sizeof(git_indexer_stream));
GITERR_CHECK_ALLOC(idx);
+ idx->progress_cb = progress_cb;
+ idx->progress_payload = progress_payload;
error = git_buf_joinpath(&path, prefix, suff);
if (error < 0)
@@ -171,69 +162,171 @@ cleanup:
/* Try to store the delta so we can try to resolve it later */
static int store_delta(git_indexer_stream *idx)
{
- git_otype type;
- git_mwindow *w = NULL;
- git_mwindow_file *mwf = &idx->pack->mwf;
- git_off_t entry_start = idx->off;
struct delta_info *delta;
- size_t entry_size;
- git_rawobj obj;
- int error;
- /*
- * ref-delta objects can refer to object that we haven't
- * found yet, so give it another opportunity
- */
- if (git_packfile_unpack_header(&entry_size, &type, mwf, &w, &idx->off) < 0)
+ delta = git__calloc(1, sizeof(struct delta_info));
+ GITERR_CHECK_ALLOC(delta);
+ delta->delta_off = idx->entry_start;
+
+ if (git_vector_insert(&idx->deltas, delta) < 0)
return -1;
- git_mwindow_close(&w);
+ return 0;
+}
- /* If it's not a delta, mark it as failure, we can't do anything with it */
- if (type != GIT_OBJ_REF_DELTA && type != GIT_OBJ_OFS_DELTA)
- return -1;
+static void hash_header(git_hash_ctx *ctx, git_off_t len, git_otype type)
+{
+ char buffer[64];
+ size_t hdrlen;
+
+ hdrlen = git_odb__format_object_header(buffer, sizeof(buffer), (size_t)len, type);
+ git_hash_update(ctx, buffer, hdrlen);
+}
+
+static int hash_object_stream(git_indexer_stream *idx, git_packfile_stream *stream)
+{
+ ssize_t read;
+
+ assert(idx && stream);
+
+ do {
+ if ((read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf))) < 0)
+ break;
+
+ git_hash_update(&idx->hash_ctx, idx->objbuf, read);
+ } while (read > 0);
+
+ if (read < 0)
+ return (int)read;
+
+ return 0;
+}
+
+/* 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;
-
- base_off = get_delta_base(idx->pack, &w, &idx->off, type, entry_start);
+ 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;
}
- 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;
+ return 0;
+}
+
+/* Read from the stream and discard any output */
+static int read_object_stream(git_indexer_stream *idx, git_packfile_stream *stream)
+{
+ ssize_t read;
+
+ assert(stream);
+
+ do {
+ read = git_packfile_stream_read(stream, idx->objbuf, sizeof(idx->objbuf));
+ } while (read > 0);
+
+ if (read < 0)
+ return (int)read;
+
+ return 0;
+}
+
+static int crc_object(uint32_t *crc_out, git_mwindow_file *mwf, git_off_t start, git_off_t size)
+{
+ void *ptr;
+ uint32_t crc;
+ unsigned int left, len;
+ git_mwindow *w = NULL;
+
+ crc = crc32(0L, Z_NULL, 0);
+ while (size) {
+ ptr = git_mwindow_open(mwf, &w, start, (size_t)size, &left);
+ if (ptr == NULL)
+ return -1;
+
+ len = min(left, (unsigned int)size);
+ crc = crc32(crc, ptr, len);
+ size -= len;
+ start += len;
+ git_mwindow_close(&w);
}
- delta = git__calloc(1, sizeof(struct delta_info));
- GITERR_CHECK_ALLOC(delta);
- delta->delta_off = entry_start;
+ *crc_out = htonl(crc);
+ return 0;
+}
+
+static int store_object(git_indexer_stream *idx)
+{
+ int i, error;
+ khiter_t k;
+ git_oid oid;
+ struct entry *entry;
+ git_off_t entry_size;
+ struct git_pack_entry *pentry;
+ git_hash_ctx *ctx = &idx->hash_ctx;
+ git_off_t entry_start = idx->entry_start;
- git__free(obj.data);
+ entry = git__calloc(1, sizeof(*entry));
+ GITERR_CHECK_ALLOC(entry);
- if (git_vector_insert(&idx->deltas, delta) < 0)
- return -1;
+ pentry = git__malloc(sizeof(struct git_pack_entry));
+ GITERR_CHECK_ALLOC(pentry);
+
+ git_hash_final(&oid, ctx);
+ entry_size = idx->off - entry_start;
+ if (entry_start > UINT31_MAX) {
+ entry->offset = UINT32_MAX;
+ entry->offset_long = entry_start;
+ } else {
+ entry->offset = (uint32_t)entry_start;
+ }
+
+ git_oid_cpy(&pentry->sha1, &oid);
+ pentry->offset = entry_start;
+
+ k = kh_put(oid, idx->pack->idx_cache, &pentry->sha1, &error);
+ if (!error) {
+ git__free(pentry);
+ goto on_error;
+ }
+
+ kh_value(idx->pack->idx_cache, k) = pentry;
+
+ git_oid_cpy(&entry->oid, &oid);
+
+ if (crc_object(&entry->crc, &idx->pack->mwf, entry_start, entry_size) < 0)
+ goto on_error;
+
+ /* Add the object to the list */
+ if (git_vector_insert(&idx->objects, entry) < 0)
+ goto on_error;
+
+ for (i = oid.id[0]; i < 256; ++i) {
+ idx->fanout[i]++;
+ }
return 0;
+
+on_error:
+ git__free(entry);
+
+ return -1;
}
static int hash_and_save(git_indexer_stream *idx, git_rawobj *obj, git_off_t entry_start)
{
- int i;
+ int i, error;
+ khiter_t k;
git_oid oid;
- void *packed;
size_t entry_size;
- unsigned int left;
struct entry *entry;
- git_mwindow *w = NULL;
- git_mwindow_file *mwf = &idx->pack->mwf;
struct git_pack_entry *pentry;
entry = git__calloc(1, sizeof(*entry));
@@ -257,20 +350,21 @@ static int hash_and_save(git_indexer_stream *idx, git_rawobj *obj, git_off_t ent
git_oid_cpy(&pentry->sha1, &oid);
pentry->offset = entry_start;
- if (git_vector_insert(&idx->pack->cache, pentry) < 0)
+ k = kh_put(oid, idx->pack->idx_cache, &pentry->sha1, &error);
+ if (!error) {
+ git__free(pentry);
goto on_error;
+ }
+
+ kh_value(idx->pack->idx_cache, k) = pentry;
git_oid_cpy(&entry->oid, &oid);
entry->crc = crc32(0L, Z_NULL, 0);
entry_size = (size_t)(idx->off - entry_start);
- packed = git_mwindow_open(mwf, &w, entry_start, entry_size, &left);
- if (packed == NULL)
+ if (crc_object(&entry->crc, &idx->pack->mwf, entry_start, entry_size) < 0)
goto on_error;
- entry->crc = htonl(crc32(entry->crc, packed, (uInt)entry_size));
- git_mwindow_close(&w);
-
/* Add the object to the list */
if (git_vector_insert(&idx->objects, entry) < 0)
goto on_error;
@@ -283,20 +377,27 @@ static int hash_and_save(git_indexer_stream *idx, git_rawobj *obj, git_off_t ent
on_error:
git__free(entry);
- git__free(pentry);
git__free(obj->data);
return -1;
}
-int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t size, git_indexer_stats *stats)
+static int do_progress_callback(git_indexer_stream *idx, git_transfer_progress *stats)
{
- int error;
+ if (!idx->progress_cb) return 0;
+ return idx->progress_cb(stats, idx->progress_payload);
+}
+
+int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t size, git_transfer_progress *stats)
+{
+ int error = -1;
struct git_pack_header hdr;
- size_t processed = stats->processed;
+ size_t processed;
git_mwindow_file *mwf = &idx->pack->mwf;
assert(idx && data && stats);
+ processed = stats->indexed_objects;
+
if (git_filebuf_write(&idx->pack_file, data, size) < 0)
return -1;
@@ -311,11 +412,11 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
mwf = &idx->pack->mwf;
if (git_mwindow_file_register(&idx->pack->mwf) < 0)
return -1;
-
- return 0;
}
if (!idx->parsed_header) {
+ unsigned int total_objects;
+
if ((unsigned)idx->pack->mwf.size < sizeof(hdr))
return 0;
@@ -328,19 +429,25 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
/* for now, limit to 2^32 objects */
assert(idx->nr_objects == (size_t)((unsigned int)idx->nr_objects));
+ if (idx->nr_objects == (size_t)((unsigned int)idx->nr_objects))
+ total_objects = (unsigned int)idx->nr_objects;
+ else
+ total_objects = UINT_MAX;
- if (git_vector_init(&idx->pack->cache, (unsigned int)idx->nr_objects, cache_cmp) < 0)
- return -1;
+ idx->pack->idx_cache = git_oidmap_alloc();
+ GITERR_CHECK_ALLOC(idx->pack->idx_cache);
idx->pack->has_cache = 1;
- if (git_vector_init(&idx->objects, (unsigned int)idx->nr_objects, objects_cmp) < 0)
+ if (git_vector_init(&idx->objects, total_objects, objects_cmp) < 0)
return -1;
- if (git_vector_init(&idx->deltas, (unsigned int)(idx->nr_objects / 2), NULL) < 0)
+ if (git_vector_init(&idx->deltas, total_objects / 2, NULL) < 0)
return -1;
- stats->total = (unsigned int)idx->nr_objects;
- stats->processed = 0;
+ stats->received_objects = 0;
+ processed = stats->indexed_objects = 0;
+ stats->total_objects = total_objects;
+ do_progress_callback(idx, stats);
}
/* Now that we have data in the pack, let's try to parse it */
@@ -348,42 +455,91 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz
/* As the file grows any windows we try to use will be out of date */
git_mwindow_free_all(mwf);
while (processed < idx->nr_objects) {
- git_rawobj obj;
+ git_packfile_stream *stream = &idx->stream;
git_off_t entry_start = idx->off;
+ size_t entry_size;
+ git_otype type;
+ git_mwindow *w = NULL;
if (idx->pack->mwf.size <= idx->off + 20)
return 0;
- error = git_packfile_unpack(&obj, idx->pack, &idx->off);
- if (error == GIT_EBUFS) {
- idx->off = entry_start;
- return 0;
- }
-
- if (error < 0) {
- idx->off = entry_start;
- error = store_delta(idx);
- if (error == GIT_EBUFS)
+ if (!idx->have_stream) {
+ error = git_packfile_unpack_header(&entry_size, &type, mwf, &w, &idx->off);
+ if (error == GIT_EBUFS) {
+ idx->off = entry_start;
return 0;
+ }
if (error < 0)
- return error;
+ return -1;
+
+ 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 = advance_delta_offset(idx, type);
+ if (error == GIT_EBUFS) {
+ idx->off = entry_start;
+ return 0;
+ }
+ if (error < 0)
+ return -1;
+
+ idx->have_delta = 1;
+ } else {
+ idx->have_delta = 0;
+ hash_header(&idx->hash_ctx, entry_size, type);
+ }
+
+ idx->have_stream = 1;
+ if (git_packfile_stream_open(stream, idx->pack, idx->off) < 0)
+ goto on_error;
- continue;
}
- if (hash_and_save(idx, &obj, entry_start) < 0)
+ if (idx->have_delta) {
+ error = read_object_stream(idx, stream);
+ } else {
+ error = hash_object_stream(idx, 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;
+
+ if (idx->have_delta) {
+ error = store_delta(idx);
+ } else {
+ error = store_object(idx);
+ }
+
+ if (error < 0)
goto on_error;
- git__free(obj.data);
+ if (!idx->have_delta) {
+ stats->indexed_objects = (unsigned int)++processed;
+ }
+ stats->received_objects++;
- stats->processed = (unsigned int)++processed;
+ if (do_progress_callback(idx, stats) != 0) {
+ error = GIT_EUSER;
+ goto on_error;
+ }
}
return 0;
on_error:
git_mwindow_free_all(mwf);
- return -1;
+ return error;
}
static int index_path_stream(git_buf *path, git_indexer_stream *idx, const char *suffix)
@@ -408,7 +564,7 @@ static int index_path_stream(git_buf *path, git_indexer_stream *idx, const char
return git_buf_oom(path) ? -1 : 0;
}
-static int resolve_deltas(git_indexer_stream *idx, git_indexer_stats *stats)
+static int resolve_deltas(git_indexer_stream *idx, git_transfer_progress *stats)
{
unsigned int i;
struct delta_info *delta;
@@ -424,13 +580,14 @@ static int resolve_deltas(git_indexer_stream *idx, git_indexer_stats *stats)
return -1;
git__free(obj.data);
- stats->processed++;
+ stats->indexed_objects++;
+ do_progress_callback(idx, stats);
}
return 0;
}
-int git_indexer_stream_finalize(git_indexer_stream *idx, git_indexer_stats *stats)
+int git_indexer_stream_finalize(git_indexer_stream *idx, git_transfer_progress *stats)
{
git_mwindow *w = NULL;
unsigned int i, long_offsets = 0, left;
@@ -439,11 +596,15 @@ int git_indexer_stream_finalize(git_indexer_stream *idx, git_indexer_stats *stat
struct entry *entry;
void *packfile_hash;
git_oid file_hash;
- SHA_CTX ctx;
+ git_hash_ctx ctx;
+ git_filebuf index_file = {0};
+
+ if (git_hash_ctx_init(&ctx) < 0)
+ return -1;
/* Test for this before resolve_deltas(), as it plays with idx->off */
if (idx->off < idx->pack->mwf.size - GIT_OID_RAWSZ) {
- giterr_set(GITERR_INDEXER, "Indexing error: junk at the end of the pack");
+ giterr_set(GITERR_INDEXER, "Indexing error: unexpected data at the end of the pack");
return -1;
}
@@ -451,7 +612,7 @@ int git_indexer_stream_finalize(git_indexer_stream *idx, git_indexer_stats *stat
if (resolve_deltas(idx, stats) < 0)
return -1;
- if (stats->processed != stats->total) {
+ if (stats->indexed_objects != stats->total_objects) {
giterr_set(GITERR_INDEXER, "Indexing error: early EOF");
return -1;
}
@@ -464,31 +625,30 @@ int git_indexer_stream_finalize(git_indexer_stream *idx, git_indexer_stats *stat
if (git_buf_oom(&filename))
return -1;
- if (git_filebuf_open(&idx->index_file, filename.ptr, GIT_FILEBUF_HASH_CONTENTS) < 0)
+ if (git_filebuf_open(&index_file, filename.ptr, GIT_FILEBUF_HASH_CONTENTS) < 0)
goto on_error;
/* Write out the header */
hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
hdr.idx_version = htonl(2);
- git_filebuf_write(&idx->index_file, &hdr, sizeof(hdr));
+ git_filebuf_write(&index_file, &hdr, sizeof(hdr));
/* Write out the fanout table */
for (i = 0; i < 256; ++i) {
uint32_t n = htonl(idx->fanout[i]);
- git_filebuf_write(&idx->index_file, &n, sizeof(n));
+ git_filebuf_write(&index_file, &n, sizeof(n));
}
/* Write out the object names (SHA-1 hashes) */
- SHA1_Init(&ctx);
git_vector_foreach(&idx->objects, i, entry) {
- git_filebuf_write(&idx->index_file, &entry->oid, sizeof(git_oid));
- SHA1_Update(&ctx, &entry->oid, GIT_OID_RAWSZ);
+ git_filebuf_write(&index_file, &entry->oid, sizeof(git_oid));
+ git_hash_update(&ctx, &entry->oid, GIT_OID_RAWSZ);
}
- SHA1_Final(idx->hash.id, &ctx);
+ git_hash_final(&idx->hash, &ctx);
/* Write out the CRC32 values */
git_vector_foreach(&idx->objects, i, entry) {
- git_filebuf_write(&idx->index_file, &entry->crc, sizeof(uint32_t));
+ git_filebuf_write(&index_file, &entry->crc, sizeof(uint32_t));
}
/* Write out the offsets */
@@ -500,7 +660,7 @@ int git_indexer_stream_finalize(git_indexer_stream *idx, git_indexer_stats *stat
else
n = htonl(entry->offset);
- git_filebuf_write(&idx->index_file, &n, sizeof(uint32_t));
+ git_filebuf_write(&index_file, &n, sizeof(uint32_t));
}
/* Write out the long offsets */
@@ -513,7 +673,7 @@ int git_indexer_stream_finalize(git_indexer_stream *idx, git_indexer_stats *stat
split[0] = htonl(entry->offset_long >> 32);
split[1] = htonl(entry->offset_long & 0xffffffff);
- git_filebuf_write(&idx->index_file, &split, sizeof(uint32_t) * 2);
+ git_filebuf_write(&index_file, &split, sizeof(uint32_t) * 2);
}
/* Write out the packfile trailer */
@@ -526,24 +686,26 @@ int git_indexer_stream_finalize(git_indexer_stream *idx, git_indexer_stats *stat
memcpy(&file_hash, packfile_hash, GIT_OID_RAWSZ);
git_mwindow_close(&w);
- git_filebuf_write(&idx->index_file, &file_hash, sizeof(git_oid));
+ git_filebuf_write(&index_file, &file_hash, sizeof(git_oid));
/* Write out the packfile trailer to the idx file as well */
- if (git_filebuf_hash(&file_hash, &idx->index_file) < 0)
+ if (git_filebuf_hash(&file_hash, &index_file) < 0)
goto on_error;
- git_filebuf_write(&idx->index_file, &file_hash, sizeof(git_oid));
+ git_filebuf_write(&index_file, &file_hash, sizeof(git_oid));
/* Figure out what the final name should be */
if (index_path_stream(&filename, idx, ".idx") < 0)
goto on_error;
/* Commit file */
- if (git_filebuf_commit_at(&idx->index_file, filename.ptr, GIT_PACK_FILE_MODE) < 0)
+ if (git_filebuf_commit_at(&index_file, filename.ptr, GIT_PACK_FILE_MODE) < 0)
goto on_error;
git_mwindow_free_all(&idx->pack->mwf);
+ /* We need to close the descriptor here so Windows doesn't choke on commit_at */
p_close(idx->pack->mwf.fd);
+ idx->pack->mwf.fd = -1;
if (index_path_stream(&filename, idx, ".pack") < 0)
goto on_error;
@@ -556,17 +718,17 @@ int git_indexer_stream_finalize(git_indexer_stream *idx, git_indexer_stats *stat
on_error:
git_mwindow_free_all(&idx->pack->mwf);
- p_close(idx->pack->mwf.fd);
- git_filebuf_cleanup(&idx->index_file);
+ git_filebuf_cleanup(&index_file);
git_buf_free(&filename);
+ git_hash_ctx_cleanup(&ctx);
return -1;
}
void git_indexer_stream_free(git_indexer_stream *idx)
{
+ khiter_t k;
unsigned int i;
struct entry *e;
- struct git_pack_entry *pe;
struct delta_info *delta;
if (idx == NULL)
@@ -575,325 +737,20 @@ void git_indexer_stream_free(git_indexer_stream *idx)
git_vector_foreach(&idx->objects, i, e)
git__free(e);
git_vector_free(&idx->objects);
- git_vector_foreach(&idx->pack->cache, i, pe)
- git__free(pe);
- git_vector_free(&idx->pack->cache);
- git_vector_foreach(&idx->deltas, i, delta)
- git__free(delta);
- git_vector_free(&idx->deltas);
- git__free(idx->pack);
- git__free(idx);
-}
-
-int git_indexer_new(git_indexer **out, const char *packname)
-{
- git_indexer *idx;
- struct git_pack_header hdr;
- int error;
-
- assert(out && packname);
-
- if (git_path_root(packname) < 0) {
- giterr_set(GITERR_INDEXER, "Path is not absolute");
- return -1;
- }
-
- idx = git__calloc(1, sizeof(git_indexer));
- GITERR_CHECK_ALLOC(idx);
-
- open_pack(&idx->pack, packname);
-
- if ((error = parse_header(&hdr, idx->pack)) < 0)
- goto cleanup;
-
- idx->nr_objects = ntohl(hdr.hdr_entries);
-
- /* for now, limit to 2^32 objects */
- assert(idx->nr_objects == (size_t)((unsigned int)idx->nr_objects));
-
- error = git_vector_init(&idx->pack->cache, (unsigned int)idx->nr_objects, cache_cmp);
- if (error < 0)
- goto cleanup;
-
- idx->pack->has_cache = 1;
- error = git_vector_init(&idx->objects, (unsigned int)idx->nr_objects, objects_cmp);
- if (error < 0)
- goto cleanup;
-
- *out = idx;
-
- return 0;
-cleanup:
- git_indexer_free(idx);
-
- return -1;
-}
-
-static int index_path(git_buf *path, git_indexer *idx)
-{
- const char prefix[] = "pack-", suffix[] = ".idx";
- size_t slash = (size_t)path->size;
-
- /* search backwards for '/' */
- while (slash > 0 && path->ptr[slash - 1] != '/')
- slash--;
-
- if (git_buf_grow(path, slash + 1 + strlen(prefix) +
- GIT_OID_HEXSZ + strlen(suffix) + 1) < 0)
- return -1;
-
- git_buf_truncate(path, slash);
- git_buf_puts(path, prefix);
- git_oid_fmt(path->ptr + git_buf_len(path), &idx->hash);
- path->size += GIT_OID_HEXSZ;
- git_buf_puts(path, suffix);
-
- return git_buf_oom(path) ? -1 : 0;
-}
-
-int git_indexer_write(git_indexer *idx)
-{
- git_mwindow *w = NULL;
- int error;
- unsigned int i, long_offsets = 0, left;
- struct git_pack_idx_header hdr;
- git_buf filename = GIT_BUF_INIT;
- struct entry *entry;
- void *packfile_hash;
- git_oid file_hash;
- SHA_CTX ctx;
-
- git_vector_sort(&idx->objects);
-
- git_buf_sets(&filename, idx->pack->pack_name);
- git_buf_truncate(&filename, filename.size - strlen("pack"));
- git_buf_puts(&filename, "idx");
- if (git_buf_oom(&filename))
- return -1;
-
- error = git_filebuf_open(&idx->file, filename.ptr, GIT_FILEBUF_HASH_CONTENTS);
- if (error < 0)
- goto cleanup;
-
- /* Write out the header */
- hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
- hdr.idx_version = htonl(2);
- error = git_filebuf_write(&idx->file, &hdr, sizeof(hdr));
- if (error < 0)
- goto cleanup;
-
- /* Write out the fanout table */
- for (i = 0; i < 256; ++i) {
- uint32_t n = htonl(idx->fanout[i]);
- error = git_filebuf_write(&idx->file, &n, sizeof(n));
- if (error < 0)
- goto cleanup;
- }
-
- /* Write out the object names (SHA-1 hashes) */
- SHA1_Init(&ctx);
- git_vector_foreach(&idx->objects, i, entry) {
- error = git_filebuf_write(&idx->file, &entry->oid, sizeof(git_oid));
- SHA1_Update(&ctx, &entry->oid, GIT_OID_RAWSZ);
- if (error < 0)
- goto cleanup;
- }
- SHA1_Final(idx->hash.id, &ctx);
-
- /* Write out the CRC32 values */
- git_vector_foreach(&idx->objects, i, entry) {
- error = git_filebuf_write(&idx->file, &entry->crc, sizeof(uint32_t));
- if (error < 0)
- goto cleanup;
- }
-
- /* Write out the offsets */
- git_vector_foreach(&idx->objects, i, entry) {
- uint32_t n;
-
- if (entry->offset == UINT32_MAX)
- n = htonl(0x80000000 | long_offsets++);
- else
- n = htonl(entry->offset);
-
- error = git_filebuf_write(&idx->file, &n, sizeof(uint32_t));
- if (error < 0)
- goto cleanup;
- }
-
- /* Write out the long offsets */
- git_vector_foreach(&idx->objects, i, entry) {
- uint32_t split[2];
-
- if (entry->offset != UINT32_MAX)
- continue;
-
- split[0] = htonl(entry->offset_long >> 32);
- split[1] = htonl(entry->offset_long & 0xffffffff);
-
- error = git_filebuf_write(&idx->file, &split, sizeof(uint32_t) * 2);
- if (error < 0)
- goto cleanup;
- }
-
- /* Write out the packfile trailer */
-
- packfile_hash = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - GIT_OID_RAWSZ, GIT_OID_RAWSZ, &left);
- git_mwindow_close(&w);
- if (packfile_hash == NULL) {
- error = -1;
- goto cleanup;
- }
-
- memcpy(&file_hash, packfile_hash, GIT_OID_RAWSZ);
-
- git_mwindow_close(&w);
-
- error = git_filebuf_write(&idx->file, &file_hash, sizeof(git_oid));
- if (error < 0)
- goto cleanup;
-
- /* Write out the index sha */
- error = git_filebuf_hash(&file_hash, &idx->file);
- if (error < 0)
- goto cleanup;
-
- error = git_filebuf_write(&idx->file, &file_hash, sizeof(git_oid));
- if (error < 0)
- goto cleanup;
-
- /* Figure out what the final name should be */
- error = index_path(&filename, idx);
- if (error < 0)
- goto cleanup;
-
- /* Commit file */
- error = git_filebuf_commit_at(&idx->file, filename.ptr, GIT_PACK_FILE_MODE);
-
-cleanup:
- git_mwindow_free_all(&idx->pack->mwf);
- if (error < 0)
- git_filebuf_cleanup(&idx->file);
- git_buf_free(&filename);
-
- return error;
-}
-
-int git_indexer_run(git_indexer *idx, git_indexer_stats *stats)
-{
- git_mwindow_file *mwf;
- git_off_t off = sizeof(struct git_pack_header);
- int error;
- struct entry *entry;
- unsigned int left, processed;
-
- assert(idx && stats);
-
- mwf = &idx->pack->mwf;
- error = git_mwindow_file_register(mwf);
- if (error < 0)
- return error;
-
- stats->total = (unsigned int)idx->nr_objects;
- stats->processed = processed = 0;
-
- while (processed < idx->nr_objects) {
- git_rawobj obj;
- git_oid oid;
- struct git_pack_entry *pentry;
- git_mwindow *w = NULL;
- int i;
- git_off_t entry_start = off;
- void *packed;
- size_t entry_size;
- char fmt[GIT_OID_HEXSZ] = {0};
-
- entry = git__calloc(1, sizeof(*entry));
- GITERR_CHECK_ALLOC(entry);
-
- if (off > UINT31_MAX) {
- entry->offset = UINT32_MAX;
- entry->offset_long = off;
- } else {
- entry->offset = (uint32_t)off;
- }
-
- error = git_packfile_unpack(&obj, idx->pack, &off);
- if (error < 0)
- goto cleanup;
-
- /* FIXME: Parse the object instead of hashing it */
- error = git_odb__hashobj(&oid, &obj);
- if (error < 0) {
- giterr_set(GITERR_INDEXER, "Failed to hash object");
- goto cleanup;
+ if (idx->pack) {
+ for (k = kh_begin(idx->pack->idx_cache); k != kh_end(idx->pack->idx_cache); k++) {
+ if (kh_exist(idx->pack->idx_cache, k))
+ git__free(kh_value(idx->pack->idx_cache, k));
}
- pentry = git__malloc(sizeof(struct git_pack_entry));
- if (pentry == NULL) {
- error = -1;
- goto cleanup;
- }
-
- git_oid_cpy(&pentry->sha1, &oid);
- pentry->offset = entry_start;
- git_oid_fmt(fmt, &oid);
- printf("adding %s to cache\n", fmt);
- error = git_vector_insert(&idx->pack->cache, pentry);
- if (error < 0)
- goto cleanup;
-
- git_oid_cpy(&entry->oid, &oid);
- entry->crc = crc32(0L, Z_NULL, 0);
-
- entry_size = (size_t)(off - entry_start);
- packed = git_mwindow_open(mwf, &w, entry_start, entry_size, &left);
- if (packed == NULL) {
- error = -1;
- goto cleanup;
- }
- entry->crc = htonl(crc32(entry->crc, packed, (uInt)entry_size));
- git_mwindow_close(&w);
-
- /* Add the object to the list */
- error = git_vector_insert(&idx->objects, entry);
- if (error < 0)
- goto cleanup;
-
- for (i = oid.id[0]; i < 256; ++i) {
- idx->fanout[i]++;
- }
-
- git__free(obj.data);
-
- stats->processed = ++processed;
+ git_oidmap_free(idx->pack->idx_cache);
}
-cleanup:
- git_mwindow_free_all(mwf);
-
- return error;
-
-}
-
-void git_indexer_free(git_indexer *idx)
-{
- unsigned int i;
- struct entry *e;
- struct git_pack_entry *pe;
-
- if (idx == NULL)
- return;
-
- p_close(idx->pack->mwf.fd);
- git_vector_foreach(&idx->objects, i, e)
- git__free(e);
- git_vector_free(&idx->objects);
- git_vector_foreach(&idx->pack->cache, i, pe)
- git__free(pe);
- git_vector_free(&idx->pack->cache);
- git__free(idx->pack);
+ git_vector_foreach(&idx->deltas, i, delta)
+ git__free(delta);
+ git_vector_free(&idx->deltas);
+ git_packfile_free(idx->pack);
+ git_filebuf_cleanup(&idx->pack_file);
git__free(idx);
}
-