summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2011-11-28 18:44:47 +0100
committerVicent Marti <tanoku@gmail.com>2011-11-28 18:44:47 +0100
commitbb34a9362100ccdbfef10212dc9000f5800266d9 (patch)
tree1b26cee0c3d383043902c599893299fd8fdc5302 /src
parent880b6f0c22153db164ecb3a18c362ba8337365d3 (diff)
parentd88d4311c7e08ad0d38edae006b50e2a548c937d (diff)
downloadlibgit2-bb34a9362100ccdbfef10212dc9000f5800266d9.tar.gz
Merge branch 'repo-ownership' into development
Diffstat (limited to 'src')
-rw-r--r--src/blob.c25
-rw-r--r--src/commit.c7
-rw-r--r--src/common.h1
-rw-r--r--src/config.c15
-rw-r--r--src/config.h2
-rw-r--r--src/config_file.c3
-rw-r--r--src/fetch.c108
-rw-r--r--src/index.c53
-rw-r--r--src/index.h3
-rw-r--r--src/object.c31
-rw-r--r--src/odb.c24
-rw-r--r--src/odb.h2
-rw-r--r--src/pkt.c24
-rw-r--r--src/pkt.h4
-rw-r--r--src/refs.c21
-rw-r--r--src/remote.c53
-rw-r--r--src/remote.h2
-rw-r--r--src/repository.c583
-rw-r--r--src/repository.h12
-rw-r--r--src/revwalk.c15
-rw-r--r--src/status.c72
-rw-r--r--src/tag.c20
-rw-r--r--src/transport.c14
-rw-r--r--src/transport.h11
-rw-r--r--src/transports/git.c23
-rw-r--r--src/transports/http.c17
-rw-r--r--src/transports/local.c169
-rw-r--r--src/tree.c36
-rw-r--r--src/util.h43
29 files changed, 774 insertions, 619 deletions
diff --git a/src/blob.c b/src/blob.c
index f13a5be15..87f5686af 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -26,7 +26,7 @@ size_t git_blob_rawsize(git_blob *blob)
void git_blob__free(git_blob *blob)
{
- git_odb_object_close(blob->odb_object);
+ git_odb_object_free(blob->odb_object);
git__free(blob);
}
@@ -41,9 +41,14 @@ int git_blob__parse(git_blob *blob, git_odb_object *odb_obj)
int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len)
{
int error;
+ git_odb *odb;
git_odb_stream *stream;
- if ((error = git_odb_open_wstream(&stream, repo->db, len, GIT_OBJ_BLOB)) < GIT_SUCCESS)
+ error = git_repository_odb__weakptr(&odb, repo);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ if ((error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create blob");
if ((error = stream->write(stream, buffer, len)) < GIT_SUCCESS) {
@@ -69,11 +74,14 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
git_off_t size;
git_odb_stream *stream;
struct stat st;
+ const char *workdir;
+ git_odb *odb;
- if (repo->path_workdir == NULL)
+ workdir = git_repository_workdir(repo);
+ if (workdir == NULL)
return git__throw(GIT_ENOTFOUND, "Failed to create blob. (No working directory found)");
- git_path_join(full_path, repo->path_workdir, path);
+ git_path_join(full_path, workdir, path);
error = p_lstat(full_path, &st);
if (error < 0) {
@@ -83,11 +91,16 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
islnk = S_ISLNK(st.st_mode);
size = st.st_size;
- if (!islnk)
+ error = git_repository_odb__weakptr(&odb, repo);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ if (!islnk) {
if ((fd = p_open(full_path, O_RDONLY)) < 0)
return git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", full_path);
+ }
- if ((error = git_odb_open_wstream(&stream, repo->db, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS) {
+ if ((error = git_odb_open_wstream(&stream, odb, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS) {
if (!islnk)
p_close(fd);
return git__rethrow(error, "Failed to create blob");
diff --git a/src/commit.c b/src/commit.c
index 83bc9fc4c..bf6ca7855 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -103,6 +103,7 @@ int git_commit_create(
{
git_buf commit = GIT_BUF_INIT;
int error, i;
+ git_odb *odb;
if (git_object_owner((const git_object *)tree) != repo)
return git__throw(GIT_EINVALIDARGS, "The given tree does not belong to this repository");
@@ -132,7 +133,11 @@ int git_commit_create(
goto cleanup;
}
- error = git_odb_write(oid, git_repository_database(repo), commit.ptr, commit.size, GIT_OBJ_COMMIT);
+ error = git_repository_odb__weakptr(&odb, repo);
+ if (error < GIT_SUCCESS)
+ goto cleanup;
+
+ error = git_odb_write(oid, odb, commit.ptr, commit.size, GIT_OBJ_COMMIT);
git_buf_free(&commit);
if (error == GIT_SUCCESS && update_ref != NULL) {
diff --git a/src/common.h b/src/common.h
index 727a08e77..35316012d 100644
--- a/src/common.h
+++ b/src/common.h
@@ -60,4 +60,5 @@ extern void git___rethrow(const char *, ...) GIT_FORMAT_PRINTF(1, 2);
#include "util.h"
+
#endif /* INCLUDE_common_h__ */
diff --git a/src/config.c b/src/config.c
index 4e48ff7f4..a8e15405b 100644
--- a/src/config.c
+++ b/src/config.c
@@ -22,15 +22,12 @@ typedef struct {
int priority;
} file_internal;
-void git_config_free(git_config *cfg)
+static void config_free(git_config *cfg)
{
unsigned int i;
git_config_file *file;
file_internal *internal;
- if (cfg == NULL)
- return;
-
for(i = 0; i < cfg->files.length; ++i){
internal = git_vector_get(&cfg->files, i);
file = internal->file;
@@ -42,6 +39,14 @@ void git_config_free(git_config *cfg)
git__free(cfg);
}
+void git_config_free(git_config *cfg)
+{
+ if (cfg == NULL)
+ return;
+
+ GIT_REFCOUNT_DEC(cfg, config_free);
+}
+
static int config_backend_cmp(const void *a, const void *b)
{
const file_internal *bk_a = (const file_internal *)(a);
@@ -66,7 +71,7 @@ int git_config_new(git_config **out)
}
*out = cfg;
-
+ GIT_REFCOUNT_INC(cfg);
return GIT_SUCCESS;
}
diff --git a/src/config.h b/src/config.h
index 43574a586..7f3494edc 100644
--- a/src/config.h
+++ b/src/config.h
@@ -17,8 +17,8 @@
#define GIT_CONFIG_FILE_MODE 0666
struct git_config {
+ git_refcount rc;
git_vector files;
- git_repository *repo;
};
#endif
diff --git a/src/config_file.c b/src/config_file.c
index 5e862d487..7a5865210 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -256,6 +256,7 @@ static int config_open(git_config_file *cfg)
diskfile_backend *b = (diskfile_backend *)cfg;
error = git_futils_readbuffer(&b->reader.buffer, b->file_path);
+
/* It's fine if the file doesn't exist */
if (error == GIT_ENOTFOUND)
return GIT_SUCCESS;
@@ -269,7 +270,7 @@ static int config_open(git_config_file *cfg)
git_futils_freebuffer(&b->reader.buffer);
- return error;
+ return GIT_SUCCESS;
cleanup:
cvar_list_free(&b->var_list);
diff --git a/src/fetch.c b/src/fetch.c
index a42732925..f447248c5 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -18,83 +18,62 @@
#include "fetch.h"
#include "netops.h"
-static int filter_wants(git_remote *remote)
-{
- git_vector list;
- git_headarray refs;
- git_remote_head *head;
- git_transport *t = remote->transport;
- git_repository *repo = remote->repo;
+struct filter_payload {
+ git_remote *remote;
const git_refspec *spec;
- int error;
- unsigned int i = 0;
+ git_odb *odb;
+ int found_head;
+};
- error = git_vector_init(&list, 16, NULL);
- if (error < GIT_SUCCESS)
- return error;
+static int filter_ref__cb(git_remote_head *head, void *payload)
+{
+ struct filter_payload *p = payload;
+ int error;
- error = t->ls(t, &refs);
- if (error < GIT_SUCCESS) {
- error = git__rethrow(error, "Failed to get remote ref list");
- goto cleanup;
- }
+ if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) {
+ p->found_head = 1;
+ } else {
+ /* If it doesn't match the refpec, we don't want it */
+ error = git_refspec_src_match(p->spec, head->name);
- /*
- * The fetch refspec can be NULL, and what this means is that the
- * user didn't specify one. This is fine, as it means that we're
- * not interested in any particular branch but just the remote's
- * HEAD, which will be stored in FETCH_HEAD after the fetch.
- */
- spec = git_remote_fetchspec(remote);
+ if (error == GIT_ENOMATCH)
+ return GIT_SUCCESS;
- /*
- * We need to handle HEAD separately, as we always want it, but it
- * probably won't matcht he refspec.
- */
- head = refs.heads[0];
- if (refs.len > 0 && !strcmp(head->name, GIT_HEAD_FILE)) {
- if (git_odb_exists(repo->db, &head->oid))
- head->local = 1;
- else
- remote->need_pack = 1;
-
- i = 1;
- error = git_vector_insert(&list, refs.heads[0]);
if (error < GIT_SUCCESS)
- goto cleanup;
+ return git__rethrow(error, "Error matching remote ref name");
}
- for (; i < refs.len; ++i) {
- head = refs.heads[i];
+ /* If we have the object, mark it so we don't ask for it */
+ if (git_odb_exists(p->odb, &head->oid))
+ head->local = 1;
+ else
+ p->remote->need_pack = 1;
- /* If it doesn't match the refpec, we don't want it */
- error = git_refspec_src_match(spec, head->name);
- if (error == GIT_ENOMATCH)
- continue;
- if (error < GIT_SUCCESS) {
- error = git__rethrow(error, "Error matching remote ref name");
- goto cleanup;
- }
+ return git_vector_insert(&p->remote->refs, head);
+}
- /* If we have the object, mark it so we don't ask for it */
- if (git_odb_exists(repo->db, &head->oid))
- head->local = 1;
- else
- remote->need_pack = 1;
+static int filter_wants(git_remote *remote)
+{
+ int error;
+ struct filter_payload p;
- error = git_vector_insert(&list, head);
- if (error < GIT_SUCCESS)
- goto cleanup;
- }
+ git_vector_clear(&remote->refs);
- remote->refs.len = list.length;
- remote->refs.heads = (git_remote_head **) list.contents;
+ /*
+ * The fetch refspec can be NULL, and what this means is that the
+ * user didn't specify one. This is fine, as it means that we're
+ * not interested in any particular branch but just the remote's
+ * HEAD, which will be stored in FETCH_HEAD after the fetch.
+ */
+ p.spec = git_remote_fetchspec(remote);
+ p.found_head = 0;
+ p.remote = remote;
- return GIT_SUCCESS;
+ error = git_repository_odb__weakptr(&p.odb, remote->repo);
+ if (error < GIT_SUCCESS)
+ return error;
-cleanup:
- git_vector_free(&list);
- return error;
+ return remote->transport->ls(remote->transport, &filter_ref__cb, &p);
}
/*
@@ -112,8 +91,9 @@ int git_fetch_negotiate(git_remote *remote)
return git__rethrow(error, "Failed to filter the reference list for wants");
/* Don't try to negotiate when we don't want anything */
- if (remote->refs.len == 0)
+ if (remote->refs.length == 0)
return GIT_SUCCESS;
+
if (!remote->need_pack)
return GIT_SUCCESS;
diff --git a/src/index.c b/src/index.c
index aad117164..d01262b39 100644
--- a/src/index.c
+++ b/src/index.c
@@ -31,6 +31,8 @@ static const unsigned int INDEX_HEADER_SIG = 0x44495243;
static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'};
static const char INDEX_EXT_UNMERGED_SIG[] = {'R', 'E', 'U', 'C'};
+#define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx)))
+
struct index_header {
uint32_t signature;
uint32_t version;
@@ -124,7 +126,7 @@ static unsigned int index_create_mode(unsigned int mode)
return S_IFREG | ((mode & 0100) ? 0755 : 0644);
}
-static int index_initialize(git_index **index_out, git_repository *owner, const char *index_path)
+int git_index_open(git_index **index_out, const char *index_path)
{
git_index *index;
@@ -142,8 +144,6 @@ static int index_initialize(git_index **index_out, git_repository *owner, const
return GIT_ENOMEM;
}
- index->repository = owner;
-
git_vector_init(&index->entries, 32, index_cmp);
/* Check if index file is stored on disk already */
@@ -151,23 +151,18 @@ static int index_initialize(git_index **index_out, git_repository *owner, const
index->on_disk = 1;
*index_out = index;
+ GIT_REFCOUNT_INC(index);
return git_index_read(index);
}
-int git_index_open(git_index **index_out, const char *index_path)
+static void index_free(git_index *index)
{
- return index_initialize(index_out, NULL, index_path);
-}
-
-/*
- * Moved from `repository.c`
- */
-int git_repository_index(git_index **index_out, git_repository *repo)
-{
- if (repo->is_bare)
- return git__throw(GIT_EBAREINDEX, "Failed to open index. Repository is bare");
+ git_index_clear(index);
+ git_vector_free(&index->entries);
+ git_vector_free(&index->unmerged);
- return index_initialize(index_out, repo, repo->path_index);
+ git__free(index->index_file_path);
+ git__free(index);
}
void git_index_free(git_index *index)
@@ -175,12 +170,7 @@ void git_index_free(git_index *index)
if (index == NULL)
return;
- git_index_clear(index);
- git_vector_free(&index->entries);
- git_vector_free(&index->unmerged);
-
- git__free(index->index_file_path);
- git__free(index);
+ GIT_REFCOUNT_DEC(index, index_free);
}
void git_index_clear(git_index *index)
@@ -298,20 +288,29 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const
struct stat st;
git_oid oid;
int error;
+ const char *workdir;
+
+ if (INDEX_OWNER(index) == NULL)
+ return git__throw(GIT_EBAREINDEX,
+ "Failed to initialize entry. Repository is bare");
- if (index->repository == NULL)
- return git__throw(GIT_EBAREINDEX, "Failed to initialize entry. Repository is bare");
+ workdir = git_repository_workdir(INDEX_OWNER(index));
+ if (workdir == NULL)
+ return git__throw(GIT_EBAREINDEX,
+ "Failed to initialize entry. Cannot resolved workdir");
- git_path_join(full_path, index->repository->path_workdir, rel_path);
+ git_path_join(full_path, workdir, rel_path);
if (p_lstat(full_path, &st) < 0)
- return git__throw(GIT_ENOTFOUND, "Failed to initialize entry. '%s' cannot be opened", full_path);
+ return git__throw(GIT_ENOTFOUND,
+ "Failed to initialize entry. '%s' cannot be opened", full_path);
if (stage < 0 || stage > 3)
- return git__throw(GIT_ERROR, "Failed to initialize entry. Invalid stage %i", stage);
+ return git__throw(GIT_ERROR,
+ "Failed to initialize entry. Invalid stage %i", stage);
/* write the blob to disk and get the oid */
- if ((error = git_blob_create_fromfile(&oid, index->repository, rel_path)) < GIT_SUCCESS)
+ if ((error = git_blob_create_fromfile(&oid, INDEX_OWNER(index), rel_path)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to initialize index entry");
entry = git__malloc(sizeof(git_index_entry));
diff --git a/src/index.h b/src/index.h
index a1cd3403e..9464afb6c 100644
--- a/src/index.h
+++ b/src/index.h
@@ -18,7 +18,8 @@
#define GIT_INDEX_FILE_MODE 0666
struct git_index {
- git_repository *repository;
+ git_refcount rc;
+
char *index_file_path;
time_t last_modified;
diff --git a/src/object.c b/src/object.c
index c84e94b05..95c7cf9d2 100644
--- a/src/object.c
+++ b/src/object.c
@@ -77,9 +77,15 @@ static int create_object(git_object **object_out, git_otype type)
return GIT_SUCCESS;
}
-int git_object_lookup_prefix(git_object **object_out, git_repository *repo, const git_oid *id, unsigned int len, git_otype type)
+int git_object_lookup_prefix(
+ git_object **object_out,
+ git_repository *repo,
+ const git_oid *id,
+ unsigned int len,
+ git_otype type)
{
git_object *object = NULL;
+ git_odb *odb = NULL;
git_odb_object *odb_obj;
int error = GIT_SUCCESS;
@@ -89,6 +95,10 @@ int git_object_lookup_prefix(git_object **object_out, git_repository *repo, cons
return git__throw(GIT_EAMBIGUOUSOIDPREFIX,
"Failed to lookup object. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN);
+ error = git_repository_odb__weakptr(&odb, repo);
+ if (error < GIT_SUCCESS)
+ return error;
+
if (len > GIT_OID_HEXSZ)
len = GIT_OID_HEXSZ;
@@ -98,10 +108,11 @@ int git_object_lookup_prefix(git_object **object_out, git_repository *repo, cons
*/
object = git_cache_get(&repo->objects, id);
if (object != NULL) {
- if (type != GIT_OBJ_ANY && type != object->type)
- {
- git_object_close(object);
- return git__throw(GIT_EINVALIDTYPE, "Failed to lookup object. The given type does not match the type on the ODB");
+ if (type != GIT_OBJ_ANY && type != object->type) {
+ git_object_free(object);
+ return git__throw(GIT_EINVALIDTYPE,
+ "Failed to lookup object. "
+ "The given type does not match the type on the ODB");
}
*object_out = object;
@@ -113,7 +124,7 @@ int git_object_lookup_prefix(git_object **object_out, git_repository *repo, cons
* it is the same cost for packed and loose object backends,
* but it may be much more costly for sqlite and hiredis.
*/
- error = git_odb_read(&odb_obj, repo->db, id);
+ error = git_odb_read(&odb_obj, odb, id);
} else {
git_oid short_oid;
@@ -133,14 +144,14 @@ int git_object_lookup_prefix(git_object **object_out, git_repository *repo, cons
* - We never explore the cache, go right to exploring the backends
* We chose the latter : we explore directly the backends.
*/
- error = git_odb_read_prefix(&odb_obj, repo->db, &short_oid, len);
+ error = git_odb_read_prefix(&odb_obj, odb, &short_oid, len);
}
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to lookup object");
if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) {
- git_odb_object_close(odb_obj);
+ git_odb_object_free(odb_obj);
return git__throw(GIT_EINVALIDTYPE, "Failed to lookup object. The given type does not match the type on the ODB");
}
@@ -174,7 +185,7 @@ int git_object_lookup_prefix(git_object **object_out, git_repository *repo, cons
break;
}
- git_odb_object_close(odb_obj);
+ git_odb_object_free(odb_obj);
if (error < GIT_SUCCESS) {
git_object__free(object);
@@ -218,7 +229,7 @@ void git_object__free(void *_obj)
}
}
-void git_object_close(git_object *object)
+void git_object_free(git_object *object)
{
if (object == NULL)
return;
diff --git a/src/odb.c b/src/odb.c
index 69fdba009..d31f93f73 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -108,7 +108,7 @@ git_otype git_odb_object_type(git_odb_object *object)
return object->raw.type;
}
-void git_odb_object_close(git_odb_object *object)
+void git_odb_object_free(git_odb_object *object)
{
git_cached_obj_decref((git_cached_obj *)object, &free_odb_object);
}
@@ -275,6 +275,7 @@ int git_odb_new(git_odb **out)
}
*out = db;
+ GIT_REFCOUNT_INC(db);
return GIT_SUCCESS;
}
@@ -405,17 +406,14 @@ int git_odb_open(git_odb **out, const char *objects_dir)
return GIT_SUCCESS;
cleanup:
- git_odb_close(db);
+ git_odb_free(db);
return error; /* error already set - pass through */
}
-void git_odb_close(git_odb *db)
+static void odb_free(git_odb *db)
{
unsigned int i;
- if (db == NULL)
- return;
-
for (i = 0; i < db->backends.length; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *backend = internal->backend;
@@ -431,6 +429,14 @@ void git_odb_close(git_odb *db)
git__free(db);
}
+void git_odb_free(git_odb *db)
+{
+ if (db == NULL)
+ return;
+
+ GIT_REFCOUNT_DEC(db, odb_free);
+}
+
int git_odb_exists(git_odb *db, const git_oid *id)
{
git_odb_object *object;
@@ -440,7 +446,7 @@ int git_odb_exists(git_odb *db, const git_oid *id)
assert(db && id);
if ((object = git_cache_get(&db->cache, id)) != NULL) {
- git_odb_object_close(object);
+ git_odb_object_free(object);
return 1;
}
@@ -466,7 +472,7 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git
if ((object = git_cache_get(&db->cache, id)) != NULL) {
*len_p = object->raw.len;
*type_p = object->raw.type;
- git_odb_object_close(object);
+ git_odb_object_free(object);
return GIT_SUCCESS;
}
@@ -491,7 +497,7 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git
*len_p = object->raw.len;
*type_p = object->raw.type;
- git_odb_object_close(object);
+ git_odb_object_free(object);
}
return GIT_SUCCESS;
diff --git a/src/odb.h b/src/odb.h
index 833739e99..b81533001 100644
--- a/src/odb.h
+++ b/src/odb.h
@@ -33,7 +33,7 @@ struct git_odb_object {
/* EXPORT */
struct git_odb {
- void *_internal;
+ git_refcount rc;
git_vector backends;
git_cache cache;
};
diff --git a/src/pkt.c b/src/pkt.c
index ff8c56eb2..9dfc40255 100644
--- a/src/pkt.c
+++ b/src/pkt.c
@@ -316,30 +316,30 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps,
* is overwrite the OID each time.
*/
-int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf *buf)
+int git_pkt_buffer_wants(const git_vector *refs, git_transport_caps *caps, git_buf *buf)
{
unsigned int i = 0;
int error;
git_remote_head *head;
if (caps->common) {
- for (; i < refs->len; ++i) {
- head = refs->heads[i];
+ for (; i < refs->length; ++i) {
+ head = refs->contents[i];
if (!head->local)
break;
}
- error = buffer_want_with_caps(refs->heads[i], caps, buf);
+ error = buffer_want_with_caps(refs->contents[i], caps, buf);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to buffer want with caps");
i++;
}
- for (; i < refs->len; ++i) {
+ for (; i < refs->length; ++i) {
char oid[GIT_OID_HEXSZ];
- head = refs->heads[i];
+ head = refs->contents[i];
if (head->local)
continue;
@@ -352,7 +352,7 @@ int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf
return git_pkt_buffer_flush(buf);
}
-int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd)
+int git_pkt_send_wants(const git_vector *refs, git_transport_caps *caps, int fd)
{
unsigned int i = 0;
int error = GIT_SUCCESS;
@@ -365,15 +365,15 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd)
/* If there are common caps, find the first one */
if (caps->common) {
- for (; i < refs->len; ++i) {
- head = refs->heads[i];
+ for (; i < refs->length; ++i) {
+ head = refs->contents[i];
if (head->local)
continue;
else
break;
}
- error = send_want_with_caps(refs->heads[i], caps, fd);
+ error = send_want_with_caps(refs->contents[i], caps, fd);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send want pkt with caps");
/* Increase it here so it's correct whether we run this or not */
@@ -381,8 +381,8 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd)
}
/* Continue from where we left off */
- for (; i < refs->len; ++i) {
- head = refs->heads[i];
+ for (; i < refs->length; ++i) {
+ head = refs->contents[i];
if (head->local)
continue;
diff --git a/src/pkt.h b/src/pkt.h
index 88711f2d8..7ce9c6cd9 100644
--- a/src/pkt.h
+++ b/src/pkt.h
@@ -68,8 +68,8 @@ int git_pkt_buffer_flush(git_buf *buf);
int git_pkt_send_flush(int s);
int git_pkt_buffer_done(git_buf *buf);
int git_pkt_send_done(int s);
-int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf *buf);
-int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd);
+int git_pkt_buffer_wants(const git_vector *refs, git_transport_caps *caps, git_buf *buf);
+int git_pkt_send_wants(const git_vector *refs, git_transport_caps *caps, int fd);
int git_pkt_buffer_have(git_oid *oid, git_buf *buf);
int git_pkt_send_have(git_oid *oid, int fd);
void git_pkt_free(git_pkt *pkt);
diff --git a/src/refs.c b/src/refs.c
index 2374cc72f..8931d5bac 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -686,7 +686,7 @@ static int packed_find_peel(git_repository *repo, struct packref *ref)
*/
}
- git_object_close(object);
+ git_object_free(object);
return GIT_SUCCESS;
}
@@ -1195,7 +1195,8 @@ cleanup:
*/
int git_reference_set_oid(git_reference *ref, const git_oid *id)
{
- int error = GIT_SUCCESS;
+ int error = GIT_SUCCESS, exists;
+ git_odb *odb = NULL;
if ((ref->flags & GIT_REF_OID) == 0)
return git__throw(GIT_EINVALIDREFSTATE,
@@ -1203,23 +1204,29 @@ int git_reference_set_oid(git_reference *ref, const git_oid *id)
assert(ref->owner);
+ error = git_repository_odb__weakptr(&odb, ref->owner);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ exists = git_odb_exists(odb, id);
+
+ git_odb_free(odb);
+
/* Don't let the user create references to OIDs that
* don't exist in the ODB */
- if (!git_odb_exists(git_repository_database(ref->owner), id))
+ if (!exists)
return git__throw(GIT_ENOTFOUND,
"Failed to set OID target of reference. OID doesn't exist in ODB");
/* Update the OID value on `ref` */
git_oid_cpy(&ref->target.oid, id);
+ /* Write back to disk */
error = loose_write(ref);
if (error < GIT_SUCCESS)
- goto cleanup;
+ return git__rethrow(error, "Failed to set OID target of reference");
return GIT_SUCCESS;
-
-cleanup:
- return git__rethrow(error, "Failed to set OID target of reference");
}
/*
diff --git a/src/remote.c b/src/remote.c
index a222023d8..75e861681 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -70,16 +70,21 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *url, cons
memset(remote, 0x0, sizeof(git_remote));
remote->repo = repo;
+ if (git_vector_init(&remote->refs, 32, NULL) < 0) {
+ git_remote_free(remote);
+ return GIT_ENOMEM;
+ }
+
remote->url = git__strdup(url);
if (remote->url == NULL) {
- git__free(remote);
+ git_remote_free(remote);
return GIT_ENOMEM;
}
if (name != NULL) {
remote->name = git__strdup(name);
if (remote->name == NULL) {
- git__free(remote);
+ git_remote_free(remote);
return GIT_ENOMEM;
}
}
@@ -88,14 +93,19 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *url, cons
return GIT_SUCCESS;
}
-int git_remote_get(git_remote **out, git_config *cfg, const char *name)
+int git_remote_load(git_remote **out, git_repository *repo, const char *name)
{
git_remote *remote;
char *buf = NULL;
const char *val;
int ret, error, buf_len;
+ git_config *config;
- assert(out && cfg && name);
+ assert(out && repo && name);
+
+ error = git_repository_config__weakptr(&config, repo);
+ if (error < GIT_SUCCESS)
+ return error;
remote = git__malloc(sizeof(git_remote));
if (remote == NULL)
@@ -108,6 +118,11 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name)
goto cleanup;
}
+ if (git_vector_init(&remote->refs, 32, NULL) < 0) {
+ error = GIT_ENOMEM;
+ goto cleanup;
+ }
+
/* "fetch" is the longest var name we're interested in */
buf_len = strlen("remote.") + strlen(".fetch") + strlen(name) + 1;
buf = git__malloc(buf_len);
@@ -122,13 +137,13 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name)
goto cleanup;
}
- error = git_config_get_string(cfg, buf, &val);
+ error = git_config_get_string(config, buf, &val);
if (error < GIT_SUCCESS) {
error = git__rethrow(error, "Remote's url doesn't exist");
goto cleanup;
}
- remote->repo = cfg->repo;
+ remote->repo = repo;
remote->url = git__strdup(val);
if (remote->url == NULL) {
error = GIT_ENOMEM;
@@ -141,7 +156,7 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name)
goto cleanup;
}
- error = parse_remote_refspec(cfg, &remote->fetch, buf);
+ error = parse_remote_refspec(config, &remote->fetch, buf);
if (error < GIT_SUCCESS) {
error = git__rethrow(error, "Failed to get fetch refspec");
goto cleanup;
@@ -153,7 +168,7 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name)
goto cleanup;
}
- error = parse_remote_refspec(cfg, &remote->push, buf);
+ error = parse_remote_refspec(config, &remote->push, buf);
/* Not finding push is fine */
if (error == GIT_ENOTFOUND)
error = GIT_SUCCESS;
@@ -165,6 +180,7 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name)
cleanup:
git__free(buf);
+
if (error < GIT_SUCCESS)
git_remote_free(remote);
@@ -221,10 +237,14 @@ cleanup:
return error;
}
-int git_remote_ls(git_remote *remote, git_headarray *refs)
+int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
{
- assert(remote && refs);
- return remote->transport->ls(remote->transport, refs);
+ assert(remote);
+
+ if (!remote->transport)
+ return git__throw(GIT_ERROR, "The remote is not connected");
+
+ return remote->transport->ls(remote->transport, list_cb, payload);
}
int git_remote_download(char **filename, git_remote *remote)
@@ -244,7 +264,7 @@ int git_remote_update_tips(git_remote *remote)
int error = GIT_SUCCESS;
unsigned int i = 0;
char refname[GIT_PATH_MAX];
- git_headarray *refs = &remote->refs;
+ git_vector *refs = &remote->refs;
git_remote_head *head;
git_reference *ref;
struct git_refspec *spec = &remote->fetch;
@@ -253,11 +273,11 @@ int git_remote_update_tips(git_remote *remote)
memset(refname, 0x0, sizeof(refname));
- if (refs->len == 0)
+ if (refs->length == 0)
return GIT_SUCCESS;
/* HEAD is only allowed to be the first in the list */
- head = refs->heads[0];
+ head = refs->contents[0];
if (!strcmp(head->name, GIT_HEAD_FILE)) {
error = git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1);
i = 1;
@@ -266,8 +286,8 @@ int git_remote_update_tips(git_remote *remote)
return git__rethrow(error, "Failed to update FETCH_HEAD");
}
- for (; i < refs->len; ++i) {
- head = refs->heads[i];
+ for (; i < refs->length; ++i) {
+ head = refs->contents[i];
error = git_refspec_transform(refname, sizeof(refname), spec, head->name);
if (error < GIT_SUCCESS)
@@ -313,6 +333,7 @@ void git_remote_free(git_remote *remote)
git__free(remote->push.dst);
git__free(remote->url);
git__free(remote->name);
+ git_vector_free(&remote->refs);
git_remote_disconnect(remote);
git__free(remote);
}
diff --git a/src/remote.h b/src/remote.h
index 4b1db6c4e..a24e14845 100644
--- a/src/remote.h
+++ b/src/remote.h
@@ -14,7 +14,7 @@
struct git_remote {
char *name;
char *url;
- git_headarray refs;
+ git_vector refs;
struct git_refspec fetch;
struct git_refspec push;
git_transport *transport;
diff --git a/src/repository.c b/src/repository.c
index f8195e2d9..f1a37c945 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -24,118 +24,57 @@
#define GIT_BRANCH_MASTER "master"
-/*
- * Git repository open methods
- *
- * Open a repository object from its path
- */
-static int assign_repository_dirs(
- git_repository *repo,
- const char *git_dir,
- const char *git_object_directory,
- const char *git_index_file,
- const char *git_work_tree)
-{
- char path_aux[GIT_PATH_MAX];
- int error = GIT_SUCCESS;
-
- assert(repo);
-
- if (git_dir == NULL)
- return git__throw(GIT_ENOTFOUND, "Failed to open repository. Git dir not found");
-
- error = git_path_prettify_dir(path_aux, git_dir, NULL);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to open repository");
- /* store GIT_DIR */
- repo->path_repository = git__strdup(path_aux);
- if (repo->path_repository == NULL)
- return GIT_ENOMEM;
-
- /* path to GIT_OBJECT_DIRECTORY */
- if (git_object_directory == NULL)
- git_path_join(path_aux, repo->path_repository, GIT_OBJECTS_DIR);
- else {
- error = git_path_prettify_dir(path_aux, git_object_directory, NULL);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to open repository");
+static void drop_odb(git_repository *repo)
+{
+ if (repo->_odb != NULL) {
+ GIT_REFCOUNT_OWN(repo->_odb, NULL);
+ git_odb_free(repo->_odb);
+ repo->_odb = NULL;
}
+}
- /* Store GIT_OBJECT_DIRECTORY */
- repo->path_odb = git__strdup(path_aux);
- if (repo->path_odb == NULL)
- return GIT_ENOMEM;
-
- /* path to GIT_WORK_TREE */
- if (git_work_tree == NULL)
- repo->is_bare = 1;
- else {
- error = git_path_prettify_dir(path_aux, git_work_tree, NULL);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to open repository");
-
- /* Store GIT_WORK_TREE */
- repo->path_workdir = git__strdup(path_aux);
- if (repo->path_workdir == NULL)
- return GIT_ENOMEM;
-
- /* Path to GIT_INDEX_FILE */
- if (git_index_file == NULL)
- git_path_join(path_aux, repo->path_repository, GIT_INDEX_FILE);
- else {
- error = git_path_prettify(path_aux, git_index_file, NULL);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to open repository");
- }
-
- /* store GIT_INDEX_FILE */
- repo->path_index = git__strdup(path_aux);
- if (repo->path_index == NULL)
- return GIT_ENOMEM;
+static void drop_config(git_repository *repo)
+{
+ if (repo->_config != NULL) {
+ GIT_REFCOUNT_OWN(repo->_config, NULL);
+ git_config_free(repo->_config);
+ repo->_config = NULL;
}
-
- return GIT_SUCCESS;
}
-static int check_repository_dirs(git_repository *repo)
+static void drop_index(git_repository *repo)
{
- char path_aux[GIT_PATH_MAX];
-
- if (git_futils_isdir(repo->path_repository) < GIT_SUCCESS)
- return git__throw(GIT_ENOTAREPO, "`%s` is not a folder", repo->path_repository);
-
- /* Ensure GIT_OBJECT_DIRECTORY exists */
- if (git_futils_isdir(repo->path_odb) < GIT_SUCCESS)
- return git__throw(GIT_ENOTAREPO, "`%s` does not exist", repo->path_odb);
-
- /* Ensure HEAD file exists */
- git_path_join(path_aux, repo->path_repository, GIT_HEAD_FILE);
- if (git_futils_isfile(path_aux) < 0)
- return git__throw(GIT_ENOTAREPO, "HEAD file is missing");
-
- return GIT_SUCCESS;
+ if (repo->_index != NULL) {
+ GIT_REFCOUNT_OWN(repo->_index, NULL);
+ git_index_free(repo->_index);
+ repo->_index = NULL;
+ }
}
-static int guess_repository_dirs(git_repository *repo, const char *repository_path)
+void git_repository_free(git_repository *repo)
{
- char buffer[GIT_PATH_MAX];
- const char *path_work_tree = NULL;
+ if (repo == NULL)
+ return;
- /* Git directory name */
- if (git_path_basename_r(buffer, sizeof(buffer), repository_path) < 0)
- return git__throw(GIT_EINVALIDPATH, "Unable to parse folder name from `%s`", repository_path);
+ git_cache_free(&repo->objects);
+ git_repository__refcache_free(&repo->references);
- if (strcmp(buffer, DOT_GIT) == 0) {
- /* Path to working dir */
- if (git_path_dirname_r(buffer, sizeof(buffer), repository_path) < 0)
- return git__throw(GIT_EINVALIDPATH, "Unable to parse parent folder name from `%s`", repository_path);
- path_work_tree = buffer;
- }
+ git__free(repo->path_repository);
+ git__free(repo->workdir);
- return assign_repository_dirs(repo, repository_path, NULL, NULL, path_work_tree);
+ drop_config(repo);
+ drop_index(repo);
+ drop_odb(repo);
+
+ git__free(repo);
}
+/*
+ * Git repository open methods
+ *
+ * Open a repository object from its path
+ */
static int quickcheck_repository_dir(const char *repository_path)
{
char path_aux[GIT_PATH_MAX];
@@ -156,6 +95,7 @@ static int quickcheck_repository_dir(const char *repository_path)
return GIT_SUCCESS;
}
+
static git_repository *repository_alloc(void)
{
int error;
@@ -175,94 +115,97 @@ static git_repository *repository_alloc(void)
return repo;
}
-static int init_odb(git_repository *repo)
+static int load_config_data(git_repository *repo)
{
- return git_odb_open(&repo->db, repo->path_odb);
-}
+ int error, is_bare;
+ git_config *config;
-int git_repository_open3(git_repository **repo_out,
- const char *git_dir,
- git_odb *object_database,
- const char *git_index_file,
- const char *git_work_tree)
-{
- git_repository *repo;
- int error = GIT_SUCCESS;
+ error = git_repository_config__weakptr(&config, repo);
+ if (error < GIT_SUCCESS)
+ return error;
- assert(repo_out);
+ error = git_config_get_bool(config, "core.bare", &is_bare);
+ if (error == GIT_SUCCESS)
+ repo->is_bare = is_bare;
- if (object_database == NULL)
- return git__throw(GIT_EINVALIDARGS, "Failed to open repository. `object_database` can't be null");
+ /* TODO: what else can we load/cache here? */
- repo = repository_alloc();
- if (repo == NULL)
- return GIT_ENOMEM;
+ return GIT_SUCCESS;
+}
- error = assign_repository_dirs(repo,
- git_dir,
- NULL,
- git_index_file,
- git_work_tree);
+static int load_workdir(git_repository *repo)
+{
+ if (!repo->is_bare) {
+ char workdir_buf[GIT_PATH_MAX];
- if (error < GIT_SUCCESS)
- goto cleanup;
+ if (git_path_dirname_r(workdir_buf, sizeof(workdir_buf), repo->path_repository) < 0)
+ return git__throw(GIT_EOSERR,
+ "Failed to resolved working directory");
- error = check_repository_dirs(repo);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ git_path_join(workdir_buf, workdir_buf, "");
- repo->db = object_database;
+ repo->workdir = git__strdup(workdir_buf);
+ if (repo->workdir == NULL)
+ return GIT_ENOMEM;
+ }
- *repo_out = repo;
return GIT_SUCCESS;
-
-cleanup:
- git_repository_free(repo);
- return git__rethrow(error, "Failed to open repository");
}
-
-int git_repository_open2(git_repository **repo_out,
- const char *git_dir,
- const char *git_object_directory,
- const char *git_index_file,
- const char *git_work_tree)
+int git_repository_open(git_repository **repo_out, const char *path)
{
- git_repository *repo;
int error = GIT_SUCCESS;
+ char path_buf[GIT_PATH_MAX];
+ size_t path_len;
+ git_repository *repo = NULL;
- assert(repo_out);
+ error = git_path_prettify_dir(path_buf, path, NULL);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to open repository");
+
+ path_len = strlen(path_buf);
+
+ /**
+ * Check if the path we've been given is actually the path
+ * of the working dir, by testing if it contains a `.git`
+ * folder inside of it.
+ */
+ git_path_join(path_buf, path_buf, DOT_GIT);
+ if (git_futils_isdir(path_buf) < GIT_SUCCESS) {
+ path_buf[path_len] = 0;
+ }
+
+ if (quickcheck_repository_dir(path_buf) < GIT_SUCCESS)
+ return git__throw(GIT_ENOTAREPO,
+ "The given path is not a valid Git repository");
repo = repository_alloc();
if (repo == NULL)
return GIT_ENOMEM;
- error = assign_repository_dirs(repo,
- git_dir,
- git_object_directory,
- git_index_file,
- git_work_tree);
-
- if (error < GIT_SUCCESS)
- goto cleanup;
+ repo->path_repository = git__strdup(path_buf);
+ if (repo->path_repository == NULL) {
+ git_repository_free(repo);
+ return GIT_ENOMEM;
+ }
- error = check_repository_dirs(repo);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ error = load_config_data(repo);
+ if (error < GIT_SUCCESS) {
+ git_repository_free(repo);
+ return error;
+ }
- error = init_odb(repo);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ error = load_workdir(repo);
+ if (error < GIT_SUCCESS) {
+ git_repository_free(repo);
+ return error;
+ }
*repo_out = repo;
return GIT_SUCCESS;
-
-cleanup:
- git_repository_free(repo);
- return git__rethrow(error, "Failed to open repository");
}
-int git_repository_config(
+static int load_config(
git_config **out,
git_repository *repo,
const char *global_config_path,
@@ -270,98 +213,178 @@ int git_repository_config(
{
char config_path[GIT_PATH_MAX];
int error;
+ git_config *cfg = NULL;
- assert(out && repo);
+ assert(repo && out);
- error = git_config_new(out);
+ error = git_config_new(&cfg);
if (error < GIT_SUCCESS)
return error;
git_path_join(config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO);
- error = git_config_add_file_ondisk(*out, config_path, 3);
+ error = git_config_add_file_ondisk(cfg, config_path, 3);
if (error < GIT_SUCCESS)
goto cleanup;
if (global_config_path != NULL) {
- error = git_config_add_file_ondisk(*out, global_config_path, 2);
+ error = git_config_add_file_ondisk(cfg, global_config_path, 2);
if (error < GIT_SUCCESS)
goto cleanup;
}
if (system_config_path != NULL) {
- error = git_config_add_file_ondisk(*out, system_config_path, 1);
+ error = git_config_add_file_ondisk(cfg, system_config_path, 1);
if (error < GIT_SUCCESS)
goto cleanup;
}
- (*out)->repo = repo;
+ *out = cfg;
return GIT_SUCCESS;
cleanup:
- git_config_free(*out);
+ git_config_free(cfg);
+ *out = NULL;
return error;
}
-int git_repository_config_autoload(
- git_config **out,
- git_repository *repo)
+int git_repository_config__weakptr(git_config **out, git_repository *repo)
{
- char global[GIT_PATH_MAX], system[GIT_PATH_MAX];
- char *global_path, *system_path;
- int error;
+ if (repo->_config == NULL) {
+ int error;
+ char buf_global[GIT_PATH_MAX], buf_system[GIT_PATH_MAX];
- error = git_config_find_global(global);
- global_path = error < GIT_SUCCESS ? NULL : global;
+ const char *global_config_path = NULL;
+ const char *system_config_path = NULL;
- error = git_config_find_system(system);
- system_path = error < GIT_SUCCESS ? NULL : system;
+ if (git_config_find_global(buf_global) == GIT_SUCCESS)
+ global_config_path = buf_global;
+
+ if (git_config_find_system(buf_system) == GIT_SUCCESS)
+ system_config_path = buf_system;
+
+ error = load_config(&repo->_config, repo, global_config_path, system_config_path);
+ if (error < GIT_SUCCESS)
+ return error;
- return git_repository_config(out, repo, global_path, system_path);
+ GIT_REFCOUNT_OWN(repo->_config, repo);
+ }
+
+ *out = repo->_config;
+ return GIT_SUCCESS;
}
-static int discover_repository_dirs(git_repository *repo, const char *path)
+int git_repository_config(git_config **out, git_repository *repo)
{
- int error;
+ int error = git_repository_config__weakptr(out, repo);
- error = guess_repository_dirs(repo, path);
- if (error < GIT_SUCCESS)
- return error;
+ if (error == GIT_SUCCESS) {
+ GIT_REFCOUNT_INC(*out);
+ }
- error = check_repository_dirs(repo);
- if (error < GIT_SUCCESS)
- return error;
+ return error;
+}
+
+void git_repository_set_config(git_repository *repo, git_config *config)
+{
+ assert(repo && config);
+
+ drop_config(repo);
+
+ repo->_config = config;
+ GIT_REFCOUNT_OWN(repo->_config, repo);
+}
+
+int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
+{
+ assert(repo && out);
+
+ if (repo->_odb == NULL) {
+ int error;
+ char odb_path[GIT_PATH_MAX];
+
+ git_path_join(odb_path, repo->path_repository, GIT_OBJECTS_DIR);
+
+ error = git_odb_open(&repo->_odb, odb_path);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ GIT_REFCOUNT_OWN(repo->_odb, repo);
+ }
+ GIT_REFCOUNT_INC(repo->_odb);
+ *out = repo->_odb;
return GIT_SUCCESS;
}
-int git_repository_open(git_repository **repo_out, const char *path)
+int git_repository_odb(git_odb **out, git_repository *repo)
{
- git_repository *repo;
- int error = GIT_SUCCESS;
+ int error = git_repository_odb__weakptr(out, repo);
- assert(repo_out && path);
+ if (error == GIT_SUCCESS) {
+ GIT_REFCOUNT_INC(*out);
+ }
- repo = repository_alloc();
- if (repo == NULL)
- return GIT_ENOMEM;
+ return error;
+}
- error = discover_repository_dirs(repo, path);
- if (error < GIT_SUCCESS)
- goto cleanup;
+void git_repository_set_odb(git_repository *repo, git_odb *odb)
+{
+ assert(repo && odb);
- error = init_odb(repo);
- if (error < GIT_SUCCESS)
- goto cleanup;
+ drop_odb(repo);
- *repo_out = repo;
+ repo->_odb = odb;
+ GIT_REFCOUNT_OWN(repo->_odb, repo);
+}
+
+int git_repository_index__weakptr(git_index **out, git_repository *repo)
+{
+ assert(out && repo);
+
+ if (repo->is_bare)
+ return git__throw(GIT_EBAREINDEX, "Cannot open index in bare repository");
+
+ if (repo->_index == NULL) {
+ int error;
+ char index_path[GIT_PATH_MAX];
+
+ git_path_join(index_path, repo->path_repository, GIT_INDEX_FILE);
+
+ error = git_index_open(&repo->_index, index_path);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ GIT_REFCOUNT_OWN(repo->_index, repo);
+ }
+
+ GIT_REFCOUNT_INC(repo->_index);
+ *out = repo->_index;
return GIT_SUCCESS;
+}
-cleanup:
- git_repository_free(repo);
- return git__rethrow(error, "Failed to open repository");
+int git_repository_index(git_index **out, git_repository *repo)
+{
+ int error = git_repository_index__weakptr(out, repo);
+
+ if (error == GIT_SUCCESS) {
+ GIT_REFCOUNT_INC(*out);
+ }
+
+ return error;
}
+void git_repository_set_index(git_repository *repo, git_index *index)
+{
+ assert(repo && index);
+
+ drop_index(repo);
+
+ repo->_index = index;
+ GIT_REFCOUNT_OWN(repo->_index, repo);
+}
+
+
static int retrieve_device(dev_t *device_out, const char *path)
{
struct stat path_info;
@@ -460,34 +483,12 @@ static int read_gitfile(char *path_out, const char *file_path, const char *base_
return git__throw(GIT_EOBJCORRUPTED, "The `.git` file points to an inexisting path");
}
-static void git_repository__free_dirs(git_repository *repo)
-{
- git__free(repo->path_workdir);
- repo->path_workdir = NULL;
- git__free(repo->path_index);
- repo->path_index = NULL;
- git__free(repo->path_repository);
- repo->path_repository = NULL;
- git__free(repo->path_odb);
- repo->path_odb = NULL;
-}
-
-void git_repository_free(git_repository *repo)
-{
- if (repo == NULL)
- return;
-
- git_cache_free(&repo->objects);
- git_repository__refcache_free(&repo->references);
- git_repository__free_dirs(repo);
-
- if (repo->db != NULL)
- git_odb_close(repo->db);
-
- git__free(repo);
-}
-
-int git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs)
+int git_repository_discover(
+ char *repository_path,
+ size_t size,
+ const char *start_path,
+ int across_fs,
+ const char *ceiling_dirs)
{
int error, ceiling_offset;
char bare_path[GIT_PATH_MAX];
@@ -519,11 +520,13 @@ int git_repository_discover(char *repository_path, size_t size, const char *star
error = read_gitfile(repository_path, normal_path, bare_path);
if (error < GIT_SUCCESS)
- return git__rethrow(error, "Unable to read git file `%s`", normal_path);
+ return git__rethrow(error,
+ "Unable to read git file `%s`", normal_path);
error = quickcheck_repository_dir(repository_path);
if (error < GIT_SUCCESS)
- return git__throw(GIT_ENOTFOUND, "The `.git` file found at '%s' points"
+ return git__throw(GIT_ENOTFOUND,
+ "The `.git` file found at '%s' points"
"to an inexisting Git folder", normal_path);
return GIT_SUCCESS;
@@ -558,7 +561,8 @@ int git_repository_discover(char *repository_path, size_t size, const char *star
error = retrieve_device(&new_device, normal_path);
if (error < GIT_SUCCESS || current_device != new_device) {
- return git__throw(GIT_ENOTAREPO,"Not a git repository (or any parent up to mount parent %s)\n"
+ return git__throw(GIT_ENOTAREPO,
+ "Not a git repository (or any parent up to mount parent %s)\n"
"Stopping at filesystem boundary.", bare_path);
}
current_device = new_device;
@@ -569,42 +573,66 @@ int git_repository_discover(char *repository_path, size_t size, const char *star
// nothing has been found, lets try the parent directory
if (bare_path[ceiling_offset] == '\0') {
- return git__throw(GIT_ENOTAREPO,"Not a git repository (or any of the parent directories): %s", start_path);
+ return git__throw(GIT_ENOTAREPO,
+ "Not a git repository (or any of the parent directories): %s", start_path);
}
}
if (size < strlen(found_path) + 2) {
- return git__throw(GIT_ESHORTBUFFER, "The repository buffer is not long enough to handle the repository path `%s`", found_path);
+ return git__throw(GIT_ESHORTBUFFER,
+ "The repository buffer is not long enough to handle the repository path `%s`", found_path);
}
git_path_join(repository_path, found_path, "");
return GIT_SUCCESS;
}
-git_odb *git_repository_database(git_repository *repo)
-{
- assert(repo);
- return repo->db;
-}
-
static int repo_init_reinit(const char *repository_path, int is_bare)
{
/* TODO: reinit the repository */
return git__throw(GIT_ENOTIMPLEMENTED,
"Failed to reinitialize the %srepository at '%s'. "
"This feature is not yet implemented",
- is_bare ? "bare" : "", repository_path);
+ is_bare ? "bare " : "", repository_path);
}
-static int repo_init_createhead(git_repository *repo)
+static int repo_init_createhead(const char *git_dir)
{
- int error;
- git_reference *head_reference;
+ char ref_path[GIT_PATH_MAX];
+ git_filebuf ref = GIT_FILEBUF_INIT;
+
+ git_path_join(ref_path, git_dir, GIT_HEAD_FILE);
+
+ git_filebuf_open(&ref, ref_path, 0);
+ git_filebuf_printf(&ref, "ref: refs/heads/master\n");
+
+ return git_filebuf_commit(&ref, GIT_REFS_FILE_MODE);
+}
+
+static int repo_init_config(const char *git_dir, int is_bare)
+{
+ char cfg_path[GIT_PATH_MAX];
+ git_config *config;
+ int error = GIT_SUCCESS;
+
+#define SET_REPO_CONFIG(type, name, val) {\
+ error = git_config_set_##type(config, name, val);\
+ if (error < GIT_SUCCESS)\
+ goto cleanup;\
+}
- error = git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE, 0);
+ git_path_join(cfg_path, git_dir, GIT_CONFIG_FILENAME_INREPO);
- git_reference_free(head_reference);
+ error = git_config_open_ondisk(&config, cfg_path);
+ if (error < GIT_SUCCESS)
+ return error;
+ SET_REPO_CONFIG(bool, "core.bare", is_bare);
+ SET_REPO_CONFIG(int32, "core.repositoryformatversion", 0);
+ /* TODO: what other defaults? */
+
+cleanup:
+ git_config_free(config);
return error;
}
@@ -674,31 +702,15 @@ int git_repository_init(git_repository **repo_out, const char *path, unsigned is
if (error < GIT_SUCCESS)
goto cleanup;
- repo = repository_alloc();
- if (repo == NULL) {
- error = GIT_ENOMEM;
- goto cleanup;
- }
-
- error = guess_repository_dirs(repo, repository_path);
+ error = repo_init_config(repository_path, is_bare);
if (error < GIT_SUCCESS)
goto cleanup;
- assert(repo->is_bare == is_bare);
-
- error = init_odb(repo);
- if (error < GIT_SUCCESS)
- goto cleanup;
-
- error = repo_init_createhead(repo);
+ error = repo_init_createhead(repository_path);
if (error < GIT_SUCCESS)
goto cleanup;
- /* should never fail */
- assert(check_repository_dirs(repo) == GIT_SUCCESS);
-
- *repo_out = repo;
- return GIT_SUCCESS;
+ return git_repository_open(repo_out, repository_path);
cleanup:
git_repository_free(repo);
@@ -709,8 +721,13 @@ int git_repository_head_detached(git_repository *repo)
{
git_reference *ref;
int error;
- size_t GIT_UNUSED(_size);
+ size_t _size;
git_otype type;
+ git_odb *odb = NULL;
+
+ error = git_repository_odb__weakptr(&odb, repo);
+ if (error < GIT_SUCCESS)
+ return error;
error = git_reference_lookup(&ref, repo, GIT_HEAD_FILE);
if (error < GIT_SUCCESS)
@@ -721,7 +738,7 @@ int git_repository_head_detached(git_repository *repo)
return 0;
}
- error = git_odb_read_header(&_size, &type, repo->db, git_reference_oid(ref));
+ error = git_odb_read_header(&_size, &type, odb, git_reference_oid(ref));
git_reference_free(ref);
@@ -797,26 +814,34 @@ int git_repository_is_empty(git_repository *repo)
return error == GIT_ENOTFOUND ? 1 : error;
}
-const char *git_repository_path(git_repository *repo, git_repository_pathid id)
+const char *git_repository_path(git_repository *repo)
{
assert(repo);
+ return repo->path_repository;
+}
- switch (id) {
- case GIT_REPO_PATH:
- return repo->path_repository;
+const char *git_repository_workdir(git_repository *repo)
+{
+ assert(repo);
- case GIT_REPO_PATH_INDEX:
- return repo->path_index;
+ if (repo->is_bare)
+ return NULL;
- case GIT_REPO_PATH_ODB:
- return repo->path_odb;
+ return repo->workdir;
+}
- case GIT_REPO_PATH_WORKDIR:
- return repo->path_workdir;
+int git_repository_set_workdir(git_repository *repo, const char *workdir)
+{
+ assert(repo && workdir);
- default:
- return NULL;
- }
+ free(repo->workdir);
+
+ repo->workdir = git__strdup(workdir);
+ if (repo->workdir == NULL)
+ return GIT_ENOMEM;
+
+ repo->is_bare = 0;
+ return GIT_SUCCESS;
}
int git_repository_is_bare(git_repository *repo)
diff --git a/src/repository.h b/src/repository.h
index 0c17958fd..c3a9a5c60 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -32,15 +32,15 @@ struct git_object {
};
struct git_repository {
- git_odb *db;
+ git_odb *_odb;
+ git_config *_config;
+ git_index *_index;
git_cache objects;
git_refcache references;
char *path_repository;
- char *path_index;
- char *path_odb;
- char *path_workdir;
+ char *workdir;
unsigned is_bare:1;
unsigned int lru_counter;
@@ -53,4 +53,8 @@ void git_object__free(void *object);
int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header);
void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid);
+int git_repository_config__weakptr(git_config **out, git_repository *repo);
+int git_repository_odb__weakptr(git_odb **out, git_repository *repo);
+int git_repository_index__weakptr(git_index **out, git_repository *repo);
+
#endif
diff --git a/src/revwalk.c b/src/revwalk.c
index 7e31650ff..d632a19b8 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -34,6 +34,7 @@ typedef struct commit_list {
struct git_revwalk {
git_repository *repo;
+ git_odb *odb;
git_hashtable *commits;
@@ -225,16 +226,16 @@ static int commit_parse(git_revwalk *walk, commit_object *commit)
if (commit->parsed)
return GIT_SUCCESS;
- if ((error = git_odb_read(&obj, walk->repo->db, &commit->oid)) < GIT_SUCCESS)
+ if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to parse commit. Can't read object");
if (obj->raw.type != GIT_OBJ_COMMIT) {
- git_odb_object_close(obj);
+ git_odb_object_free(obj);
return git__throw(GIT_EOBJTYPE, "Failed to parse commit. Object is no commit object");
}
error = commit_quick_parse(walk, commit, &obj->raw);
- git_odb_object_close(obj);
+ git_odb_object_free(obj);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse commit");
}
@@ -429,6 +430,7 @@ static int prepare_walk(git_revwalk *walk)
int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
{
+ int error;
git_revwalk *walk;
walk = git__malloc(sizeof(git_revwalk));
@@ -455,6 +457,12 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
walk->repo = repo;
+ error = git_repository_odb(&walk->odb, repo);
+ if (error < GIT_SUCCESS) {
+ git_revwalk_free(walk);
+ return error;
+ }
+
*revwalk_out = walk;
return GIT_SUCCESS;
}
@@ -469,6 +477,7 @@ void git_revwalk_free(git_revwalk *walk)
return;
git_revwalk_reset(walk);
+ git_odb_free(walk->odb);
/* if the parent has more than PARENTS_PER_COMMIT parents,
* we had to allocate a separate array for those parents.
diff --git a/src/status.c b/src/status.c
index d50199d9a..97093a553 100644
--- a/src/status.c
+++ b/src/status.c
@@ -162,7 +162,7 @@ static int retrieve_head_tree(git_tree **tree_out, git_repository *repo)
*tree_out = tree;
exit:
- git_commit_close(head_commit);
+ git_commit_free(head_commit);
return error;
}
@@ -214,7 +214,7 @@ static int process_folder(struct status_st *st, const git_tree_entry *tree_entry
}
if (tree_entry_type == GIT_OBJ_TREE) {
- git_object_close(subtree);
+ git_object_free(subtree);
st->head_tree_relative_path_len -= 1 + tree_entry->filename_len;
st->tree = pushed_tree;
st->tree_position = pushed_tree_position;
@@ -410,9 +410,15 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
unsigned int i;
git_tree *tree;
struct status_entry *e;
+ const char *workdir;
- if ((error = git_repository_index(&index, repo)) < GIT_SUCCESS) {
- return git__rethrow(error, "Failed to determine statuses. Index can't be opened");
+ if ((workdir = git_repository_workdir(repo)) == NULL)
+ return git__throw(GIT_ERROR,
+ "Cannot retrieve status on a bare repository");
+
+ if ((error = git_repository_index__weakptr(&index, repo)) < GIT_SUCCESS) {
+ return git__rethrow(error,
+ "Failed to determine statuses. Index can't be opened");
}
if ((error = retrieve_head_tree(&tree, repo)) < GIT_SUCCESS) {
@@ -422,7 +428,7 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
git_vector_init(&entries, DEFAULT_SIZE, status_cmp);
- dirent_st.workdir_path_len = strlen(repo->path_workdir);
+ dirent_st.workdir_path_len = strlen(workdir);
dirent_st.tree_position = 0;
dirent_st.index_position = 0;
dirent_st.tree = tree;
@@ -432,18 +438,29 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
dirent_st.head_tree_relative_path_len = 0;
dirent_st.is_dir = 1;
- strcpy(temp_path, repo->path_workdir);
+ strcpy(temp_path, workdir);
if (git_futils_isdir(temp_path)) {
- error = git__throw(GIT_EINVALIDPATH, "Failed to determine status of file '%s'. Provided path doesn't lead to a folder", temp_path);
+ error = git__throw(GIT_EINVALIDPATH,
+ "Failed to determine status of file '%s'. "
+ "The given path doesn't lead to a folder", temp_path);
goto exit;
}
- if ((error = alphasorted_futils_direach(temp_path, sizeof(temp_path), dirent_cb, &dirent_st)) < GIT_SUCCESS)
- error = git__rethrow(error, "Failed to determine statuses. An error occured while processing the working directory");
+ error = alphasorted_futils_direach(
+ temp_path, sizeof(temp_path),
+ dirent_cb, &dirent_st
+ );
+
+ if (error < GIT_SUCCESS)
+ error = git__rethrow(error,
+ "Failed to determine statuses. "
+ "An error occured while processing the working directory");
if ((error == GIT_SUCCESS) && ((error = dirent_cb(&dirent_st, NULL)) < GIT_SUCCESS))
- error = git__rethrow(error, "Failed to determine statuses. An error occured while post-processing the HEAD tree and the index");
+ error = git__rethrow(error,
+ "Failed to determine statuses. "
+ "An error occured while post-processing the HEAD tree and the index");
for (i = 0; i < entries.length; ++i) {
e = (struct status_entry *)git_vector_get(&entries, i);
@@ -451,7 +468,8 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
if (error == GIT_SUCCESS) {
error = callback(e->path, e->status_flags, payload);
if (error < GIT_SUCCESS)
- error = git__rethrow(error, "Failed to determine statuses. User callback failed");
+ error = git__rethrow(error,
+ "Failed to determine statuses. User callback failed");
}
git__free(e);
@@ -459,8 +477,7 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig
exit:
git_vector_free(&entries);
- git_tree_close(tree);
- git_index_free(index);
+ git_tree_free(tree);
return error;
}
@@ -495,7 +512,7 @@ static int recurse_tree_entry(git_tree *tree, struct status_entry *e, const char
return git__throw(GIT_EOBJCORRUPTED, "Can't find tree object '%s'", tree_entry->filename);
error = recurse_tree_entry(subtree, e, dir_sep+1);
- git_tree_close(subtree);
+ git_tree_free(subtree);
return error;
}
@@ -506,12 +523,19 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
char temp_path[GIT_PATH_MAX];
int error = GIT_SUCCESS;
git_tree *tree = NULL;
+ const char *workdir;
assert(status_flags && repo && path);
- git_path_join(temp_path, repo->path_workdir, path);
+ if ((workdir = git_repository_workdir(repo)) == NULL)
+ return git__throw(GIT_ERROR,
+ "Cannot retrieve status on a bare repository");
+
+ git_path_join(temp_path, workdir, path);
if (git_futils_isdir(temp_path) == GIT_SUCCESS)
- return git__throw(GIT_EINVALIDPATH, "Failed to determine status of file '%s'. Provided path leads to a folder, not a file", path);
+ return git__throw(GIT_EINVALIDPATH,
+ "Failed to determine status of file '%s'. "
+ "Given path leads to a folder, not a file", path);
e = status_entry_new(NULL, path);
if (e == NULL)
@@ -524,16 +548,18 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
}
/* Find file in Index */
- if ((error = git_repository_index(&index, repo)) < GIT_SUCCESS) {
- error = git__rethrow(error, "Failed to determine status of file '%s'. Index can't be opened", path);
+ if ((error = git_repository_index__weakptr(&index, repo)) < GIT_SUCCESS) {
+ error = git__rethrow(error,
+ "Failed to determine status of file '%s'."
+ "Index can't be opened", path);
goto exit;
}
status_entry_update_from_index(e, index);
- git_index_free(index);
if ((error = retrieve_head_tree(&tree, repo)) < GIT_SUCCESS) {
- error = git__rethrow(error, "Failed to determine status of file '%s'", path);
+ error = git__rethrow(error,
+ "Failed to determine status of file '%s'", path);
goto exit;
}
@@ -543,7 +569,9 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
error = recurse_tree_entry(tree, e, temp_path);
if (error < GIT_SUCCESS) {
- error = git__rethrow(error, "Failed to determine status of file '%s'. An error occured while processing the tree", path);
+ error = git__rethrow(error,
+ "Failed to determine status of file '%s'. "
+ "An error occured while processing the tree", path);
goto exit;
}
}
@@ -557,7 +585,7 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char
*status_flags = e->status_flags;
exit:
- git_tree_close(tree);
+ git_tree_free(tree);
git__free(e);
return error;
}
diff --git a/src/tag.c b/src/tag.c
index 7372e68c7..16d46ce16 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -175,6 +175,7 @@ static int write_tag_annotation(
{
int error = GIT_SUCCESS;
git_buf tag = GIT_BUF_INIT;
+ git_odb *odb;
git_oid__writebuf(&tag, "object ", git_object_id(target));
git_buf_printf(&tag, "type %s\n", git_object_type2string(git_object_type(target)));
@@ -188,7 +189,13 @@ static int write_tag_annotation(
return git__throw(GIT_ENOMEM, "Not enough memory to build the tag data");
}
- error = git_odb_write(oid, git_repository_database(repo), tag.ptr, tag.size, GIT_OBJ_TAG);
+ error = git_repository_odb__weakptr(&odb, repo);
+ if (error < GIT_SUCCESS) {
+ git_buf_free(&tag);
+ return error;
+ }
+
+ error = git_odb_write(oid, odb, tag.ptr, tag.size, GIT_OBJ_TAG);
git_buf_free(&tag);
if (error < GIT_SUCCESS)
@@ -286,6 +293,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
{
git_tag tag;
int error, should_update_ref = 0;
+ git_odb *odb;
git_odb_stream *stream;
git_odb_object *target_obj;
@@ -296,18 +304,22 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
memset(&tag, 0, sizeof(tag));
+ error = git_repository_odb__weakptr(&odb, repo);
+ if (error < GIT_SUCCESS)
+ return error;
+
/* validate the buffer */
if ((error = parse_tag_buffer(&tag, buffer, buffer + strlen(buffer))) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag");
/* validate the target */
- if ((error = git_odb_read(&target_obj, repo->db, &tag.target)) < GIT_SUCCESS)
+ if ((error = git_odb_read(&target_obj, odb, &tag.target)) < GIT_SUCCESS)
return git__rethrow(error, "Failed to create tag");
if (tag.type != target_obj->raw.type)
return git__throw(error, "The type for the given target is invalid");
- git_odb_object_close(target_obj);
+ git_odb_object_free(target_obj);
error = retrieve_tag_reference(&new_ref, ref_name, repo, tag.tag_name);
@@ -334,7 +346,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu
}
/* write the buffer */
- if ((error = git_odb_open_wstream(&stream, repo->db, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) {
+ if ((error = git_odb_open_wstream(&stream, odb, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) {
git_reference_free(new_ref);
return git__rethrow(error, "Failed to create tag");
}
diff --git a/src/transport.c b/src/transport.c
index 0d67e1967..d836561b4 100644
--- a/src/transport.c
+++ b/src/transport.c
@@ -6,7 +6,7 @@
*/
#include "common.h"
#include "git2/types.h"
-#include "git2/transport.h"
+#include "git2/remote.h"
#include "git2/net.h"
#include "transport.h"
@@ -49,11 +49,6 @@ int git_transport_dummy(git_transport **GIT_UNUSED(transport))
return git__throw(GIT_ENOTIMPLEMENTED, "This protocol isn't implemented. Sorry");
}
-int git_transport_valid_url(const char *url)
-{
- return transport_find_fn(url) != NULL;
-}
-
int git_transport_new(git_transport **out, const char *url)
{
git_transport_cb fn;
@@ -81,3 +76,10 @@ int git_transport_new(git_transport **out, const char *url)
return GIT_SUCCESS;
}
+
+/* from remote.h */
+int git_remote_valid_url(const char *url)
+{
+ return transport_find_fn(url) != NULL;
+}
+
diff --git a/src/transport.h b/src/transport.h
index 23b83b690..2ed8ad32a 100644
--- a/src/transport.h
+++ b/src/transport.h
@@ -7,7 +7,6 @@
#ifndef INCLUDE_transport_h__
#define INCLUDE_transport_h__
-#include "git2/transport.h"
#include "git2/net.h"
#include "vector.h"
@@ -61,7 +60,7 @@ struct git_transport {
/**
* Give a list of references, useful for ls-remote
*/
- int (*ls)(struct git_transport *transport, git_headarray *headarray);
+ int (*ls)(struct git_transport *transport, git_headlist_cb list_cb, void *opaque);
/**
* Push the changes over
*/
@@ -74,7 +73,7 @@ struct git_transport {
* Negotiate the minimal amount of objects that need to be
* retrieved
*/
- int (*negotiate_fetch)(struct git_transport *transport, git_repository *repo, git_headarray *list);
+ int (*negotiate_fetch)(struct git_transport *transport, git_repository *repo, const git_vector *wants);
/**
* Send a flush
*/
@@ -97,9 +96,15 @@ struct git_transport {
void (*free)(struct git_transport *transport);
};
+
+int git_transport_new(struct git_transport **transport, const char *url);
int git_transport_local(struct git_transport **transport);
int git_transport_git(struct git_transport **transport);
int git_transport_http(struct git_transport **transport);
int git_transport_dummy(struct git_transport **transport);
+int git_transport_valid_url(const char *url);
+
+typedef struct git_transport git_transport;
+typedef int (*git_transport_cb)(git_transport **transport);
#endif
diff --git a/src/transports/git.c b/src/transports/git.c
index 2ee2e4831..bdb94d090 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -226,32 +226,30 @@ cleanup:
return error;
}
-static int git_ls(git_transport *transport, git_headarray *array)
+static int git_ls(git_transport *transport, git_headlist_cb list_cb, void *opaque)
{
transport_git *t = (transport_git *) transport;
git_vector *refs = &t->refs;
- int len = 0;
unsigned int i;
+ git_pkt *p = NULL;
- array->heads = git__calloc(refs->length, sizeof(git_remote_head *));
- if (array->heads == NULL)
- return GIT_ENOMEM;
+ git_vector_foreach(refs, i, p) {
+ git_pkt_ref *pkt = NULL;
- for (i = 0; i < refs->length; ++i) {
- git_pkt *p = git_vector_get(refs, i);
if (p->type != GIT_PKT_REF)
continue;
- ++len;
- array->heads[i] = &(((git_pkt_ref *) p)->head);
+ pkt = (git_pkt_ref *)p;
+
+ if (list_cb(&pkt->head, opaque) < 0)
+ return git__throw(GIT_ERROR,
+ "The user callback returned an error code");
}
- array->len = len;
- t->heads = array->heads;
return GIT_SUCCESS;
}
-static int git_negotiate_fetch(git_transport *transport, git_repository *repo, git_headarray *wants)
+static int git_negotiate_fetch(git_transport *transport, git_repository *repo, const git_vector *wants)
{
transport_git *t = (transport_git *) transport;
git_revwalk *walk;
@@ -290,6 +288,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g
if (git_reference_type(ref) == GIT_REF_SYMBOLIC)
continue;
+
error = git_revwalk_push(walk, git_reference_oid(ref));
if (error < GIT_ERROR) {
error = git__rethrow(error, "Failed to push %s", refs.strings[i]);
diff --git a/src/transports/http.c b/src/transports/http.c
index ae0c56a73..e463a0f59 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -301,29 +301,22 @@ cleanup:
return error;
}
-static int http_ls(git_transport *transport, git_headarray *array)
+static int http_ls(git_transport *transport, git_headlist_cb list_cb, void *opaque)
{
transport_http *t = (transport_http *) transport;
git_vector *refs = &t->refs;
unsigned int i;
- int len = 0;
git_pkt_ref *p;
- array->heads = git__calloc(refs->length, sizeof(git_remote_head*));
- if (array->heads == NULL)
- return GIT_ENOMEM;
-
git_vector_foreach(refs, i, p) {
if (p->type != GIT_PKT_REF)
continue;
- array->heads[len] = &p->head;
- len++;
+ if (list_cb(&p->head, opaque) < 0)
+ return git__throw(GIT_ERROR,
+ "The user callback returned an error code");
}
- array->len = len;
- t->heads = array->heads;
-
return GIT_SUCCESS;
}
@@ -470,7 +463,7 @@ cleanup:
return error;
}
-static int http_negotiate_fetch(git_transport *transport, git_repository *repo, git_headarray *wants)
+static int http_negotiate_fetch(git_transport *transport, git_repository *repo, const git_vector *wants)
{
transport_http *t = (transport_http *) transport;
int error;
diff --git a/src/transports/local.c b/src/transports/local.c
index 058ed7e79..f50a96173 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -6,7 +6,6 @@
*/
#include "common.h"
#include "git2/types.h"
-#include "git2/transport.h"
#include "git2/net.h"
#include "git2/repository.h"
#include "git2/object.h"
@@ -18,39 +17,10 @@
typedef struct {
git_transport parent;
git_repository *repo;
- git_vector *refs;
+ git_vector refs;
} transport_local;
-/*
- * Try to open the url as a git directory. The direction doesn't
- * matter in this case because we're calulating the heads ourselves.
- */
-static int local_connect(git_transport *transport, int GIT_UNUSED(direction))
-{
- git_repository *repo;
- int error;
- transport_local *t = (transport_local *) transport;
- const char *path;
- const char file_prefix[] = "file://";
- GIT_UNUSED_ARG(direction);
-
- /* The repo layer doesn't want the prefix */
- if (!git__prefixcmp(transport->url, file_prefix))
- path = transport->url + strlen(file_prefix);
- else
- path = transport->url;
-
- error = git_repository_open(&repo, path);
- if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to open remote");
-
- t->repo = repo;
- t->parent.connected = 1;
-
- return GIT_SUCCESS;
-}
-
-static int add_ref(const char *name, git_repository *repo, git_vector *vec)
+static int add_ref(transport_local *t, const char *name)
{
const char peeled[] = "^{}";
git_remote_head *head;
@@ -68,7 +38,7 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec)
goto out;
}
- error = git_reference_lookup(&ref, repo, name);
+ error = git_reference_lookup(&ref, t->repo, name);
if (error < GIT_SUCCESS)
goto out;
@@ -78,15 +48,17 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec)
git_oid_cpy(&head->oid, git_reference_oid(ref));
- error = git_vector_insert(vec, head);
+ error = git_vector_insert(&t->refs, head);
if (error < GIT_SUCCESS)
goto out;
+ head = NULL;
+
/* If it's not a tag, we don't need to try to peel it */
if (git__prefixcmp(name, GIT_REFS_TAGS_DIR))
goto out;
- error = git_object_lookup(&obj, repo, &head->oid, GIT_OBJ_ANY);
+ error = git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJ_ANY);
if (error < GIT_SUCCESS) {
git__rethrow(error, "Failed to lookup object");
}
@@ -100,13 +72,12 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec)
peel_len = strlen(name) + strlen(peeled);
head->name = git__malloc(peel_len + 1);
ret = p_snprintf(head->name, peel_len + 1, "%s%s", name, peeled);
- if (ret >= peel_len + 1) {
- error = git__throw(GIT_ERROR, "The string is magically to long");
- }
+
+ assert(ret < peel_len + 1);
git_oid_cpy(&head->oid, git_tag_target_oid((git_tag *) obj));
- error = git_vector_insert(vec, head);
+ error = git_vector_insert(&t->refs, head);
if (error < GIT_SUCCESS)
goto out;
@@ -114,71 +85,109 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec)
git_reference_free(ref);
git_reference_free(resolved_ref);
- git_object_close(obj);
- if (error < GIT_SUCCESS) {
+ git_object_free(obj);
+ if (head && error < GIT_SUCCESS) {
git__free(head->name);
git__free(head);
}
+
return error;
}
-static int local_ls(git_transport *transport, git_headarray *array)
+static int store_refs(transport_local *t)
{
int error;
unsigned int i;
- git_repository *repo;
- git_vector *vec;
- git_strarray refs;
- transport_local *t = (transport_local *) transport;
+ git_strarray ref_names = {0};
- assert(transport && transport->connected);
-
- repo = t->repo;
+ assert(t);
- error = git_reference_listall(&refs, repo, GIT_REF_LISTALL);
+ error = git_vector_init(&t->refs, ref_names.count, NULL);
if (error < GIT_SUCCESS)
- return git__rethrow(error, "Failed to list remote heads");
-
- vec = git__malloc(sizeof(git_vector));
- if (vec == NULL) {
- error = GIT_ENOMEM;
- goto out;
- }
+ return error;
- error = git_vector_init(vec, refs.count, NULL);
+ error = git_reference_listall(&ref_names, t->repo, GIT_REF_LISTALL);
if (error < GIT_SUCCESS)
- return error;
+ return git__rethrow(error, "Failed to list remote heads");
/* Sort the references first */
- git__tsort((void **)refs.strings, refs.count, &git__strcmp_cb);
+ git__tsort((void **)ref_names.strings, ref_names.count, &git__strcmp_cb);
/* Add HEAD */
- error = add_ref(GIT_HEAD_FILE, repo, vec);
+ error = add_ref(t, GIT_HEAD_FILE);
if (error < GIT_SUCCESS)
- goto out;
+ goto cleanup;
- for (i = 0; i < refs.count; ++i) {
- error = add_ref(refs.strings[i], repo, vec);
+ for (i = 0; i < ref_names.count; ++i) {
+ error = add_ref(t, ref_names.strings[i]);
if (error < GIT_SUCCESS)
- goto out;
+ goto cleanup;
}
- array->len = vec->length;
- array->heads = (git_remote_head **)vec->contents;
+cleanup:
+ git_strarray_free(&ref_names);
+ return error;
+}
- t->refs = vec;
+static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *payload)
+{
+ transport_local *t = (transport_local *) transport;
+ git_vector *refs = &t->refs;
+ unsigned int i;
+ git_remote_head *h;
- out:
+ assert(transport && transport->connected);
- git_strarray_free(&refs);
+ git_vector_foreach(refs, i, h) {
+ if (list_cb(h, payload) < 0)
+ return git__throw(GIT_ERROR,
+ "The user callback returned an error code");
+ }
- return error;
+ return GIT_SUCCESS;
+}
+
+
+/*
+ * Try to open the url as a git directory. The direction doesn't
+ * matter in this case because we're calulating the heads ourselves.
+ */
+static int local_connect(git_transport *transport, int GIT_UNUSED(direction))
+{
+ git_repository *repo;
+ int error;
+ transport_local *t = (transport_local *) transport;
+ const char *path;
+ const char file_prefix[] = "file://";
+ GIT_UNUSED_ARG(direction);
+
+ /* The repo layer doesn't want the prefix */
+ if (!git__prefixcmp(transport->url, file_prefix))
+ path = transport->url + strlen(file_prefix);
+ else
+ path = transport->url;
+
+ error = git_repository_open(&repo, path);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to open remote");
+
+ error = store_refs(t);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to retrieve references");
+
+ t->repo = repo;
+ t->parent.connected = 1;
+
+ return GIT_SUCCESS;
}
static int local_close(git_transport *GIT_UNUSED(transport))
{
- /* Nothing to do */
- GIT_UNUSED_ARG(transport);
+ transport_local *t = (transport_local *)transport;
+
+ git_repository_free(t->repo);
+ t->repo = NULL;
+
return GIT_SUCCESS;
}
@@ -186,21 +195,17 @@ static void local_free(git_transport *transport)
{
unsigned int i;
transport_local *t = (transport_local *) transport;
- git_vector *vec = t->refs;
+ git_vector *vec = &t->refs;
git_remote_head *h;
assert(transport);
- if (t->refs != NULL) {
- git_vector_foreach (vec, i, h) {
- git__free(h->name);
- git__free(h);
- }
- git_vector_free(vec);
- git__free(vec);
+ git_vector_foreach (vec, i, h) {
+ git__free(h->name);
+ git__free(h);
}
+ git_vector_free(vec);
- git_repository_free(t->repo);
git__free(t->parent.url);
git__free(t);
}
diff --git a/src/tree.c b/src/tree.c
index 92ca5ab77..702095d14 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -300,9 +300,15 @@ static int append_entry(git_treebuilder *bld, const char *filename, const git_oi
return GIT_SUCCESS;
}
-static int write_tree(git_oid *oid, git_index *index, const char *dirname, unsigned int start)
+static int write_tree(
+ git_oid *oid,
+ git_repository *repo,
+ git_index *index,
+ const char *dirname,
+ unsigned int start)
{
git_treebuilder *bld = NULL;
+
unsigned int i, entries = git_index_entrycount(index);
int error;
size_t dirname_len = strlen(dirname);
@@ -358,7 +364,7 @@ static int write_tree(git_oid *oid, git_index *index, const char *dirname, unsig
}
/* Write out the subtree */
- written = write_tree(&sub_oid, index, subdir, i);
+ written = write_tree(&sub_oid, repo, index, subdir, i);
if (written < 0) {
error = git__rethrow(written, "Failed to write subtree %s", subdir);
} else {
@@ -391,7 +397,7 @@ static int write_tree(git_oid *oid, git_index *index, const char *dirname, unsig
}
}
- error = git_treebuilder_write(oid, index->repository, bld);
+ error = git_treebuilder_write(oid, repo, bld);
if (error < GIT_SUCCESS)
error = git__rethrow(error, "Failed to write tree to db");
@@ -406,10 +412,15 @@ static int write_tree(git_oid *oid, git_index *index, const char *dirname, unsig
int git_tree_create_fromindex(git_oid *oid, git_index *index)
{
+ git_repository *repo;
int error;
- if (index->repository == NULL)
- return git__throw(GIT_EBAREINDEX, "Failed to create tree. The index file is not backed up by an existing repository");
+ repo = (git_repository *)GIT_REFCOUNT_OWNER(index);
+
+ if (repo == NULL)
+ return git__throw(GIT_EBAREINDEX,
+ "Failed to create tree. "
+ "The index file is not backed up by an existing repository");
if (index->tree != NULL && index->tree->entries >= 0) {
git_oid_cpy(oid, &index->tree->oid);
@@ -417,7 +428,7 @@ int git_tree_create_fromindex(git_oid *oid, git_index *index)
}
/* The tree cache didn't help us */
- error = write_tree(oid, index, "", 0);
+ error = write_tree(oid, repo, index, "", 0);
return (error < GIT_SUCCESS) ? git__rethrow(error, "Failed to create tree") : GIT_SUCCESS;
}
@@ -546,6 +557,7 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b
unsigned int i;
int error;
git_buf tree = GIT_BUF_INIT;
+ git_odb *odb;
assert(bld);
@@ -570,7 +582,13 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b
return git__throw(GIT_ENOMEM, "Not enough memory to build the tree data");
}
- error = git_odb_write(oid, git_repository_database(repo), tree.ptr, tree.size, GIT_OBJ_TREE);
+ error = git_repository_odb__weakptr(&odb, repo);
+ if (error < GIT_SUCCESS) {
+ git_buf_free(&tree);
+ return error;
+ }
+
+ error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE);
git_buf_free(&tree);
return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write tree");
@@ -662,7 +680,7 @@ static int tree_frompath(
slash_pos - treeentry_path + 1
);
- git_tree_close(subtree);
+ git_tree_free(subtree);
return error;
}
@@ -713,7 +731,7 @@ static int tree_walk_post(
payload
);
- git_tree_close(subtree);
+ git_tree_free(subtree);
}
}
diff --git a/src/util.h b/src/util.h
index fbf9012a3..4b1104b7b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -104,29 +104,34 @@ extern void git__strtolower(char *str);
extern int git__fnmatch(const char *pattern, const char *name, int flags);
-/*
- * Realloc the buffer pointed at by variable 'x' so that it can hold
- * at least 'nr' entries; the number of entries currently allocated
- * is 'alloc', using the standard growing factor alloc_nr() macro.
- *
- * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
- */
-#define alloc_nr(x) (((x)+16)*3/2)
-#define ALLOC_GROW(x, nr, alloc) \
- do { \
- if ((nr) > alloc) { \
- if (alloc_nr(alloc) < (nr)) \
- alloc = (nr); \
- else \
- alloc = alloc_nr(alloc); \
- x = xrealloc((x), alloc * sizeof(*(x))); \
- } \
- } while (0)
-
extern void git__tsort(void **dst, size_t size, int (*cmp)(const void *, const void *));
extern void **git__bsearch(const void *key, void **base, size_t nmemb,
int (*compar)(const void *, const void *));
extern int git__strcmp_cb(const void *a, const void *b);
+typedef struct {
+ short refcount;
+ void *owner;
+} git_refcount;
+
+typedef void (*git_refcount_freeptr)(void *r);
+
+#define GIT_REFCOUNT_INC(r) { \
+ ((git_refcount *)(r))->refcount++; \
+}
+
+#define GIT_REFCOUNT_DEC(_r, do_free) { \
+ git_refcount *r = (git_refcount *)(_r); \
+ r->refcount--; \
+ if (r->refcount <= 0 && r->owner == NULL) { do_free(_r); } \
+}
+
+#define GIT_REFCOUNT_OWN(r, o) { \
+ ((git_refcount *)(r))->owner = o; \
+}
+
+#define GIT_REFCOUNT_OWNER(r) (((git_refcount *)(r))->owner)
+
+
#endif /* INCLUDE_util_h__ */