summaryrefslogtreecommitdiff
path: root/src/odb.c
diff options
context:
space:
mode:
authorShawn O. Pearce <spearce@spearce.org>2008-12-31 16:20:05 -0800
committerShawn O. Pearce <spearce@spearce.org>2008-12-31 16:20:05 -0800
commitb438016ecda7648426036e66c4ed17fc93e71cfa (patch)
tree60711175510355240283174b84d16ee85fd599ec /src/odb.c
parent7350e6337a2d94c2d2a105845fc78ba0ddc89ea5 (diff)
downloadlibgit2-b438016ecda7648426036e66c4ed17fc93e71cfa.tar.gz
Find pack files in $GIT_DIR/objects/pack directory on git_odb_open
Currently we only catalog the available pack files into a table, storing their path names relative to the pack directory. Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Diffstat (limited to 'src/odb.c')
-rw-r--r--src/odb.c125
1 files changed, 123 insertions, 2 deletions
diff --git a/src/odb.c b/src/odb.c
index 8a6be5524..0e40ca2e7 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -30,14 +30,26 @@
#include "hash.h"
#include <stdio.h>
+#define GIT_PACK_NAME_MAX (5 + 40 + 1)
+typedef struct {
+ git_refcnt ref;
+
+ char pack_name[GIT_PACK_NAME_MAX];
+} git_pack;
+
struct git_odb {
git_lck lock;
/** Path to the "objects" directory. */
char *objects_dir;
+ /** Known pack files from ${objects_dir}/packs. */
+ git_pack **packs;
+ size_t n_packs;
+
/** Alternate databases to search. */
git_odb **alternates;
+ size_t n_alternates;
};
typedef struct { /* object header data */
@@ -432,13 +444,111 @@ static int open_alternates(git_odb *db)
}
db->alternates[n] = NULL;
+ db->n_alternates = n;
+ gitlck_unlock(&db->lock);
+ return 0;
+}
+
+static void free_pack(git_pack *p)
+{
+ gitrc_free(&p->ref);
+ free(p);
+}
+
+static git_pack *alloc_pack(const char *pack_name)
+{
+ git_pack *p = git__calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ gitrc_init(&p->ref);
+ strcpy(p->pack_name, pack_name);
+ gitrc_inc(&p->ref);
+ return p;
+}
+
+struct scanned_pack {
+ struct scanned_pack *next;
+ git_pack *pack;
+};
+
+static int scan_one_pack(void *state, char *name)
+{
+ struct scanned_pack **ret = state, *r;
+ char *s = strrchr(name, '/'), *d;
+
+ if (git__prefixcmp(s + 1, "pack-")
+ || git__suffixcmp(s, ".pack")
+ || strlen(s + 1) != GIT_PACK_NAME_MAX + 4)
+ return 0;
+
+ d = strrchr(s + 1, '.');
+ strcpy(d + 1, "idx"); /* "pack-abc.pack" -> "pack-abc.idx" */
+ if (gitfo_exists(name))
+ return 0;
+
+ if (!(r = git__malloc(sizeof(*r))))
+ return GIT_ERROR;
+
+ *d = '\0'; /* "pack-abc.pack" -_> "pack-abc" */
+ if (!(r->pack = alloc_pack(s + 1))) {
+ free(r);
+ return GIT_ERROR;
+ }
+
+ r->next = *ret;
+ *ret = r;
+ return 0;
+}
+
+static int scan_packs(git_odb *db)
+{
+ char pb[GIT_PATH_MAX];
+ struct scanned_pack *state = NULL, *c;
+ size_t cnt;
+
+ if (git__fmt(pb, sizeof(pb), "%s/pack", db->objects_dir) < 0)
+ return GIT_ERROR;
+ gitfo_dirent(pb, sizeof(pb), scan_one_pack, &state);
+ gitlck_lock(&db->lock);
+
+ if (!db->packs) {
+ for (cnt = 0, c = state; c; c = c->next)
+ cnt++;
+
+ db->packs = git__malloc(sizeof(*db->packs) * (cnt + 1));
+ if (!db->packs)
+ goto unlock_fail;
+ for (cnt = 0, c = state; c; ) {
+ struct scanned_pack *n = c->next;
+ db->packs[cnt++] = c->pack;
+ free(c);
+ c = n;
+ }
+ db->packs[cnt] = NULL;
+ db->n_packs = cnt;
+ } else {
+ /* TODO - merge new entries into the existing array */
+ goto unlock_fail;
+ }
+
gitlck_unlock(&db->lock);
return 0;
+
+unlock_fail:
+ gitlck_unlock(&db->lock);
+ while (state) {
+ struct scanned_pack *n = state->next;
+ free_pack(state->pack);
+ free(state);
+ state = n;
+ }
+ return GIT_ERROR;
}
int git_odb_open(git_odb **out, const char *objects_dir)
{
- git_odb *db = git__malloc(sizeof(*db));
+ git_odb *db = git__calloc(1, sizeof(*db));
if (!db)
return GIT_ERROR;
@@ -448,8 +558,11 @@ int git_odb_open(git_odb **out, const char *objects_dir)
return GIT_ERROR;
}
- db->alternates = NULL;
gitlck_init(&db->lock);
+ if (scan_packs(db)) {
+ git_odb_close(db);
+ return GIT_ERROR;
+ }
*out = db;
return GIT_SUCCESS;
@@ -462,6 +575,14 @@ void git_odb_close(git_odb *db)
gitlck_lock(&db->lock);
+ if (db->packs) {
+ git_pack **p;
+ for (p = db->packs; *p; p++)
+ if (gitrc_dec(&(*p)->ref))
+ free_pack(*p);
+ free(db->packs);
+ }
+
if (db->alternates) {
git_odb **alt;
for (alt = db->alternates; *alt; alt++)