diff --git a/include/git/odb.h b/include/git/odb.h index 7c6be4f3f..0d65e1969 100644 --- a/include/git/odb.h +++ b/include/git/odb.h @@ -54,9 +54,8 @@ GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir); /** * Close an open object database. * @param db database pointer to close. If NULL no action is taken. - * The pointer is set to NULL when the close is completed. */ -GIT_EXTERN(void) git_odb_close(git_odb **db); +GIT_EXTERN(void) git_odb_close(git_odb *db); /** Basic type (loose or packed) of any Git object. */ typedef enum { @@ -129,7 +128,11 @@ GIT_EXTERN(int) git_odb__read_loose(git_sobj *out, git_odb *db, const git_oid *i * * @param obj object descriptor to free. */ -GIT_EXTERN(void) git_sobj_close(git_sobj *obj); +GIT_INLINE(void) git_sobj_close(git_sobj *obj) +{ + free(obj->data); + obj->data = NULL; +} /** @} */ GIT_END_DECL diff --git a/src/odb.c b/src/odb.c index 86dcfa927..0a420998a 100644 --- a/src/odb.c +++ b/src/odb.c @@ -27,21 +27,71 @@ struct git_odb { /** Path to the "objects" directory. */ - const char *path; + char *path; /** Alternate databases to search. */ git_odb **alternates; - - /** Number of alternates available. */ - unsigned n_alternates; }; +static int open_alternates(git_odb *db) +{ + unsigned n = 0; + + db->alternates = malloc(sizeof(*db->alternates) * (n + 1)); + if (!db->alternates) + return GIT_ERROR; + + db->alternates[n] = NULL; + return GIT_SUCCESS; +} + +int git_odb_open(git_odb **out, const char *objects_dir) +{ + git_odb *db = malloc(sizeof(*db)); + if (!db) + return GIT_ERROR; + + db->path = strdup(objects_dir); + if (!db->path) { + free(db); + return GIT_ERROR; + } + + db->alternates = NULL; + + *out = db; + return GIT_SUCCESS; +} + +void git_odb_close(git_odb *db) +{ + if (!db) + return; + + if (db->alternates) { + git_odb **alt; + for (alt = db->alternates; *alt; alt++) + git_odb_close(*alt); + free(db->alternates); + } + + free(db->path); + free(db); +} + int git_odb_read( git_sobj *out, git_odb *db, const git_oid *id) { +attempt: if (!git_odb__read_packed(out, db, id)) return GIT_SUCCESS; - return git_odb__read_loose(out, db, id); + if (!git_odb__read_loose(out, db, id)) + return GIT_SUCCESS; + if (!db->alternates && !open_alternates(db)) + goto attempt; + + out->data = NULL; + return GIT_ENOTFOUND; }