From b438016ecda7648426036e66c4ed17fc93e71cfa Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 31 Dec 2008 16:20:05 -0800 Subject: [PATCH] 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 --- src/odb.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file 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 +#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++)