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
path: root/src
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2011-03-18 20:38:49 +0300
committerVicent Marti <tanoku@gmail.com>2011-03-20 22:45:11 +0300
commit72a3fe42fb7208712bbe8f0981f4c6274c05e9c3 (patch)
treeb073a1c36b3215d94b1e78a0f294d7aa30d949df /src
parentbb3de0c472b2d5d6b8091c190bee3db79c4b5e27 (diff)
I broke your bindings
Hey. Apologies in advance -- I broke your bindings. This is a major commit that includes a long-overdue redesign of the whole object-database structure. This is expected to be the last major external API redesign of the library until the first non-alpha release. Please get your bindings up to date with these changes. They will be included in the next minor release. Sorry again! Major features include: - Real caching and refcounting on parsed objects - Real caching and refcounting on objects read from the ODB - Streaming writes & reads from the ODB - Single-method writes for all object types - The external API is now partially thread-safe The speed increases are significant in all aspects, specially when reading an object several times from the ODB (revwalking) and when writing big objects to the ODB. Here's a full changelog for the external API: blob.h ------ - Remove `git_blob_new` - Remove `git_blob_set_rawcontent` - Remove `git_blob_set_rawcontent_fromfile` - Rename `git_blob_writefile` -> `git_blob_create_fromfile` - Change `git_blob_create_fromfile`: The `path` argument is now relative to the repository's working dir - Add `git_blob_create_frombuffer` commit.h -------- - Remove `git_commit_new` - Remove `git_commit_add_parent` - Remove `git_commit_set_message` - Remove `git_commit_set_committer` - Remove `git_commit_set_author` - Remove `git_commit_set_tree` - Add `git_commit_create` - Add `git_commit_create_v` - Add `git_commit_create_o` - Add `git_commit_create_ov` tag.h ----- - Remove `git_tag_new` - Remove `git_tag_set_target` - Remove `git_tag_set_name` - Remove `git_tag_set_tagger` - Remove `git_tag_set_message` - Add `git_tag_create` - Add `git_tag_create_o` tree.h ------ - Change `git_tree_entry_2object`: New signature is `(git_object **object_out, git_repository *repo, git_tree_entry *entry)` - Remove `git_tree_new` - Remove `git_tree_add_entry` - Remove `git_tree_remove_entry_byindex` - Remove `git_tree_remove_entry_byname` - Remove `git_tree_clearentries` - Remove `git_tree_entry_set_id` - Remove `git_tree_entry_set_name` - Remove `git_tree_entry_set_attributes` object.h ------------ - Remove `git_object_new - Remove `git_object_write` - Change `git_object_close`: This method is now *mandatory*. Not closing an object causes a memory leak. odb.h ----- - Remove type `git_rawobj` - Remove `git_rawobj_close` - Rename `git_rawobj_hash` -> `git_odb_hash` - Change `git_odb_hash`: New signature is `(git_oid *id, const void *data, size_t len, git_otype type)` - Add type `git_odb_object` - Add `git_odb_object_close` - Change `git_odb_read`: New signature is `(git_odb_object **out, git_odb *db, const git_oid *id)` - Change `git_odb_read_header`: New signature is `(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id)` - Remove `git_odb_write` - Add `git_odb_open_wstream` - Add `git_odb_open_rstream` odb_backend.h ------------- - Change type `git_odb_backend`: New internal signatures are as follows int (* read)(void **, size_t *, git_otype *, struct git_odb_backend *, const git_oid *) int (* read_header)(size_t *, git_otype *, struct git_odb_backend *, const git_oid *) int (* writestream)(struct git_odb_stream **, struct git_odb_backend *, size_t, git_otype) int (* readstream)( struct git_odb_stream **, struct git_odb_backend *, const git_oid *) - Add type `git_odb_stream` - Add enum `git_odb_streammode` Signed-off-by: Vicent Marti <tanoku@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/backends/sqlite.c9
-rw-r--r--src/blob.c113
-rw-r--r--src/blob.h6
-rw-r--r--src/cache.c46
-rw-r--r--src/cache.h21
-rw-r--r--src/commit.c268
-rw-r--r--src/commit.h4
-rw-r--r--src/delta-apply.h2
-rw-r--r--src/errors.c3
-rw-r--r--src/filebuf.c188
-rw-r--r--src/filebuf.h22
-rw-r--r--src/fileops.c90
-rw-r--r--src/fileops.h2
-rw-r--r--src/index.c2
-rw-r--r--src/object.c276
-rw-r--r--src/odb.c133
-rw-r--r--src/odb.h18
-rw-r--r--src/odb_loose.c264
-rw-r--r--src/odb_pack.c19
-rw-r--r--src/oid.c14
-rw-r--r--src/repository.c72
-rw-r--r--src/repository.h28
-rw-r--r--src/revwalk.c13
-rw-r--r--src/signature.c23
-rw-r--r--src/signature.h2
-rw-r--r--src/tag.c144
-rw-r--r--src/tag.h4
-rw-r--r--src/thread-utils.h10
-rw-r--r--src/tree.c191
-rw-r--r--src/tree.h7
-rw-r--r--src/util.h2
31 files changed, 918 insertions, 1078 deletions
diff --git a/src/backends/sqlite.c b/src/backends/sqlite.c
index b4c941a59..72d7b4d8e 100644
--- a/src/backends/sqlite.c
+++ b/src/backends/sqlite.c
@@ -272,4 +272,13 @@ cleanup:
return GIT_ERROR;
}
+#else
+
+int git_odb_backend_sqlite(git_odb_backend **GIT_UNUSED(backend_out), const char *GIT_UNUSED(sqlite_db))
+{
+ GIT_UNUSED_ARG(backend_out);
+ GIT_UNUSED_ARG(sqlite_db);
+ return GIT_ENOTIMPLEMENTED;
+}
+
#endif /* HAVE_SQLITE3 */
diff --git a/src/blob.c b/src/blob.c
index 1e03b6b67..bc0a08a8a 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -33,104 +33,89 @@
const void *git_blob_rawcontent(git_blob *blob)
{
assert(blob);
-
- if (blob->content.data != NULL)
- return blob->content.data;
-
- if (blob->object.in_memory)
- return NULL;
-
- if (!blob->object.source.open && git_object__source_open((git_object *)blob) < GIT_SUCCESS)
- return NULL;
-
- return blob->object.source.raw.data;
+ return blob->odb_object->raw.data;
}
int git_blob_rawsize(git_blob *blob)
{
assert(blob);
-
- if (blob->content.data != NULL)
- return blob->content.len;
-
- return blob->object.source.raw.len;
+ return blob->odb_object->raw.len;
}
void git_blob__free(git_blob *blob)
{
- gitfo_free_buf(&blob->content);
+ git_odb_object_close(blob->odb_object);
free(blob);
}
-int git_blob__parse(git_blob *blob)
+int git_blob__parse(git_blob *blob, git_odb_object *odb_obj)
{
assert(blob);
+ git_cached_obj_incref((git_cached_obj *)odb_obj);
+ blob->odb_object = odb_obj;
return GIT_SUCCESS;
}
-int git_blob__writeback(git_blob *blob, git_odb_source *src)
-{
- assert(blob->object.modified);
-
- if (blob->content.data == NULL)
- return GIT_EMISSINGOBJDATA;
-
- return git__source_write(src, blob->content.data, blob->content.len);
-}
-
-int git_blob_set_rawcontent(git_blob *blob, const void *buffer, size_t len)
+int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len)
{
- assert(blob && buffer);
-
- blob->object.modified = 1;
-
- git_object__source_close((git_object *)blob);
-
- if (blob->content.data != NULL)
- gitfo_free_buf(&blob->content);
+ int error;
+ git_odb_stream *stream;
- blob->content.data = git__malloc(len);
- blob->content.len = len;
+ if ((error = git_odb_open_wstream(&stream, repo->db, len, GIT_OBJ_BLOB)) < GIT_SUCCESS)
+ return error;
- if (blob->content.data == NULL)
- return GIT_ENOMEM;
+ stream->write(stream, buffer, len);
- memcpy(blob->content.data, buffer, len);
+ error = stream->finalize_write(oid, stream);
+ stream->free(stream);
- return GIT_SUCCESS;
+ return error;
}
-int git_blob_set_rawcontent_fromfile(git_blob *blob, const char *filename)
+int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path)
{
- assert(blob && filename);
- blob->object.modified = 1;
+ int error, fd;
+ char full_path[GIT_PATH_MAX];
+ char buffer[2048];
+ git_off_t size;
+ git_odb_stream *stream;
- if (blob->content.data != NULL)
- gitfo_free_buf(&blob->content);
-
- return gitfo_read_file(&blob->content, filename);
-}
+ if (repo->path_workdir == NULL)
+ return GIT_ENOTFOUND;
-int git_blob_writefile(git_oid *written_id, git_repository *repo, const char *path)
-{
- int error;
- git_blob *blob;
+ git__joinpath(full_path, repo->path_workdir, path);
- if (gitfo_exists(path) < 0)
+ if ((fd = gitfo_open(full_path, O_RDONLY)) < 0)
return GIT_ENOTFOUND;
- if ((error = git_blob_new(&blob, repo)) < GIT_SUCCESS)
- return error;
+ if ((size = gitfo_size(fd)) < 0 || !git__is_sizet(size)) {
+ gitfo_close(fd);
+ return GIT_EOSERR;
+ }
- if ((error = git_blob_set_rawcontent_fromfile(blob, path)) < GIT_SUCCESS)
+ if ((error = git_odb_open_wstream(&stream, repo->db, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS) {
+ gitfo_close(fd);
return error;
+ }
- if ((error = git_object_write((git_object *)blob)) < GIT_SUCCESS)
- return error;
+ while (size > 0) {
+ ssize_t read_len;
- git_oid_cpy(written_id, git_object_id((git_object *)blob));
+ read_len = read(fd, buffer, sizeof(buffer));
- git_object_close((git_object*)blob);
- return GIT_SUCCESS;
+ if (read_len < 0) {
+ gitfo_close(fd);
+ stream->free(stream);
+ return GIT_EOSERR;
+ }
+
+ stream->write(stream, buffer, read_len);
+ size -= read_len;
+ }
+
+ error = stream->finalize_write(oid, stream);
+ stream->free(stream);
+
+ return error;
}
diff --git a/src/blob.h b/src/blob.h
index febc296fe..4300d7e54 100644
--- a/src/blob.h
+++ b/src/blob.h
@@ -3,15 +3,15 @@
#include "git2/blob.h"
#include "repository.h"
+#include "odb.h"
#include "fileops.h"
struct git_blob {
git_object object;
- gitfo_buf content;
+ git_odb_object *odb_object;
};
void git_blob__free(git_blob *blob);
-int git_blob__parse(git_blob *blob);
-int git_blob__writeback(git_blob *blob, git_odb_source *src);
+int git_blob__parse(git_blob *blob, git_odb_object *obj);
#endif
diff --git a/src/cache.c b/src/cache.c
index 5a9b8415c..fdf5c1b80 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -32,23 +32,6 @@
#define GIT_CACHE_OPENADR 3
-GIT_INLINE(int) cached_obj_compare(git_cached_obj *obj, const git_oid *oid)
-{
- return git_oid_cmp(&obj->oid, oid);
-}
-
-GIT_INLINE(void) cached_obj_incref(git_cached_obj *obj)
-{
- git_atomic_inc(&obj->refcount);
-}
-
-GIT_INLINE(void) cached_obj_decref(git_cached_obj *obj, git_cached_obj_freeptr free_obj)
-{
- if (git_atomic_dec(&obj->refcount) == 0)
- free_obj(obj);
-}
-
-
void git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr)
{
size_t i;
@@ -82,7 +65,9 @@ void git_cache_free(git_cache *cache)
size_t i;
for (i = 0; i < (cache->size_mask + 1); ++i) {
- cached_obj_decref(cache->nodes[i].ptr, cache->free_obj);
+ if (cache->nodes[i].ptr)
+ git_cached_obj_decref(cache->nodes[i].ptr, cache->free_obj);
+
git_mutex_free(&cache->nodes[i].lock);
}
@@ -103,8 +88,8 @@ void *git_cache_get(git_cache *cache, const git_oid *oid)
git_mutex_lock(&node->lock);
{
- if (cached_obj_compare(node->ptr, oid) == 0) {
- cached_obj_incref(node->ptr);
+ if (node->ptr && git_cached_obj_compare(node->ptr, oid) == 0) {
+ git_cached_obj_incref(node->ptr);
node->lru = ++cache->lru_count;
found = 1;
}
@@ -121,14 +106,14 @@ void *git_cache_try_store(git_cache *cache, void *entry)
cache_node *nodes[GIT_CACHE_OPENADR], *lru_node;
const uint32_t *hash;
const git_oid *oid;
- size_t i, stored = 0;
+ size_t i;
oid = &((git_cached_obj*)entry)->oid;
hash = (const uint32_t *)oid->id;
/* increase the refcount on this object, because
* the cache now owns it */
- cached_obj_incref(entry);
+ git_cached_obj_incref(entry);
for (i = 0; i < GIT_CACHE_OPENADR; ++i) {
size_t pos = hash[i] & cache->size_mask;
@@ -139,34 +124,35 @@ void *git_cache_try_store(git_cache *cache, void *entry)
lru_node = nodes[0];
- for (i = 0; !stored && entry && i < GIT_CACHE_OPENADR; ++i) {
+ for (i = 0; i < GIT_CACHE_OPENADR; ++i) {
if (nodes[i]->ptr == NULL) {
nodes[i]->ptr = entry;
nodes[i]->lru = ++cache->lru_count;
- stored = 1;
- } else if (cached_obj_compare(nodes[i]->ptr, oid) == 0) {
- cached_obj_decref(entry, cache->free_obj);
+ break;
+ } else if (git_cached_obj_compare(nodes[i]->ptr, oid) == 0) {
+ git_cached_obj_decref(entry, cache->free_obj);
entry = nodes[i]->ptr;
- stored = 1;
+ nodes[i]->lru = ++cache->lru_count;
+ break;
}
if (nodes[i]->lru < lru_node->lru)
lru_node = nodes[i];
}
- if (!stored) {
+ if (i == GIT_CACHE_OPENADR) {
void *old_entry = lru_node->ptr;
assert(old_entry);
- cached_obj_decref(old_entry, cache->free_obj);
+ git_cached_obj_decref(old_entry, cache->free_obj);
lru_node->ptr = entry;
lru_node->lru = ++cache->lru_count;
}
/* increase the refcount again, because we are
* returning it to the user */
- cached_obj_incref(entry);
+ git_cached_obj_incref(entry);
for (i = 0; i < GIT_CACHE_OPENADR; ++i)
git_mutex_unlock(&nodes[i]->lock);
diff --git a/src/cache.h b/src/cache.h
index 9f525e68c..975aaff7e 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -7,6 +7,8 @@
#include "thread-utils.h"
+#define GIT_DEFAULT_CACHE_SIZE 128
+
typedef void (*git_cached_obj_freeptr)(void *);
typedef struct {
@@ -35,4 +37,23 @@ void git_cache_free(git_cache *cache);
void *git_cache_try_store(git_cache *cache, void *entry);
void *git_cache_get(git_cache *cache, const git_oid *oid);
+
+GIT_INLINE(int) git_cached_obj_compare(git_cached_obj *obj, const git_oid *oid)
+{
+ return git_oid_cmp(&obj->oid, oid);
+}
+
+GIT_INLINE(void) git_cached_obj_incref(git_cached_obj *obj)
+{
+ git_atomic_inc(&obj->refcount);
+}
+
+GIT_INLINE(void) git_cached_obj_decref(git_cached_obj *obj, git_cached_obj_freeptr free_obj)
+{
+ if (git_atomic_dec(&obj->refcount) == 0)
+ free_obj(obj);
+}
+
+
+
#endif
diff --git a/src/commit.c b/src/commit.c
index 8da170cad..2670c2e0a 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -29,9 +29,12 @@
#include "git2/signature.h"
#include "common.h"
+#include "odb.h"
#include "commit.h"
#include "signature.h"
+#include <stdarg.h>
+
#define COMMIT_BASIC_PARSE 0x0
#define COMMIT_FULL_PARSE 0x1
@@ -71,35 +74,165 @@ const git_oid *git_commit_id(git_commit *c)
return git_object_id((git_object *)c);
}
-int git_commit__writeback(git_commit *commit, git_odb_source *src)
+
+int git_commit_create_v(
+ git_oid *oid,
+ git_repository *repo,
+ const char *update_ref,
+ const git_signature *author,
+ const git_signature *committer,
+ const char *message,
+ const git_oid *tree_oid,
+ int parent_count,
+ ...)
{
- unsigned int i;
+ va_list ap;
+ int i, error;
+ const git_oid **oids;
- git__write_oid(src, "tree", &commit->tree_oid);
+ oids = git__malloc(parent_count * sizeof(git_oid *));
- for (i = 0; i < commit->parent_oids.length; ++i) {
- git_oid *parent_oid;
+ va_start(ap, parent_count);
+ for (i = 0; i < parent_count; ++i)
+ oids[i] = va_arg(ap, const git_oid *);
+ va_end(ap);
- parent_oid = git_vector_get(&commit->parent_oids, i);
- git__write_oid(src, "parent", parent_oid);
- }
+ error = git_commit_create(
+ oid, repo, update_ref, author, committer, message,
+ tree_oid, parent_count, oids);
+
+ free(oids);
+ return error;
+}
+
+int git_commit_create_ov(
+ git_oid *oid,
+ git_repository *repo,
+ const char *update_ref,
+ const git_signature *author,
+ const git_signature *committer,
+ const char *message,
+ const git_tree *tree,
+ int parent_count,
+ ...)
+{
+ va_list ap;
+ int i, error;
+ const git_oid **oids;
+
+ oids = git__malloc(parent_count * sizeof(git_oid *));
+
+ va_start(ap, parent_count);
+ for (i = 0; i < parent_count; ++i)
+ oids[i] = git_object_id(va_arg(ap, const git_object *));
+ va_end(ap);
+
+ error = git_commit_create(
+ oid, repo, update_ref, author, committer, message,
+ git_object_id((git_object *)tree),
+ parent_count, oids);
+
+ free(oids);
+ return error;
+}
+
+int git_commit_create_o(
+ git_oid *oid,
+ git_repository *repo,
+ const char *update_ref,
+ const git_signature *author,
+ const git_signature *committer,
+ const char *message,
+ const git_tree *tree,
+ int parent_count,
+ const git_commit *parents[])
+{
+ int i, error;
+ const git_oid **oids;
+
+ oids = git__malloc(parent_count * sizeof(git_oid *));
+
+ for (i = 0; i < parent_count; ++i)
+ oids[i] = git_object_id((git_object *)parents[i]);
+
+ error = git_commit_create(
+ oid, repo, update_ref, author, committer, message,
+ git_object_id((git_object *)tree),
+ parent_count, oids);
+
+ free(oids);
+ return error;
+}
- if (commit->author == NULL)
- return GIT_EMISSINGOBJDATA;
+int git_commit_create(
+ git_oid *oid,
+ git_repository *repo,
+ const char *update_ref,
+ const git_signature *author,
+ const git_signature *committer,
+ const char *message,
+ const git_oid *tree_oid,
+ int parent_count,
+ const git_oid *parents[])
+{
+ size_t final_size = 0;
+ int message_length, author_length, committer_length;
+
+ char *author_str, *committer_str;
+
+ int error, i;
+ git_odb_stream *stream;
+
+ message_length = strlen(message);
+ author_length = git_signature__write(&author_str, "author", author);
+ committer_length = git_signature__write(&committer_str, "committer", committer);
+
+ if (author_length < 0 || committer_length < 0)
+ return GIT_ENOMEM;
+
+ final_size += GIT_OID_LINE_LENGTH("tree");
+ final_size += GIT_OID_LINE_LENGTH("parent") * parent_count;
+ final_size += author_length;
+ final_size += committer_length;
+ final_size += 1 + message_length;
+
+ if ((error = git_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_COMMIT)) < GIT_SUCCESS)
+ return error;
+
+ git__write_oid(stream, "tree", tree_oid);
- git_signature__write(src, "author", commit->author);
+ for (i = 0; i < parent_count; ++i)
+ git__write_oid(stream, "parent", parents[i]);
- if (commit->committer == NULL)
- return GIT_EMISSINGOBJDATA;
+ stream->write(stream, author_str, author_length);
+ free(author_str);
- git_signature__write(src, "committer", commit->committer);
+ stream->write(stream, committer_str, committer_length);
+ free(committer_str);
- if (commit->message != NULL) {
- git__source_write(src, "\n", 1);
- git__source_write(src, commit->message, strlen(commit->message));
+
+ stream->write(stream, "\n", 1);
+ stream->write(stream, message, message_length);
+
+ error = stream->finalize_write(oid, stream);
+ stream->free(stream);
+
+ if (error == GIT_SUCCESS && update_ref != NULL) {
+ git_reference *head;
+
+ error = git_reference_lookup(&head, repo, update_ref);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ if (git_reference_type(head) == GIT_REF_SYMBOLIC) {
+ if ((error = git_reference_resolve(&head, head)) < GIT_SUCCESS)
+ return error;
+ }
+
+ error = git_reference_set_oid(head, oid);
}
- return GIT_SUCCESS;
+ return error;
}
int commit_parse_buffer(git_commit *commit, void *data, size_t len)
@@ -110,12 +243,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len)
git_oid parent_oid;
int error;
- /* first parse; the vector hasn't been initialized yet */
- if (commit->parent_oids.contents == NULL) {
- git_vector_init(&commit->parent_oids, 4, NULL);
- }
-
- clear_parents(commit);
+ git_vector_init(&commit->parent_oids, 4, NULL);
if ((error = git__parse_oid(&commit->tree_oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS)
return error;
@@ -134,17 +262,11 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len)
return GIT_ENOMEM;
}
- if (commit->author)
- git_signature_free(commit->author);
-
commit->author = git__malloc(sizeof(git_signature));
if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS)
return error;
/* Always parse the committer; we need the commit time */
- if (commit->committer)
- git_signature_free(commit->committer);
-
commit->committer = git__malloc(sizeof(git_signature));
if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ")) < GIT_SUCCESS)
return error;
@@ -176,11 +298,10 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len)
return GIT_SUCCESS;
}
-int git_commit__parse(git_commit *commit)
+int git_commit__parse(git_commit *commit, git_odb_object *obj)
{
- assert(commit && commit->object.source.open);
- return commit_parse_buffer(commit,
- commit->object.source.raw.data, commit->object.source.raw.len);
+ assert(commit);
+ return commit_parse_buffer(commit, obj->raw.data, obj->raw.len);
}
#define GIT_COMMIT_GETTER(_rvalue, _name, _return) \
@@ -218,82 +339,3 @@ int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n)
}
-
-int git_commit_set_tree(git_commit *commit, git_tree *tree)
-{
- const git_oid *oid;
-
- assert(commit && tree);
-
- if ((oid = git_object_id((git_object *)tree)) == NULL)
- return GIT_EMISSINGOBJDATA;
-
- commit->object.modified = 1;
- git_oid_cpy(&commit->tree_oid, oid);
- return GIT_SUCCESS;
-}
-
-int git_commit_add_parent(git_commit *commit, git_commit *new_parent)
-{
- const git_oid *parent_oid;
- git_oid *new_oid;
- assert(commit && new_parent);
-
- if ((parent_oid = git_object_id((git_object *)new_parent)) == NULL)
- return GIT_EMISSINGOBJDATA;
-
- new_oid = git__malloc(sizeof(git_oid));
- if (new_oid == NULL)
- return GIT_ENOMEM;
-
- commit->object.modified = 1;
- git_oid_cpy(new_oid, parent_oid);
- return git_vector_insert(&commit->parent_oids, new_oid);
-}
-
-void git_commit_set_author(git_commit *commit, const git_signature *author_sig)
-{
- assert(commit && author_sig);
- commit->object.modified = 1;
-
- git_signature_free(commit->author);
- commit->author = git_signature_dup(author_sig);
-}
-
-void git_commit_set_committer(git_commit *commit, const git_signature *committer_sig)
-{
- assert(commit && committer_sig);
- commit->object.modified = 1;
-
- git_signature_free(commit->committer);
- commit->committer = git_signature_dup(committer_sig);
-}
-
-void git_commit_set_message(git_commit *commit, const char *message)
-{
- const char *line_end;
- size_t message_len;
-
- commit->object.modified = 1;
-
- if (commit->message)
- free(commit->message);
-
- if (commit->message_short)
- free(commit->message_short);
-
- commit->message = git__strdup(message);
-
- /* Short message */
- if((line_end = strchr(message, '\n')) == NULL) {
- commit->message_short = git__strdup(message);
- return;
- }
-
- message_len = line_end - message;
-
- commit->message_short = git__malloc(message_len + 1);
- memcpy(commit->message_short, message, message_len);
- commit->message_short[message_len] = 0;
-}
-
diff --git a/src/commit.h b/src/commit.h
index aaf349ca6..3d15c5044 100644
--- a/src/commit.h
+++ b/src/commit.h
@@ -22,8 +22,6 @@ struct git_commit {
};
void git_commit__free(git_commit *c);
-int git_commit__parse(git_commit *commit);
-
-int git_commit__writeback(git_commit *commit, git_odb_source *src);
+int git_commit__parse(git_commit *commit, git_odb_object *obj);
#endif
diff --git a/src/delta-apply.h b/src/delta-apply.h
index 642442de0..36c5cc60d 100644
--- a/src/delta-apply.h
+++ b/src/delta-apply.h
@@ -1,6 +1,8 @@
#ifndef INCLUDE_delta_apply_h__
#define INCLUDE_delta_apply_h__
+#include "odb.h"
+
/**
* Apply a git binary delta to recover the original content.
*
diff --git a/src/errors.c b/src/errors.c
index 880163f78..f6b964837 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -27,7 +27,8 @@ static struct {
{GIT_EPACKEDREFSCORRUPTED, "The pack-refs file is either corrupted of its format is not currently supported"},
{GIT_EINVALIDPATH, "The path is invalid" },
{GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"},
- {GIT_EINVALIDREFSTATE, "The state of the reference is not valid"}
+ {GIT_EINVALIDREFSTATE, "The state of the reference is not valid"},
+ {GIT_ENOTIMPLEMENTED, "This feature has not been implemented yet"}
};
const char *git_strerror(int num)
diff --git a/src/filebuf.c b/src/filebuf.c
index 4fc4f1486..607ad618d 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -77,43 +77,81 @@ void git_filebuf_cleanup(git_filebuf *file)
if (file->fd >= 0)
gitfo_close(file->fd);
- if (gitfo_exists(file->path_lock) == GIT_SUCCESS)
+ if (file->path_lock && gitfo_exists(file->path_lock) == GIT_SUCCESS)
gitfo_unlink(file->path_lock);
if (file->digest)
git_hash_free_ctx(file->digest);
free(file->buffer);
+ free(file->z_buf);
-#ifdef GIT_FILEBUF_THREADS
- free(file->buffer_back);
-#endif
+ deflateEnd(&file->zs);
free(file->path_original);
free(file->path_lock);
}
-static int flush_buffer(git_filebuf *file)
+GIT_INLINE(int) flush_buffer(git_filebuf *file)
{
- int result = GIT_SUCCESS;
+ int result = file->write(file, file->buffer, file->buf_pos);
+ file->buf_pos = 0;
+ return result;
+}
- if (file->buf_pos > 0) {
- result = gitfo_write(file->fd, file->buffer, file->buf_pos);
- if (file->digest)
- git_hash_update(file->digest, file->buffer, file->buf_pos);
+static int write_normal(git_filebuf *file, const void *source, size_t len)
+{
+ int result = 0;
- file->buf_pos = 0;
+ if (len > 0) {
+ result = gitfo_write(file->fd, (void *)source, len);
+ if (file->digest)
+ git_hash_update(file->digest, source, len);
}
return result;
}
+static int write_deflate(git_filebuf *file, const void *source, size_t len)
+{
+ int result = Z_OK;
+ z_stream *zs = &file->zs;
+
+ if (len > 0 || file->flush_mode == Z_FINISH) {
+ zs->next_in = (void *)source;
+ zs->avail_in = len;
+
+ do {
+ int have;
+
+ zs->next_out = file->z_buf;
+ zs->avail_out = file->buf_size;
+
+ result = deflate(zs, file->flush_mode);
+ assert(result != Z_STREAM_ERROR);
+
+ have = file->buf_size - zs->avail_out;
+
+ if (gitfo_write(file->fd, file->z_buf, have) < GIT_SUCCESS)
+ return GIT_EOSERR;
+
+ } while (zs->avail_out == 0);
+
+ assert(zs->avail_in == 0);
+
+ if (file->digest)
+ git_hash_update(file->digest, source, len);
+ }
+
+ return GIT_SUCCESS;
+}
+
int git_filebuf_open(git_filebuf *file, const char *path, int flags)
{
int error;
size_t path_len;
- if (file == NULL || path == NULL)
+ if (file == NULL)
return GIT_ERROR;
memset(file, 0x0, sizeof(git_filebuf));
@@ -122,46 +160,93 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags)
file->buf_pos = 0;
file->fd = -1;
- path_len = strlen(path);
-
- file->path_original = git__strdup(path);
- if (file->path_original == NULL) {
+ /* Allocate the main cache buffer */
+ file->buffer = git__malloc(file->buf_size);
+ if (file->buffer == NULL){
error = GIT_ENOMEM;
goto cleanup;
}
- file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH);
- if (file->path_lock == NULL) {
- error = GIT_ENOMEM;
- goto cleanup;
+ /* If we are hashing on-write, allocate a new hash context */
+ if (flags & GIT_FILEBUF_HASH_CONTENTS) {
+ if ((file->digest = git_hash_new_ctx()) == NULL) {
+ error = GIT_ENOMEM;
+ goto cleanup;
+ }
}
- memcpy(file->path_lock, file->path_original, path_len);
- memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH);
+ /* If we are deflating on-write, */
+ if (flags & GIT_FILEBUF_DEFLATE_CONTENTS) {
- file->buffer = git__malloc(file->buf_size);
- if (file->buffer == NULL){
- error = GIT_ENOMEM;
- goto cleanup;
- }
+ /* Initialize the ZLib stream */
+ if (deflateInit(&file->zs, Z_DEFAULT_COMPRESSION) != Z_OK) {
+ error = GIT_EZLIB;
+ goto cleanup;
+ }
-#ifdef GIT_FILEBUF_THREADS
- file->buffer_back = git__malloc(file->buf_size);
- if (file->buffer_back == NULL){
- error = GIT_ENOMEM;
- goto cleanup;
+ /* Allocate the Zlib cache buffer */
+ file->z_buf = git__malloc(file->buf_size);
+ if (file->z_buf == NULL){
+ error = GIT_ENOMEM;
+ goto cleanup;
+ }
+
+ /* Never flush */
+ file->flush_mode = Z_NO_FLUSH;
+ file->write = &write_deflate;
+ } else {
+ file->write = &write_normal;
}
-#endif
- if (flags & GIT_FILEBUF_HASH_CONTENTS) {
- if ((file->digest = git_hash_new_ctx()) == NULL) {
+ /* If we are writing to a temp file */
+ if (flags & GIT_FILEBUF_TEMPORARY) {
+ char tmp_path[GIT_PATH_MAX];
+
+ /* Open the file as temporary for locking */
+ file->fd = gitfo_creat_tmp(tmp_path, "_filebuf_");
+ if (file->fd < 0) {
+ error = GIT_EOSERR;
+ goto cleanup;
+ }
+
+ /* No original path */
+ file->path_original = NULL;
+ file->path_lock = git__strdup(tmp_path);
+
+ if (file->path_lock == NULL) {
error = GIT_ENOMEM;
goto cleanup;
}
- }
+ } else {
+ /* If the file is not temporary, make sure we have a path */
+ if (path == NULL) {
+ error = GIT_ERROR;
+ goto cleanup;
+ }
- if ((error = lock_file(file, flags)) < GIT_SUCCESS)
- goto cleanup;
+ path_len = strlen(path);
+
+ /* Save the original path of the file */
+ file->path_original = git__strdup(path);
+ if (file->path_original == NULL) {
+ error = GIT_ENOMEM;
+ goto cleanup;
+ }
+
+ /* create the locking path by appending ".lock" to the original */
+ file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH);
+ if (file->path_lock == NULL) {
+ error = GIT_ENOMEM;
+ goto cleanup;
+ }
+
+ memcpy(file->path_lock, file->path_original, path_len);
+ memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH);
+
+ /* open the file for locking */
+ if ((error = lock_file(file, flags)) < GIT_SUCCESS)
+ goto cleanup;
+ }
return GIT_SUCCESS;
@@ -187,10 +272,25 @@ int git_filebuf_hash(git_oid *oid, git_filebuf *file)
return GIT_SUCCESS;
}
+int git_filebuf_commit_at(git_filebuf *file, const char *path)
+{
+ free(file->path_original);
+ file->path_original = git__strdup(path);
+ if (file->path_original == NULL)
+ return GIT_ENOMEM;
+
+ return git_filebuf_commit(file);
+}
+
int git_filebuf_commit(git_filebuf *file)
{
int error;
+ /* tmp file cannot be commited */
+ if (file->path_original == NULL)
+ return GIT_EOSERR;
+
+ file->flush_mode = Z_FINISH;
if ((error = flush_buffer(file)) < GIT_SUCCESS)
goto cleanup;
@@ -204,16 +304,16 @@ cleanup:
return error;
}
-GIT_INLINE(void) add_to_cache(git_filebuf *file, void *buf, size_t len)
+GIT_INLINE(void) add_to_cache(git_filebuf *file, const void *buf, size_t len)
{
memcpy(file->buffer + file->buf_pos, buf, len);
file->buf_pos += len;
}
-int git_filebuf_write(git_filebuf *file, void *buff, size_t len)
+int git_filebuf_write(git_filebuf *file, const void *buff, size_t len)
{
int error;
- unsigned char *buf = buff;
+ const unsigned char *buf = buff;
for (;;) {
size_t space_left = file->buf_size - file->buf_pos;
@@ -237,9 +337,9 @@ int git_filebuf_write(git_filebuf *file, void *buff, size_t len)
/* write too-large chunks immediately */
if (len > file->buf_size) {
- error = gitfo_write(file->fd, buf, len);
- if (file->digest)
- git_hash_update(file->digest, buf, len);
+ error = file->write(file, buf, len);
+ if (error < GIT_SUCCESS)
+ return error;
}
}
}
diff --git a/src/filebuf.h b/src/filebuf.h
index 9db615fbd..37cb36784 100644
--- a/src/filebuf.h
+++ b/src/filebuf.h
@@ -3,14 +3,17 @@
#include "fileops.h"
#include "hash.h"
+#include "git2/zlib.h"
#ifdef GIT_THREADS
# define GIT_FILEBUF_THREADS
#endif
-#define GIT_FILEBUF_HASH_CONTENTS 0x1
-#define GIT_FILEBUF_APPEND 0x2
-#define GIT_FILEBUF_FORCE 0x4
+#define GIT_FILEBUF_HASH_CONTENTS (1 << 0)
+#define GIT_FILEBUF_APPEND (1 << 2)
+#define GIT_FILEBUF_FORCE (1 << 3)
+#define GIT_FILEBUF_TEMPORARY (1 << 4)
+#define GIT_FILEBUF_DEFLATE_CONTENTS (1 << 5)
#define GIT_FILELOCK_EXTENSION ".lock\0"
#define GIT_FILELOCK_EXTLENGTH 6
@@ -19,12 +22,16 @@ struct git_filebuf {
char *path_original;
char *path_lock;
+ int (*write)(struct git_filebuf *file,
+ const void *source, size_t len);
+
git_hash_ctx *digest;
unsigned char *buffer;
-#ifdef GIT_FILEBUF_THREADS
- unsigned char *buffer_back;
-#endif
+ unsigned char *z_buf;
+
+ z_stream zs;
+ int flush_mode;
size_t buf_size, buf_pos;
git_file fd;
@@ -32,12 +39,13 @@ struct git_filebuf {
typedef struct git_filebuf git_filebuf;
-int git_filebuf_write(git_filebuf *lock, void *buff, size_t len);
+int git_filebuf_write(git_filebuf *lock, const void *buff, size_t len);
int git_filebuf_reserve(git_filebuf *file, void **buff, size_t len);
int git_filebuf_printf(git_filebuf *file, const char *format, ...);
int git_filebuf_open(git_filebuf *lock, const char *path, int flags);
int git_filebuf_commit(git_filebuf *lock);
+int git_filebuf_commit_at(git_filebuf *lock, const char *path);
void git_filebuf_cleanup(git_filebuf *lock);
int git_filebuf_hash(git_oid *oid, git_filebuf *file);
diff --git a/src/fileops.c b/src/fileops.c
index 76e689e8a..237a16a9f 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -2,13 +2,13 @@
#include "fileops.h"
#include <ctype.h>
-static int force_path(const char *to)
+int gitfo_mkdir_2file(const char *file_path)
{
const int mode = 0755; /* or 0777 ? */
int error = GIT_SUCCESS;
char target_folder_path[GIT_PATH_MAX];
- error = git__dirname_r(target_folder_path, sizeof(target_folder_path), to);
+ error = git__dirname_r(target_folder_path, sizeof(target_folder_path), file_path);
if (error < GIT_SUCCESS)
return error;
@@ -25,6 +25,87 @@ static int force_path(const char *to)
return GIT_SUCCESS;
}
+static int creat_tempfile(char *path_out, const char *tmp_dir, const char *filename)
+{
+ int fd;
+
+ git__joinpath(path_out, tmp_dir, filename);
+ strcat(path_out, "_git2_XXXXXX");
+
+#ifdef GIT_WIN32
+ /* FIXME: there may be race conditions when multi-threading
+ * with the library */
+ if (_mktemp_s(path_out, GIT_PATH_MAX) != 0)
+ return GIT_EOSERR;
+
+ fd = gitfo_creat(path_out, 0744);
+#else
+ fd = mkstemp(path_out);
+#endif
+
+ return fd >= 0 ? fd : GIT_EOSERR;
+}
+
+static const char *find_tmpdir(void)
+{
+ static int tmpdir_not_found = 0;
+ static char temp_dir[GIT_PATH_MAX];
+ static const char *env_vars[] = {
+ "TEMP", "TMP", "TMPDIR"
+ };
+
+ unsigned int i, j;
+ char test_file[GIT_PATH_MAX];
+
+ if (tmpdir_not_found)
+ return NULL;
+
+ if (temp_dir[0] != '\0')
+ return temp_dir;
+
+ for (i = 0; i < ARRAY_SIZE(env_vars); ++i) {
+ char *env_path;
+
+ env_path = getenv(env_vars[i]);
+ if (env_path == NULL)
+ continue;
+
+ strcpy(temp_dir, env_path);
+
+ /* Fix backslashes because Windows environment vars
+ * are probably fucked up */
+ for (j = 0; j < strlen(temp_dir); ++j)
+ if (temp_dir[j] == '\\')
+ temp_dir[j] = '/';
+
+ if (creat_tempfile(test_file, temp_dir, "writetest") >= 0) {
+ gitfo_unlink(test_file);
+ return temp_dir;
+ }
+ }
+
+ /* last resort: current folder. */
+ strcpy(temp_dir, "./");
+ if (creat_tempfile(test_file, temp_dir, "writetest") >= 0) {
+ gitfo_unlink(test_file);
+ return temp_dir;
+ }
+
+ tmpdir_not_found = 1;
+ return NULL;
+}
+
+int gitfo_creat_tmp(char *path_out, const char *filename)
+{
+ const char *tmp_dir;
+
+ tmp_dir = find_tmpdir();
+ if (tmp_dir == NULL)
+ return GIT_EOSERR;
+
+ return creat_tempfile(path_out, tmp_dir, filename);
+}
+
int gitfo_open(const char *path, int flags)
{
int fd = open(path, flags | O_BINARY);
@@ -39,7 +120,7 @@ int gitfo_creat(const char *path, int mode)
int gitfo_creat_force(const char *path, int mode)
{
- if (force_path(path) < GIT_SUCCESS)
+ if (gitfo_mkdir_2file(path) < GIT_SUCCESS)
return GIT_EOSERR;
return gitfo_creat(path, mode);
@@ -117,6 +198,7 @@ int gitfo_isdir(const char *path)
int gitfo_exists(const char *path)
{
+ assert(path);
return access(path, F_OK);
}
@@ -198,7 +280,7 @@ int gitfo_mv(const char *from, const char *to)
int gitfo_mv_force(const char *from, const char *to)
{
- if (force_path(to) < GIT_SUCCESS)
+ if (gitfo_mkdir_2file(to) < GIT_SUCCESS)
return GIT_EOSERR;
return gitfo_mv(from, to);
diff --git a/src/fileops.h b/src/fileops.h
index 5aa302b54..bc636fc38 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -58,8 +58,10 @@ extern int gitfo_exists(const char *path);
extern int gitfo_open(const char *path, int flags);
extern int gitfo_creat(const char *path, int mode);
extern int gitfo_creat_force(const char *path, int mode);
+extern int gitfo_creat_tmp(char *path_out, const char *filename);
extern int gitfo_isdir(const char *path);
extern int gitfo_mkdir_recurs(const char *path, int mode);
+extern int gitfo_mkdir_2file(const char *path);
#define gitfo_close(fd) close(fd)
extern int gitfo_read(git_file fd, void *buf, size_t cnt);
diff --git a/src/index.c b/src/index.c
index 95e56b7d5..6a355e11b 100644
--- a/src/index.c
+++ b/src/index.c
@@ -324,7 +324,7 @@ int git_index_add(git_index *index, const char *rel_path, int stage)
entry.file_size = st.st_size;
/* write the blob to disk and get the oid */
- if ((error = git_blob_writefile(&entry.oid, index->repository, full_path)) < GIT_SUCCESS)
+ if ((error = git_blob_create_fromfile(&entry.oid, index->repository, rel_path)) < GIT_SUCCESS)
return error;
entry.flags |= (stage << GIT_IDXENTRY_STAGESHIFT);
diff --git a/src/object.c b/src/object.c
index c432c6da0..0572663eb 100644
--- a/src/object.c
+++ b/src/object.c
@@ -66,153 +66,6 @@ static struct {
{ "REF_DELTA", 0, 0 }
};
-/*
- * Object source methods
- *
- * Abstract buffer methods that allow the writeback system
- * to prepare the contents of any git file in-memory before
- * writing them to disk.
- */
-static int source_resize(git_odb_source *src)
-{
- size_t write_offset, new_size;
- void *new_data;
-
- write_offset = (size_t)((char *)src->write_ptr - (char *)src->raw.data);
-
- new_size = src->raw.len * 2;
- if ((new_data = git__malloc(new_size)) == NULL)
- return GIT_ENOMEM;
-
- memcpy(new_data, src->raw.data, src->written_bytes);
- free(src->raw.data);
-
- src->raw.data = new_data;
- src->raw.len = new_size;
- src->write_ptr = (char *)new_data + write_offset;
-
- return GIT_SUCCESS;
-}
-
-int git__source_printf(git_odb_source *source, const char *format, ...)
-{
- va_list arglist;
- int len;
-
- assert(source->open && source->write_ptr);
-
- va_start(arglist, format);
-
- len = vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);
-
- while (source->written_bytes + len >= source->raw.len) {
- if (source_resize(source) < GIT_SUCCESS)
- return GIT_ENOMEM;
-
- len = vsnprintf(source->write_ptr, source->raw.len - source->written_bytes, format, arglist);
- }
-
- source->write_ptr = (char *)source->write_ptr + len;
- source->written_bytes += len;
-
- return GIT_SUCCESS;
-}
-
-int git__source_write(git_odb_source *source, const void *bytes, size_t len)
-{
- assert(source);
-
- assert(source->open && source->write_ptr);
-
- while (source->written_bytes + len >= source->raw.len) {
- if (source_resize(source) < GIT_SUCCESS)
- return GIT_ENOMEM;
- }
-
- memcpy(source->write_ptr, bytes, len);
- source->write_ptr = (char *)source->write_ptr + len;
- source->written_bytes += len;
-
- return GIT_SUCCESS;
-}
-
-static void prepare_write(git_object *object)
-{
- if (object->source.write_ptr != NULL || object->source.open)
- git_object__source_close(object);
-
- /* TODO: proper size calculation */
- object->source.raw.data = git__malloc(OBJECT_BASE_SIZE);
- object->source.raw.len = OBJECT_BASE_SIZE;
-
- object->source.write_ptr = object->source.raw.data;
- object->source.written_bytes = 0;
-
- object->source.open = 1;
-}
-
-static int write_back(git_object *object)
-{
- int error;
- git_oid new_id;
-
- assert(object);
-
- assert(object->source.open);
- assert(object->modified);
-
- object->source.raw.len = object->source.written_bytes;
-
- if ((error = git_odb_write(&new_id, object->repo->db, &object->source.raw)) < GIT_SUCCESS)
- return error;
-
- if (object->in_memory) {
- int idx = git_vector_search(&object->repo->memory_objects, object);
- git_vector_remove(&object->repo->memory_objects, idx);
- } else {
- git_hashtable_remove(object->repo->objects, &object->id);
- }
-
- git_oid_cpy(&object->id, &new_id);
- git_hashtable_insert(object->repo->objects, &object->id, object);
-
- object->source.write_ptr = NULL;
- object->source.written_bytes = 0;
-
- object->modified = 0;
- object->in_memory = 0;
-
- git_object__source_close(object);
- return GIT_SUCCESS;
-}
-
-int git_object__source_open(git_object *object)
-{
- int error;
-
- assert(object && !object->in_memory);
-
- if (object->source.open)
- git_object__source_close(object);
-
- error = git_odb_read(&object->source.raw, object->repo->db, &object->id);
- if (error < GIT_SUCCESS)
- return error;
-
- object->source.open = 1;
- return GIT_SUCCESS;
-}
-
-void git_object__source_close(git_object *object)
-{
- assert(object);
-
- if (object->source.open) {
- git_rawobj_close(&object->source.raw);
- object->source.open = 0;
- }
-}
-
static int create_object(git_object **object_out, git_otype type)
{
git_object *object = NULL;
@@ -225,43 +78,19 @@ static int create_object(git_object **object_out, git_otype type)
case GIT_OBJ_COMMIT:
case GIT_OBJ_TAG:
case GIT_OBJ_BLOB:
+ case GIT_OBJ_TREE:
object = git__malloc(git_object__size(type));
if (object == NULL)
return GIT_ENOMEM;
memset(object, 0x0, git_object__size(type));
break;
-
- case GIT_OBJ_TREE:
- object = (git_object *)git_tree__new();
- if (object == NULL)
- return GIT_ENOMEM;
- break;
default:
return GIT_EINVALIDTYPE;
}
- *object_out = object;
- return GIT_SUCCESS;
-}
-
-int git_object_new(git_object **object_out, git_repository *repo, git_otype type)
-{
- git_object *object = NULL;
- int error;
-
- assert(object_out && repo);
-
- if ((error = create_object(&object, type)) < GIT_SUCCESS)
- return error;
-
- object->repo = repo;
- object->in_memory = 1;
- object->modified = 1;
-
- object->source.raw.type = type;
+ object->type = type;
- object->lru = ++repo->lru_counter;
*object_out = object;
return GIT_SUCCESS;
}
@@ -269,126 +98,77 @@ int git_object_new(git_object **object_out, git_repository *repo, git_otype type
int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type)
{
git_object *object = NULL;
- git_rawobj obj_file;
+ git_odb_object *odb_obj;
int error = GIT_SUCCESS;
assert(repo && object_out && id);
- object = git_hashtable_lookup(repo->objects, id);
+ object = git_cache_get(&repo->objects, id);
if (object != NULL) {
- if (type != GIT_OBJ_ANY && type != object->source.raw.type)
+ if (type != GIT_OBJ_ANY && type != object->type)
return GIT_EINVALIDTYPE;
*object_out = object;
- object->lru = ++repo->lru_counter;
- object->can_free = 0;
return GIT_SUCCESS;
}
- error = git_odb_read(&obj_file, repo->db, id);
+ error = git_odb_read(&odb_obj, repo->db, id);
if (error < GIT_SUCCESS)
return error;
- if (type != GIT_OBJ_ANY && type != obj_file.type) {
- git_rawobj_close(&obj_file);
+ if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) {
+ git_odb_object_close(odb_obj);
return GIT_EINVALIDTYPE;
}
- type = obj_file.type;
+ type = odb_obj->raw.type;
if ((error = create_object(&object, type)) < GIT_SUCCESS)
return error;
/* Initialize parent object */
- git_oid_cpy(&object->id, id);
+ git_oid_cpy(&object->cached.oid, id);
object->repo = repo;
- memcpy(&object->source.raw, &obj_file, sizeof(git_rawobj));
- object->source.open = 1;
switch (type) {
case GIT_OBJ_COMMIT:
- error = git_commit__parse((git_commit *)object);
+ error = git_commit__parse((git_commit *)object, odb_obj);
break;
case GIT_OBJ_TREE:
- error = git_tree__parse((git_tree *)object);
+ error = git_tree__parse((git_tree *)object, odb_obj);
break;
case GIT_OBJ_TAG:
- error = git_tag__parse((git_tag *)object);
+ error = git_tag__parse((git_tag *)object, odb_obj);
break;
case GIT_OBJ_BLOB:
- error = git_blob__parse((git_blob *)object);
+ error = git_blob__parse((git_blob *)object, odb_obj);
break;
default:
break;
}
+ git_odb_object_close(odb_obj);
+
if (error < GIT_SUCCESS) {
git_object__free(object);
return error;
}
- git_object__source_close(object);
- git_hashtable_insert(repo->objects, &object->id, object);
-
- object->lru = ++repo->lru_counter;
- *object_out = object;
+ *object_out = git_cache_try_store(&repo->objects, object);
return GIT_SUCCESS;
}
-int git_object_write(git_object *object)
+void git_object__free(void *_obj)
{
- int error;
- git_odb_source *source;
+ git_object *object = (git_object *)_obj;
assert(object);
- if (object->modified == 0)
- return GIT_SUCCESS;
-
- prepare_write(object);
- source = &object->source;
-
- switch (source->raw.type) {
- case GIT_OBJ_COMMIT:
- error = git_commit__writeback((git_commit *)object, source);
- break;
-
- case GIT_OBJ_TREE:
- error = git_tree__writeback((git_tree *)object, source);
- break;
-
- case GIT_OBJ_TAG:
- error = git_tag__writeback((git_tag *)object, source);
- break;
-
- case GIT_OBJ_BLOB:
- error = git_blob__writeback((git_blob *)object, source);
- break;
-
- default:
- error = GIT_ERROR;
- break;
- }
-
- if (error < GIT_SUCCESS) {
- git_object__source_close(object);
- return error;
- }
-
- return write_back(object);
-}
-
-void git_object__free(git_object *object)
-{
- assert(object);
-
- git_object__source_close(object);
-
- switch (object->source.raw.type) {
+ switch (object->type) {
case GIT_OBJ_COMMIT:
git_commit__free((git_commit *)object);
break;
@@ -416,29 +196,19 @@ void git_object_close(git_object *object)
if (object == NULL)
return;
- if (object->in_memory) {
- int idx = git_vector_search(&object->repo->memory_objects, object);
- git_vector_remove(&object->repo->memory_objects, idx);
- git_object__free(object);
- } else {
- object->can_free = 1;
- }
+ git_cached_obj_decref((git_cached_obj *)object, git_object__free);
}
const git_oid *git_object_id(const git_object *obj)
{
assert(obj);
-
- if (obj->in_memory)
- return NULL;
-
- return &obj->id;
+ return &obj->cached.oid;
}
git_otype git_object_type(const git_object *obj)
{
assert(obj);
- return obj->source.raw.type;
+ return obj->type;
}
git_repository *git_object_owner(const git_object *obj)
diff --git a/src/odb.c b/src/odb.c
index 2013ac24c..9aeaa8a23 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -87,56 +87,49 @@ int git_odb__hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_rawobj *ob
return GIT_SUCCESS;
}
-void git_rawobj_close(git_rawobj *obj)
-{
- free(obj->data);
- obj->data = NULL;
-}
-int git_rawobj_hash(git_oid *id, git_rawobj *obj)
+static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source)
{
- char hdr[64];
- int hdrlen;
+ git_odb_object *object = git__malloc(sizeof(git_odb_object));
+ memset(object, 0x0, sizeof(git_odb_object));
- assert(id && obj);
+ git_oid_cpy(&object->cached.oid, oid);
+ memcpy(&object->raw, source, sizeof(git_rawobj));
- return git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj);
+ return object;
}
-int git_odb__inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
+static void free_odb_object(void *o)
{
- z_stream zs;
- int status = Z_OK;
-
- memset(&zs, 0x0, sizeof(zs));
-
- zs.next_out = out;
- zs.avail_out = outlen;
-
- zs.next_in = in;
- zs.avail_in = inlen;
+ git_odb_object *object = (git_odb_object *)o;
- if (inflateInit(&zs) < Z_OK)
- return GIT_ERROR;
+ if (object != NULL) {
+ free(object->raw.data);
+ free(object);
+ }
+}
- while (status == Z_OK)
- status = inflate(&zs, Z_FINISH);
+void git_odb_object_close(git_odb_object *object)
+{
+ git_cached_obj_decref((git_cached_obj *)object, &free_odb_object);
+}
- inflateEnd(&zs);
+int git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type)
+{
+ char hdr[64];
+ int hdrlen;
+ git_rawobj raw;
- if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */)
- return GIT_ERROR;
+ assert(id);
- if (zs.total_out != outlen)
- return GIT_ERROR;
+ raw.data = (void *)data;
+ raw.len = len;
+ raw.type = type;
- return GIT_SUCCESS;
+ return git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, &raw);
}
-
-
-
/***********************************************************
*
* OBJECT DATABASE PUBLIC API
@@ -162,6 +155,8 @@ int git_odb_new(git_odb **out)
if (!db)
return GIT_ENOMEM;
+ git_cache_init(&db->cache, GIT_DEFAULT_CACHE_SIZE, &free_odb_object);
+
if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
free(db);
return GIT_ENOMEM;
@@ -306,16 +301,23 @@ void git_odb_close(git_odb *db)
}
git_vector_free(&db->backends);
+ git_cache_free(&db->cache);
free(db);
}
int git_odb_exists(git_odb *db, const git_oid *id)
{
+ git_odb_object *object;
unsigned int i;
int found = 0;
assert(db && id);
+ if ((object = git_cache_get(&db->cache, id)) != NULL) {
+ git_odb_object_close(object);
+ return 1;
+ }
+
for (i = 0; i < db->backends.length && !found; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend;
@@ -327,19 +329,27 @@ int git_odb_exists(git_odb *db, const git_oid *id)
return found;
}
-int git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id)
+int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id)
{
unsigned int i;
int error = GIT_ENOTFOUND;
+ git_odb_object *object;
- assert(out && db && id);
+ assert(db && id);
+
+ if ((object = git_cache_get(&db->cache, id)) != NULL) {
+ *len_p = object->raw.len;
+ *type_p = object->raw.type;
+ git_odb_object_close(object);
+ return GIT_SUCCESS;
+ }
for (i = 0; i < db->backends.length && error < 0; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend;
if (b->read_header != NULL)
- error = b->read_header(out, b, id);
+ error = b->read_header(len_p, type_p, b, id);
}
/*
@@ -347,37 +357,50 @@ int git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id)
* try reading the whole object and freeing the contents
*/
if (error < 0) {
- error = git_odb_read(out, db, id);
- git_rawobj_close(out);
+ if ((error = git_odb_read(&object, db, id)) < GIT_SUCCESS)
+ return error;
+
+ *len_p = object->raw.len;
+ *type_p = object->raw.len;
+ git_odb_object_close(object);
}
- return error;
+ return GIT_SUCCESS;
}
-int git_odb_read(git_rawobj *out, git_odb *db, const git_oid *id)
+int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
{
unsigned int i;
int error = GIT_ENOTFOUND;
+ git_rawobj raw;
assert(out && db && id);
+ *out = git_cache_get(&db->cache, id);
+ if (*out != NULL)
+ return GIT_SUCCESS;
+
for (i = 0; i < db->backends.length && error < 0; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *b = internal->backend;
if (b->read != NULL)
- error = b->read(out, b, id);
+ error = b->read(&raw.data, &raw.len, &raw.type, b, id);
+ }
+
+ if (error == GIT_SUCCESS) {
+ *out = git_cache_try_store(&db->cache, new_odb_object(id, &raw));
}
return error;
}
-int git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj)
+int git_odb_open_wstream(git_odb_stream **stream, git_odb *db, size_t size, git_otype type)
{
unsigned int i;
int error = GIT_ERROR;
- assert(obj && db && id);
+ assert(stream && db);
for (i = 0; i < db->backends.length && error < 0; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i);
@@ -387,8 +410,26 @@ int git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj)
if (internal->is_alternate)
continue;
- if (b->write != NULL)
- error = b->write(id, b, obj);
+ if (b->writestream != NULL)
+ error = b->writestream(stream, b, size, type);
+ }
+
+ return error;
+}
+
+int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oid)
+{
+ unsigned int i;
+ int error = GIT_ERROR;
+
+ assert(stream && db);
+
+ for (i = 0; i < db->backends.length && error < 0; ++i) {
+ backend_internal *internal = git_vector_get(&db->backends, i);
+ git_odb_backend *b = internal->backend;
+
+ if (b->readstream != NULL)
+ error = b->readstream(stream, b, oid);
}
return error;
diff --git a/src/odb.h b/src/odb.h
index c3d0a17ab..f3685834e 100644
--- a/src/odb.h
+++ b/src/odb.h
@@ -3,15 +3,31 @@
#include "git2/odb.h"
#include "git2/oid.h"
+#include "git2/types.h"
#include "vector.h"
+#include "cache.h"
+/* DO NOT EXPORT */
+typedef struct {
+ void *data; /**< Raw, decompressed object data. */
+ size_t len; /**< Total number of bytes in data. */
+ git_otype type; /**< Type of this object. */
+} git_rawobj;
+
+/* EXPORT */
+struct git_odb_object {
+ git_cached_obj cached;
+ git_rawobj raw;
+};
+
+/* EXPORT */
struct git_odb {
void *_internal;
git_vector backends;
+ git_cache cache;
};
int git_odb__hash_obj(git_oid *id, char *hdr, size_t n, int *len, git_rawobj *obj);
-int git_odb__inflate_buffer(void *in, size_t inlen, void *out, size_t outlen);
#endif
diff --git a/src/odb_loose.c b/src/odb_loose.c
index 4e2d9a639..4ab1128f3 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -30,14 +30,22 @@
#include "hash.h"
#include "odb.h"
#include "delta-apply.h"
+#include "filebuf.h"
#include "git2/odb_backend.h"
+#include "git2/types.h"
typedef struct { /* object header data */
git_otype type; /* object type */
size_t size; /* object size */
} obj_hdr;
+typedef struct {
+ git_odb_stream stream;
+ git_filebuf fbuf;
+ int finished;
+} loose_writestream;
+
typedef struct loose_backend {
git_odb_backend parent;
@@ -53,38 +61,6 @@ typedef struct loose_backend {
*
***********************************************************/
-static int make_temp_file(git_file *fd, char *tmp, size_t n, char *file)
-{
- char *template = "/tmp_obj_XXXXXX";
- size_t tmplen = strlen(template);
- int dirlen;
-
- if ((dirlen = git__dirname_r(tmp, n, file)) < 0)
- return GIT_ERROR;
-
- if ((dirlen + tmplen) >= n)
- return GIT_ERROR;
-
- strcpy(tmp + dirlen, (dirlen) ? template : template + 1);
-
- *fd = gitfo_mkstemp(tmp);
- if (*fd < 0 && dirlen) {
- /* create directory if it doesn't exist */
- tmp[dirlen] = '\0';
- if ((gitfo_exists(tmp) < 0) && gitfo_mkdir(tmp, 0755))
- return GIT_ERROR;
- /* try again */
- strcpy(tmp + dirlen, template);
- *fd = gitfo_mkstemp(tmp);
- }
- if (*fd < 0)
- return GIT_ERROR;
-
- return GIT_SUCCESS;
-}
-
-
-
static size_t object_file_name(char *name, size_t n, char *dir, const git_oid *id)
{
size_t len = strlen(dir);
@@ -236,72 +212,44 @@ static int finish_inflate(z_stream *s)
return GIT_SUCCESS;
}
-static int deflate_buf(z_stream *s, void *in, size_t len, int flush)
+static int is_zlib_compressed_data(unsigned char *data)
{
- int status = Z_OK;
+ unsigned int w;
- set_stream_input(s, in, len);
- while (status == Z_OK) {
- status = deflate(s, flush);
- if (s->avail_in == 0)
- break;
- }
- return status;
+ w = ((unsigned int)(data[0]) << 8) + data[1];
+ return data[0] == 0x78 && !(w % 31);
}
-static int deflate_obj(gitfo_buf *buf, char *hdr, int hdrlen, git_rawobj *obj, int level)
+static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
{
z_stream zs;
- int status;
- size_t size;
-
- assert(buf && !buf->data && hdr && obj);
- assert(level == Z_DEFAULT_COMPRESSION || (level >= 0 && level <= 9));
+ int status = Z_OK;
- buf->data = NULL;
- buf->len = 0;
- init_stream(&zs, NULL, 0);
+ memset(&zs, 0x0, sizeof(zs));
- if (deflateInit(&zs, level) < Z_OK)
- return GIT_ERROR;
+ zs.next_out = out;
+ zs.avail_out = outlen;
- size = deflateBound(&zs, hdrlen + obj->len);
+ zs.next_in = in;
+ zs.avail_in = inlen;
- if ((buf->data = git__malloc(size)) == NULL) {
- deflateEnd(&zs);
+ if (inflateInit(&zs) < Z_OK)
return GIT_ERROR;
- }
- set_stream_output(&zs, buf->data, size);
-
- /* compress the header */
- status = deflate_buf(&zs, hdr, hdrlen, Z_NO_FLUSH);
+ while (status == Z_OK)
+ status = inflate(&zs, Z_FINISH);
- /* if header compressed OK, compress the object */
- if (status == Z_OK)
- status = deflate_buf(&zs, obj->data, obj->len, Z_FINISH);
+ inflateEnd(&zs);
- if (status != Z_STREAM_END) {
- deflateEnd(&zs);
- free(buf->data);
- buf->data = NULL;
+ if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */)
return GIT_ERROR;
- }
- buf->len = zs.total_out;
- deflateEnd(&zs);
+ if (zs.total_out != outlen)
+ return GIT_ERROR;
return GIT_SUCCESS;
}
-static int is_zlib_compressed_data(unsigned char *data)
-{
- unsigned int w;
-
- w = ((unsigned int)(data[0]) << 8) + data[1];
- return data[0] == 0x78 && !(w % 31);
-}
-
static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr)
{
unsigned char *buf, *head = hb;
@@ -371,7 +319,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, gitfo_buf *obj)
in = ((unsigned char *)obj->data) + used;
len = obj->len - used;
- if (git_odb__inflate_buffer(in, len, buf, hdr.size)) {
+ if (inflate_buffer(in, len, buf, hdr.size)) {
free(buf);
return GIT_ERROR;
}
@@ -505,37 +453,6 @@ cleanup:
return error;
}
-static int write_obj(gitfo_buf *buf, git_oid *id, loose_backend *backend)
-{
- char file[GIT_PATH_MAX];
- char temp[GIT_PATH_MAX];
- git_file fd;
-
- if (object_file_name(file, sizeof(file), backend->objects_dir, id))
- return GIT_EOSERR;
-
- if (make_temp_file(&fd, temp, sizeof(temp), file) < 0)
- return GIT_EOSERR;
-
- if (gitfo_write(fd, buf->data, buf->len) < 0) {
- gitfo_close(fd);
- gitfo_unlink(temp);
- return GIT_EOSERR;
- }
-
- if (backend->fsync_object_files)
- gitfo_fsync(fd);
- gitfo_close(fd);
- gitfo_chmod(temp, 0444);
-
- if (gitfo_mv(temp, file) < 0) {
- gitfo_unlink(temp);
- return GIT_EOSERR;
- }
-
- return GIT_SUCCESS;
-}
-
static int locate_object(char *object_location, loose_backend *backend, const git_oid *oid)
{
object_file_name(object_location, GIT_PATH_MAX, backend->objects_dir, oid);
@@ -558,29 +475,44 @@ static int locate_object(char *object_location, loose_backend *backend, const gi
*
***********************************************************/
-int loose_backend__read_header(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)
+int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
{
char object_path[GIT_PATH_MAX];
+ git_rawobj raw;
+ int error;
- assert(obj && backend && oid);
+ assert(backend && oid);
if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
return GIT_ENOTFOUND;
- return read_header_loose(obj, object_path);
-}
+ if ((error = read_header_loose(&raw, object_path)) < GIT_SUCCESS)
+ return error;
+ *len_p = raw.len;
+ *type_p = raw.type;
+ return GIT_SUCCESS;
+}
-int loose_backend__read(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)
+int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
{
char object_path[GIT_PATH_MAX];
+ git_rawobj raw;
+ int error;
- assert(obj && backend && oid);
+ assert(backend && oid);
if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
return GIT_ENOTFOUND;
- return read_loose(obj, object_path);
+ if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS)
+ return error;
+
+ *buffer_p = raw.data;
+ *len_p = raw.len;
+ *type_p = raw.type;
+
+ return GIT_SUCCESS;
}
int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
@@ -592,32 +524,104 @@ int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
return locate_object(object_path, (loose_backend *)backend, oid) == GIT_SUCCESS;
}
+int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
+{
+ loose_writestream *stream = (loose_writestream *)_stream;
+ loose_backend *backend = (loose_backend *)_stream->backend;
+
+ int error;
+ char final_path[GIT_PATH_MAX];
+
+ if ((error = git_filebuf_hash(oid, &stream->fbuf)) < GIT_SUCCESS)
+ return error;
+
+ if (object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid))
+ return GIT_ENOMEM;
-int loose_backend__write(git_oid *id, git_odb_backend *_backend, git_rawobj *obj)
+ if ((error = gitfo_mkdir_2file(final_path)) < GIT_SUCCESS)
+ return error;
+
+ stream->finished = 1;
+ return git_filebuf_commit_at(&stream->fbuf, final_path);
+}
+
+int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len)
{
+ loose_writestream *stream = (loose_writestream *)_stream;
+ return git_filebuf_write(&stream->fbuf, data, len);
+}
+
+void loose_backend__stream_free(git_odb_stream *_stream)
+{
+ loose_writestream *stream = (loose_writestream *)_stream;
+
+ if (!stream->finished)
+ git_filebuf_cleanup(&stream->fbuf);
+
+ free(stream);
+}
+
+static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type)
+{
+ const char *type_str = git_object_type2string(obj_type);
+ int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj_len);
+
+ assert(len > 0); /* otherwise snprintf() is broken */
+ assert(((size_t) len) < n); /* otherwise the caller is broken! */
+
+ if (len < 0 || ((size_t) len) >= n)
+ return GIT_ERROR;
+ return len+1;
+}
+
+int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, size_t length, git_otype type)
+{
+ loose_backend *backend;
+ loose_writestream *stream;
+
char hdr[64];
int hdrlen;
- gitfo_buf buf = GITFO_BUF_INIT;
int error;
- loose_backend *backend;
- assert(id && _backend && obj);
+ assert(_backend);
backend = (loose_backend *)_backend;
+ *stream_out = NULL;
- if ((error = git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, obj)) < 0)
- return error;
+ hdrlen = format_object_header(hdr, sizeof(hdr), length, type);
+ if (hdrlen < GIT_SUCCESS)
+ return GIT_EOBJCORRUPTED;
+
+ stream = git__calloc(1, sizeof(loose_writestream));
+ if (stream == NULL)
+ return GIT_ENOMEM;
- if (git_odb_exists(_backend->odb, id))
- return GIT_SUCCESS;
+ stream->stream.backend = _backend;
+ stream->stream.read = NULL; /* read only */
+ stream->stream.write = &loose_backend__stream_write;
+ stream->stream.finalize_write = &loose_backend__stream_fwrite;
+ stream->stream.free = &loose_backend__stream_free;
+ stream->stream.mode = GIT_STREAM_WRONLY;
- if ((error = deflate_obj(&buf, hdr, hdrlen, obj, backend->object_zlib_level)) < 0)
+ error = git_filebuf_open(&stream->fbuf, NULL,
+ GIT_FILEBUF_HASH_CONTENTS |
+ GIT_FILEBUF_DEFLATE_CONTENTS |
+ GIT_FILEBUF_TEMPORARY);
+
+ if (error < GIT_SUCCESS) {
+ free(stream);
return error;
+ }
- error = write_obj(&buf, id, backend);
+ error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen);
+ if (error < GIT_SUCCESS) {
+ git_filebuf_cleanup(&stream->fbuf);
+ free(stream);
+ return error;
+ }
- gitfo_free_buf(&buf);
- return error;
+ *stream_out = (git_odb_stream *)stream;
+ return GIT_SUCCESS;
}
void loose_backend__free(git_odb_backend *_backend)
@@ -649,7 +653,7 @@ int git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir
backend->parent.read = &loose_backend__read;
backend->parent.read_header = &loose_backend__read_header;
- backend->parent.write = &loose_backend__write;
+ backend->parent.writestream = &loose_backend__stream;
backend->parent.exists = &loose_backend__exists;
backend->parent.free = &loose_backend__free;
diff --git a/src/odb_pack.c b/src/odb_pack.c
index 3067179be..65210f0b0 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -1243,7 +1243,7 @@ static int packfile_unpack_delta(
error = packfile_unpack_compressed(&delta, backend, p, w_curs, curpos, delta_size, delta_type);
if (error < GIT_SUCCESS) {
- git_rawobj_close(&base);
+ free(base.data);
return error;
}
@@ -1252,8 +1252,8 @@ static int packfile_unpack_delta(
base.data, base.len,
delta.data, delta.len);
- git_rawobj_close(&base);
- git_rawobj_close(&delta);
+ free(base.data);
+ free(delta.data);
/* TODO: we might want to cache this shit. eventually */
//add_delta_base_cache(p, base_offset, base, base_size, *type);
@@ -1337,15 +1337,23 @@ int pack_backend__read_header(git_rawobj *obj, git_odb_backend *backend, const g
}
*/
-int pack_backend__read(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid)
+int pack_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
{
struct pack_entry e;
+ git_rawobj raw;
int error;
if ((error = pack_entry_find(&e, (struct pack_backend *)backend, oid)) < GIT_SUCCESS)
return error;
- return packfile_unpack(obj, (struct pack_backend *)backend, e.p, e.offset);
+ if ((error = packfile_unpack(&raw, (struct pack_backend *)backend, e.p, e.offset)) < GIT_SUCCESS)
+ return error;
+
+ *buffer_p = raw.data;
+ *len_p = raw.len;
+ *type_p = raw.type;
+
+ return GIT_SUCCESS;
}
int pack_backend__exists(git_odb_backend *backend, const git_oid *oid)
@@ -1397,7 +1405,6 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
backend->parent.read = &pack_backend__read;
backend->parent.read_header = NULL;
- backend->parent.write = NULL;
backend->parent.exists = &pack_backend__exists;
backend->parent.free = &pack_backend__free;
diff --git a/src/oid.c b/src/oid.c
index 81b7d6005..eb167a685 100644
--- a/src/oid.c
+++ b/src/oid.c
@@ -143,14 +143,18 @@ int git__parse_oid(git_oid *oid, char **buffer_out,
return GIT_SUCCESS;
}
-int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid)
+int git__write_oid(git_odb_stream *stream, const char *header, const git_oid *oid)
{
- char hex_oid[41];
+ char hex_oid[42];
- git_oid_fmt(hex_oid, oid);
- hex_oid[40] = 0;
+ git_oid_fmt(hex_oid + 1, oid);
- return git__source_printf(src, "%s %s\n", header, hex_oid);
+ hex_oid[0] = ' ';
+ hex_oid[41] = '\n';
+
+ stream->write(stream, header, strlen(header));
+ stream->write(stream, hex_oid, 42);
+ return GIT_SUCCESS;
}
void git_oid_mkraw(git_oid *out, const unsigned char *raw)
diff --git a/src/repository.c b/src/repository.c
index 37aa44781..132969402 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -40,30 +40,12 @@
#define GIT_BRANCH_MASTER "master"
-static const int OBJECT_TABLE_SIZE = 32;
-
typedef struct {
char *path_repository;
unsigned is_bare:1, has_been_reinit:1;
} repo_init;
/*
- * Hash table methods
- *
- * Callbacks for the ODB cache, implemented
- * as a hash table
- */
-static uint32_t object_table_hash(const void *key, int hash_id)
-{
- uint32_t r;
- git_oid *id;
-
- id = (git_oid *)key;
- memcpy(&r, id->id + (hash_id * sizeof(uint32_t)), sizeof(r));
- return r;
-}
-
-/*
* Git repository open methods
*
* Open a repository object from its path
@@ -186,25 +168,9 @@ static git_repository *repository_alloc()
memset(repo, 0x0, sizeof(git_repository));
- repo->objects = git_hashtable_alloc(
- OBJECT_TABLE_SIZE,
- object_table_hash,
- (git_hash_keyeq_ptr)git_oid_cmp);
-
- if (repo->objects == NULL) {
- free(repo);
- return NULL;
- }
+ git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {
- git_hashtable_free(repo->objects);
- free(repo);
- return NULL;
- }
-
- if (git_vector_init(&repo->memory_objects, 16, NULL) < GIT_SUCCESS) {
- git_hashtable_free(repo->objects);
- git_repository__refcache_free(&repo->references);
free(repo);
return NULL;
}
@@ -330,51 +296,19 @@ cleanup:
return error;
}
-int git_repository_gc(git_repository *repo)
-{
- int collected = 0;
- git_object *object;
- const void *_unused;
-
- GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,
- if (object->can_free) {
- git_object__free(object);
- collected++;
- }
- );
-
- return collected;
-}
-
void git_repository_free(git_repository *repo)
{
- git_object *object;
- const void *_unused;
- unsigned int i;
-
if (repo == NULL)
return;
- /* force free all the objects */
- GIT_HASHTABLE_FOREACH(repo->objects, _unused, object,
- git_object__free(object);
- );
-
- for (i = 0; i < repo->memory_objects.length; ++i) {
- object = git_vector_get(&repo->memory_objects, i);
- git_object__free(object);
- }
+ git_cache_free(&repo->objects);
+ git_repository__refcache_free(&repo->references);
free(repo->path_workdir);
free(repo->path_index);
free(repo->path_repository);
free(repo->path_odb);
- git_hashtable_free(repo->objects);
- git_vector_free(&repo->memory_objects);
-
- git_repository__refcache_free(&repo->references);
-
if (repo->db != NULL)
git_odb_close(repo->db);
diff --git a/src/repository.h b/src/repository.h
index 48b8dae6b..fef1c7da0 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -9,6 +9,7 @@
#include "hashtable.h"
#include "index.h"
+#include "cache.h"
#include "refs.h"
#define DOT_GIT ".git"
@@ -16,28 +17,17 @@
#define GIT_OBJECTS_DIR "objects/"
#define GIT_INDEX_FILE "index"
-typedef struct {
- git_rawobj raw;
- void *write_ptr;
- size_t written_bytes;
- int open:1;
-} git_odb_source;
-
struct git_object {
- git_oid id;
+ git_cached_obj cached;
git_repository *repo;
- git_odb_source source;
- unsigned int lru;
- unsigned char in_memory, modified, can_free, _pad;
+ git_otype type;
};
struct git_repository {
git_odb *db;
git_index *index;
- git_hashtable *objects;
- git_vector memory_objects;
-
+ git_cache objects;
git_refcache references;
char *path_repository;
@@ -49,17 +39,11 @@ struct git_repository {
unsigned int lru_counter;
};
-int git_object__source_open(git_object *object);
-void git_object__source_close(git_object *object);
-
/* fully free the object; internal method, do not
* export */
-void git_object__free(git_object *object);
-
-int git__source_printf(git_odb_source *source, const char *format, ...);
-int git__source_write(git_odb_source *source, const void *bytes, size_t len);
+void git_object__free(void *object);
int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header);
-int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid);
+int git__write_oid(git_odb_stream *src, const char *header, const git_oid *oid);
#endif
diff --git a/src/revwalk.c b/src/revwalk.c
index 3b7ad34e6..a9d4f8734 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -25,6 +25,7 @@
#include "common.h"
#include "commit.h"
+#include "odb.h"
#include "hashtable.h"
#include "pqueue.h"
@@ -236,22 +237,22 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo
static int commit_parse(git_revwalk *walk, commit_object *commit)
{
- git_rawobj data;
+ git_odb_object *obj;
int error;
if (commit->parsed)
return GIT_SUCCESS;
- if ((error = git_odb_read(&data, walk->repo->db, &commit->oid)) < GIT_SUCCESS)
+ if ((error = git_odb_read(&obj, walk->repo->db, &commit->oid)) < GIT_SUCCESS)
return error;
- if (data.type != GIT_OBJ_COMMIT) {
- git_rawobj_close(&data);
+ if (obj->raw.type != GIT_OBJ_COMMIT) {
+ git_odb_object_close(obj);
return GIT_EOBJTYPE;
}
- error = commit_quick_parse(walk, commit, &data);
- git_rawobj_close(&data);
+ error = commit_quick_parse(walk, commit, &obj->raw);
+ git_odb_object_close(obj);
return error;
}
diff --git a/src/signature.c b/src/signature.c
index 5c9f15973..13816c396 100644
--- a/src/signature.c
+++ b/src/signature.c
@@ -46,13 +46,7 @@ git_signature *git_signature_new(const char *name, const char *email, time_t tim
goto cleanup;
p->name = git__strdup(name);
- if (p->name == NULL)
- goto cleanup;
-
p->email = git__strdup(email);
- if (p->email == NULL)
- goto cleanup;
-
p->when.time = time;
p->when.offset = offset;
@@ -179,10 +173,12 @@ int git_signature__parse(git_signature *sig, char **buffer_out,
return GIT_SUCCESS;
}
-int git_signature__write(git_odb_source *src, const char *header, const git_signature *sig)
+int git_signature__write(char **signature, const char *header, const git_signature *sig)
{
- char sign;
int offset, hours, mins;
+ char sig_buffer[2048];
+ int sig_buffer_len;
+ char sign;
offset = sig->when.offset;
sign = (sig->when.offset < 0) ? '-' : '+';
@@ -193,7 +189,16 @@ int git_signature__write(git_odb_source *src, const char *header, const git_sign
hours = offset / 60;
mins = offset % 60;
- return git__source_printf(src, "%s %s <%s> %u %c%02d%02d\n", header, sig->name, sig->email, (unsigned)sig->when.time, sign, hours, mins);
+ sig_buffer_len = snprintf(sig_buffer, sizeof(sig_buffer),
+ "%s %s <%s> %u %c%02d%02d\n",
+ header, sig->name, sig->email,
+ (unsigned)sig->when.time, sign, hours, mins);
+
+ if (sig_buffer_len < 0 || (size_t)sig_buffer_len > sizeof(sig_buffer))
+ return GIT_ENOMEM;
+
+ *signature = git__strdup(sig_buffer);
+ return sig_buffer_len;
}
diff --git a/src/signature.h b/src/signature.h
index ee212c2dc..3534cb21f 100644
--- a/src/signature.h
+++ b/src/signature.h
@@ -7,6 +7,6 @@
#include <time.h>
int git_signature__parse(git_signature *sig, char **buffer_out, const char *buffer_end, const char *header);
-int git_signature__write(git_odb_source *src, const char *header, const git_signature *sig);
+int git_signature__write(char **signature, const char *header, const git_signature *sig);
#endif
diff --git a/src/tag.c b/src/tag.c
index 0489e7e4a..7baababbf 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -56,21 +56,6 @@ const git_oid *git_tag_target_oid(git_tag *t)
return &t->target;
}
-int git_tag_set_target(git_tag *tag, git_object *target)
-{
- const git_oid *oid;
-
- assert(tag && target);
-
- if ((oid = git_object_id(target)) == NULL)
- return GIT_EMISSINGOBJDATA;
-
- tag->object.modified = 1;
- git_oid_cpy(&tag->target, oid);
- tag->type = git_object_type(target);
- return GIT_SUCCESS;
-}
-
git_otype git_tag_type(git_tag *t)
{
assert(t);
@@ -83,50 +68,17 @@ const char *git_tag_name(git_tag *t)
return t->tag_name;
}
-void git_tag_set_name(git_tag *tag, const char *name)
-{
- assert(tag && name);
-
- tag->object.modified = 1;
-
- if (tag->tag_name)
- free(tag->tag_name);
-
- tag->tag_name = git__strdup(name);
-}
-
const git_signature *git_tag_tagger(git_tag *t)
{
return t->tagger;
}
-void git_tag_set_tagger(git_tag *tag, const git_signature *tagger_sig)
-{
- assert(tag && tagger_sig);
- tag->object.modified = 1;
-
- git_signature_free(tag->tagger);
- tag->tagger = git_signature_dup(tagger_sig);
-}
-
const char *git_tag_message(git_tag *t)
{
assert(t);
return t->message;
}
-void git_tag_set_message(git_tag *tag, const char *message)
-{
- assert(tag && message);
-
- tag->object.modified = 1;
-
- if (tag->message)
- free(tag->message);
-
- tag->message = git__strdup(message);
-}
-
static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
{
static const char *tag_types[] = {
@@ -187,9 +139,6 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
buffer = search + 1;
- if (tag->tagger != NULL)
- git_signature_free(tag->tagger);
-
tag->tagger = git__malloc(sizeof(git_signature));
if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ")) != 0)
@@ -197,9 +146,6 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
text_len = buffer_end - ++buffer;
- if (tag->message != NULL)
- free(tag->message);
-
tag->message = git__malloc(text_len + 1);
memcpy(tag->message, buffer, text_len);
tag->message[text_len] = '\0';
@@ -207,26 +153,90 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end)
return GIT_SUCCESS;
}
-int git_tag__writeback(git_tag *tag, git_odb_source *src)
+int git_tag_create_o(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_object *target,
+ const git_signature *tagger,
+ const char *message)
{
- if (tag->tag_name == NULL || tag->tagger == NULL)
- return GIT_EMISSINGOBJDATA;
+ return git_tag_create(
+ oid, repo, tag_name,
+ git_object_id(target),
+ git_object_type(target),
+ tagger, message);
+}
- git__write_oid(src, "object", &tag->target);
- git__source_printf(src, "type %s\n", git_object_type2string(tag->type));
- git__source_printf(src, "tag %s\n", tag->tag_name);
- git_signature__write(src, "tagger", tag->tagger);
+int git_tag_create(
+ git_oid *oid,
+ git_repository *repo,
+ const char *tag_name,
+ const git_oid *target,
+ git_otype target_type,
+ const git_signature *tagger,
+ const char *message)
+{
+ size_t final_size = 0;
+ git_odb_stream *stream;
- if (tag->message != NULL)
- git__source_printf(src, "\n%s", tag->message);
+ const char *type_str;
+ char *tagger_str;
- return GIT_SUCCESS;
+ int type_str_len, tag_name_len, tagger_str_len, message_len;
+ int error;
+
+
+ type_str = git_object_type2string(target_type);
+
+ tagger_str_len = git_signature__write(&tagger_str, "tagger", tagger);
+
+ type_str_len = strlen(type_str);
+ tag_name_len = strlen(tag_name);
+ message_len = strlen(message);
+
+ final_size += GIT_OID_LINE_LENGTH("object");
+ final_size += STRLEN("type ") + type_str_len + 1;
+ final_size += STRLEN("tag ") + tag_name_len + 1;
+ final_size += tagger_str_len;
+ final_size += 1 + message_len;
+
+ if ((error = git_odb_open_wstream(&stream, repo->db, final_size, GIT_OBJ_TAG)) < GIT_SUCCESS)
+ return error;
+
+ git__write_oid(stream, "object", target);
+
+ stream->write(stream, "type ", STRLEN("type "));
+ stream->write(stream, type_str, type_str_len);
+
+ stream->write(stream, "\ntag ", STRLEN("\ntag "));
+ stream->write(stream, tag_name, tag_name_len);
+ stream->write(stream, "\n", 1);
+
+ stream->write(stream, tagger_str, tagger_str_len);
+ free(tagger_str);
+
+ stream->write(stream, "\n", 1);
+ stream->write(stream, message, message_len);
+
+
+ error = stream->finalize_write(oid, stream);
+ stream->free(stream);
+
+ if (error == GIT_SUCCESS) {
+ char ref_name[512];
+ git_reference *new_ref;
+ git__joinpath(ref_name, GIT_REFS_TAGS_DIR, tag_name);
+ error = git_reference_create_oid(&new_ref, repo, ref_name, oid);
+ }
+
+ return error;
}
-int git_tag__parse(git_tag *tag)
+int git_tag__parse(git_tag *tag, git_odb_object *obj)
{
- assert(tag && tag->object.source.open);
- return parse_tag_buffer(tag, tag->object.source.raw.data, (char *)tag->object.source.raw.data + tag->object.source.raw.len);
+ assert(tag);
+ return parse_tag_buffer(tag, obj->raw.data, (char *)obj->raw.data + obj->raw.len);
}
diff --git a/src/tag.h b/src/tag.h
index a1782d064..eddf8fa3a 100644
--- a/src/tag.h
+++ b/src/tag.h
@@ -3,6 +3,7 @@
#include "git2/tag.h"
#include "repository.h"
+#include "odb.h"
struct git_tag {
git_object object;
@@ -16,7 +17,6 @@ struct git_tag {
};
void git_tag__free(git_tag *tag);
-int git_tag__parse(git_tag *tag);
-int git_tag__writeback(git_tag *tag, git_odb_source *src);
+int git_tag__parse(git_tag *tag, git_odb_object *obj);
#endif
diff --git a/src/thread-utils.h b/src/thread-utils.h
index 1cf0e3407..e542639c8 100644
--- a/src/thread-utils.h
+++ b/src/thread-utils.h
@@ -8,7 +8,7 @@ typedef struct {
volatile int val;
} git_atomic;
-static inline void git_atomic_set(git_atomic *a, int val)
+GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
{
a->val = val;
}
@@ -36,7 +36,7 @@ static inline void git_atomic_set(git_atomic *a, int val)
#define git_cond_signal(c) (void)0 //pthread_cond_signal(c)
#define git_cond_broadcast(c) (void)0 //pthread_cond_broadcast(c)
-static inline int git_atomic_inc(git_atomic *a)
+GIT_INLINE(int) git_atomic_inc(git_atomic *a)
{
#ifdef __GNUC__
return __sync_add_and_fetch(&a->val, 1);
@@ -47,7 +47,7 @@ static inline int git_atomic_inc(git_atomic *a)
#endif
}
-static inline int git_atomic_dec(git_atomic *a)
+GIT_INLINE(int) git_atomic_dec(git_atomic *a)
{
#ifdef __GNUC__
return __sync_sub_and_fetch(&a->val, 1);
@@ -81,12 +81,12 @@ static inline int git_atomic_dec(git_atomic *a)
#define git_cond_signal(c) (void)0
#define git_cond_broadcast(c) (void)0
-static inline int git_atomic_inc(git_atomic *a)
+GIT_INLINE(int) git_atomic_inc(git_atomic *a)
{
return ++a->val;
}
-static inline int git_atomic_dec(git_atomic *a)
+GIT_INLINE(int) git_atomic_dec(git_atomic *a)
{
return --a->val;
}
diff --git a/src/tree.c b/src/tree.c
index 307d41b0d..31b286e69 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -41,9 +41,11 @@ int entry_search_cmp(const void *key, const void *array_member)
return strcmp(filename, entry->filename);
}
+#if 0
static int valid_attributes(const int attributes) {
return attributes >= 0 && attributes <= MAX_FILEMODE;
}
+#endif
int entry_sort_cmp(const void *a, const void *b)
{
@@ -56,13 +58,10 @@ int entry_sort_cmp(const void *a, const void *b)
entry_b->attr & 040000);
}
-void git_tree_clear_entries(git_tree *tree)
+void git_tree__free(git_tree *tree)
{
unsigned int i;
- if (tree == NULL)
- return;
-
for (i = 0; i < tree->entries.length; ++i) {
git_tree_entry *e;
e = git_vector_get(&tree->entries, i);
@@ -71,32 +70,6 @@ void git_tree_clear_entries(git_tree *tree)
free(e);
}
- git_vector_clear(&tree->entries);
- tree->object.modified = 1;
-}
-
-
-git_tree *git_tree__new(void)
-{
- git_tree *tree;
-
- tree = git__malloc(sizeof(struct git_tree));
- if (tree == NULL)
- return NULL;
-
- memset(tree, 0x0, sizeof(struct git_tree));
-
- if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS) {
- free(tree);
- return NULL;
- }
-
- return tree;
-}
-
-void git_tree__free(git_tree *tree)
-{
- git_tree_clear_entries(tree);
git_vector_free(&tree->entries);
free(tree);
}
@@ -106,37 +79,6 @@ const git_oid *git_tree_id(git_tree *c)
return git_object_id((git_object *)c);
}
-int git_tree_entry_set_attributes(git_tree_entry *entry, unsigned int attr)
-{
- assert(entry && entry->owner);
-
- if (!valid_attributes(attr)) {
- return GIT_ERROR;
- }
-
- entry->attr = attr;
- entry->owner->object.modified = 1;
- return GIT_SUCCESS;
-}
-
-void git_tree_entry_set_name(git_tree_entry *entry, const char *name)
-{
- assert(entry && entry->owner);
-
- free(entry->filename);
- entry->filename = git__strdup(name);
- git_vector_sort(&entry->owner->entries);
- entry->owner->object.modified = 1;
-}
-
-void git_tree_entry_set_id(git_tree_entry *entry, const git_oid *oid)
-{
- assert(entry && entry->owner);
-
- git_oid_cpy(&entry->oid, oid);
- entry->owner->object.modified = 1;
-}
-
unsigned int git_tree_entry_attributes(git_tree_entry *entry)
{
return entry->attr;
@@ -154,15 +96,10 @@ const git_oid *git_tree_entry_id(git_tree_entry *entry)
return &entry->oid;
}
-int git_tree_entry_2object(git_object **object_out, git_tree_entry *entry)
+int git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry)
{
assert(entry && object_out);
- return git_object_lookup(object_out, entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY);
-}
-
-static void sort_entries(git_tree *tree)
-{
- git_vector_sort(&tree->entries);
+ return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJ_ANY);
}
git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
@@ -171,8 +108,6 @@ git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
assert(tree && filename);
- sort_entries(tree);
-
idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename);
if (idx == GIT_ENOTFOUND)
return NULL;
@@ -183,9 +118,6 @@ git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename)
git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx)
{
assert(tree);
-
- sort_entries(tree);
-
return git_vector_get(&tree->entries, (unsigned int)idx);
}
@@ -195,107 +127,12 @@ size_t git_tree_entrycount(git_tree *tree)
return tree->entries.length;
}
-int git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes)
-{
- git_tree_entry *entry;
-
- assert(tree && id && filename);
- if (!valid_attributes(attributes)) {
- return GIT_ERROR;
- }
-
- if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL)
- return GIT_ENOMEM;
-
- memset(entry, 0x0, sizeof(git_tree_entry));
-
- entry->filename = git__strdup(filename);
- git_oid_cpy(&entry->oid, id);
- entry->attr = attributes;
- entry->owner = tree;
-
- if (git_vector_insert(&tree->entries, entry) < 0)
- return GIT_ENOMEM;
-
- if (entry_out != NULL)
- *entry_out = entry;
-
- tree->object.modified = 1;
- return GIT_SUCCESS;
-}
-
-int git_tree_remove_entry_byindex(git_tree *tree, int idx)
-{
- git_tree_entry *remove_ptr;
-
- assert(tree);
-
- sort_entries(tree);
-
- remove_ptr = git_vector_get(&tree->entries, (unsigned int)idx);
- if (remove_ptr == NULL)
- return GIT_ENOTFOUND;
-
- free(remove_ptr->filename);
- free(remove_ptr);
-
- tree->object.modified = 1;
-
- return git_vector_remove(&tree->entries, (unsigned int)idx);
-}
-
-int git_tree_remove_entry_byname(git_tree *tree, const char *filename)
-{
- int idx;
-
- assert(tree && filename);
-
- sort_entries(tree);
-
- idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename);
- if (idx == GIT_ENOTFOUND)
- return GIT_ENOTFOUND;
-
- return git_tree_remove_entry_byindex(tree, idx);
-}
-
-int git_tree__writeback(git_tree *tree, git_odb_source *src)
-{
- size_t i;
- char filemode[MAX_FILEMODE_BYTES + 1 + 1];
-
- assert(tree && src);
-
- if (tree->entries.length == 0)
- return GIT_EMISSINGOBJDATA;
-
- sort_entries(tree);
-
- for (i = 0; i < tree->entries.length; ++i) {
- git_tree_entry *entry;
-
- entry = git_vector_get(&tree->entries, i);
-
- snprintf(filemode, sizeof(filemode), "%o ", entry->attr);
-
- git__source_write(src, filemode, strlen(filemode));
- git__source_write(src, entry->filename, strlen(entry->filename) + 1);
- git__source_write(src, entry->oid.id, GIT_OID_RAWSZ);
- }
-
- return GIT_SUCCESS;
-}
-
-
static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)
{
- static const size_t avg_entry_size = 40;
- unsigned int expected_size;
int error = GIT_SUCCESS;
- expected_size = (tree->object.source.raw.len / avg_entry_size) + 1;
-
- git_tree_clear_entries(tree);
+ if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS)
+ return GIT_ENOMEM;
while (buffer < buffer_end) {
git_tree_entry *entry;
@@ -309,7 +146,6 @@ static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)
if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS)
return GIT_ENOMEM;
- entry->owner = tree;
entry->attr = strtol(buffer, &buffer, 8);
if (*buffer++ != ' ') {
@@ -336,16 +172,9 @@ static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end)
return error;
}
-int git_tree__parse(git_tree *tree)
+int git_tree__parse(git_tree *tree, git_odb_object *obj)
{
- char *buffer, *buffer_end;
-
- assert(tree && tree->object.source.open);
- assert(!tree->object.in_memory);
-
- buffer = tree->object.source.raw.data;
- buffer_end = buffer + tree->object.source.raw.len;
-
- return tree_parse_buffer(tree, buffer, buffer_end);
+ assert(tree);
+ return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len);
}
diff --git a/src/tree.h b/src/tree.h
index 78500c471..b4e910a9f 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -3,14 +3,13 @@
#include "git2/tree.h"
#include "repository.h"
+#include "odb.h"
#include "vector.h"
struct git_tree_entry {
unsigned int attr;
char *filename;
git_oid oid;
-
- git_tree *owner;
};
struct git_tree {
@@ -19,8 +18,6 @@ struct git_tree {
};
void git_tree__free(git_tree *tree);
-git_tree *git_tree__new(void);
-int git_tree__parse(git_tree *tree);
-int git_tree__writeback(git_tree *tree, git_odb_source *src);
+int git_tree__parse(git_tree *tree, git_odb_object *obj);
#endif
diff --git a/src/util.h b/src/util.h
index e0dfd7b20..653b34d02 100644
--- a/src/util.h
+++ b/src/util.h
@@ -97,6 +97,8 @@ extern char *git__strtok_keep(char *output, char *src, char *delimit);
#define STRLEN(str) (sizeof(str) - 1)
+#define GIT_OID_LINE_LENGTH(header) (STRLEN(header) + 1 + GIT_OID_HEXSZ + 1)
+
/*
* Realloc the buffer pointed at by variable 'x' so that it can hold
* at least 'nr' entries; the number of entries currently allocated