diff options
author | Carlos Martín Nieto <cmn@elego.de> | 2012-06-05 14:48:51 +0200 |
---|---|---|
committer | Carlos Martín Nieto <carlos@cmartin.tk> | 2012-07-03 12:50:51 +0200 |
commit | 521aedad307c6f72d6f6d660943508b2b015f6dd (patch) | |
tree | aef33032b13ca170a3d7a016e7e8522a7635ce6f | |
parent | e560aa8ffa7cf143fbd34a5aec44741ae4c77271 (diff) | |
download | libgit2-521aedad307c6f72d6f6d660943508b2b015f6dd.tar.gz |
odb: add git_odb_foreach()
Go through each backend and list every objects that exists in
them. This allows fsck-like uses.
-rw-r--r-- | include/git2/odb.h | 14 | ||||
-rw-r--r-- | include/git2/odb_backend.h | 6 | ||||
-rw-r--r-- | src/odb.c | 12 | ||||
-rw-r--r-- | src/odb_loose.c | 84 | ||||
-rw-r--r-- | src/odb_pack.c | 20 | ||||
-rw-r--r-- | src/pack.c | 43 | ||||
-rw-r--r-- | src/pack.h | 4 | ||||
-rw-r--r-- | tests-clar/odb/foreach.c | 36 |
8 files changed, 219 insertions, 0 deletions
diff --git a/include/git2/odb.h b/include/git2/odb.h index e2443178c..dac9e06a9 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -173,6 +173,20 @@ GIT_EXTERN(int) git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *d GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id); /** + * List all objects available in the database + * + * The callback will be called for each object available in the + * database. Note that the objects are likely to be returned in the + * index order, which would make accessing the objects in that order + * inefficient. + * + * @param db database to use + * @param cb the callback to call for each object + * @param data data to pass to the callback + */ +GIT_EXTERN(int) git_odb_foreach(git_odb *db, int (*cb)(git_oid *oid, void *data), void *data); + +/** * Write an object directly into the ODB * * This method writes a full object straight into the ODB. diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h index f4620f5f4..3f67202d1 100644 --- a/include/git2/odb_backend.h +++ b/include/git2/odb_backend.h @@ -71,6 +71,12 @@ struct git_odb_backend { struct git_odb_backend *, const git_oid *); + int (*foreach)( + struct git_odb_backend *, + int (*cb)(git_oid *oid, void *data), + void *data + ); + void (* free)(struct git_odb_backend *); }; @@ -605,6 +605,18 @@ int git_odb_read_prefix( return 0; } +int git_odb_foreach(git_odb *db, int (*cb)(git_oid *oid, void *data), void *data) +{ + unsigned int i; + backend_internal *internal; + git_vector_foreach(&db->backends, i, internal) { + git_odb_backend *b = internal->backend; + b->foreach(b, cb, data); + } + + return 0; +} + int git_odb_write( git_oid *oid, git_odb *db, const void *data, size_t len, git_otype type) { diff --git a/src/odb_loose.c b/src/odb_loose.c index 989b03ab2..ea51c4d14 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -676,6 +676,89 @@ static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid) return !error; } +struct foreach_state { + size_t dir_len; + int (*cb)(git_oid *oid, void *data); + void *data; +}; + +static inline int filename_to_oid(git_oid *oid, const char *ptr) +{ + int v, i = 0; + if (strlen(ptr) != 41) + return -1; + + if (ptr[2] != '/') { + return -1; + } + + v = (git__fromhex(ptr[i]) << 4) | git__fromhex(ptr[i+1]); + if (v < 0) + return -1; + + oid->id[0] = (unsigned char) v; + + ptr += 3; + for (i = 0; i < 38; i += 2) { + v = (git__fromhex(ptr[i]) << 4) | git__fromhex(ptr[i + 1]); + if (v < 0) + return -1; + + oid->id[1 + i/2] = (unsigned char) v; + } + + return 0; +} + +static int foreach_object_dir_cb(void *_state, git_buf *path) +{ + git_oid oid; + struct foreach_state *state = (struct foreach_state *) _state; + + if (filename_to_oid(&oid, path->ptr + state->dir_len) < 0) + return 0; + + if (state->cb(&oid, state->data) < 0) + return -1; + + return 0; +} + +static int foreach_cb(void *_state, git_buf *path) +{ + struct foreach_state *state = (struct foreach_state *) _state; + + if (git_path_direach(path, foreach_object_dir_cb, state) < 0) + return -1; + + return 0; +} + +static int loose_backend__foreach(git_odb_backend *_backend, int (*cb)(git_oid *oid, void *data), void *data) +{ + char *objects_dir; + int error; + git_buf buf = GIT_BUF_INIT; + struct foreach_state state; + loose_backend *backend = (loose_backend *) _backend; + + assert(backend && cb); + + objects_dir = backend->objects_dir; + + git_buf_sets(&buf, objects_dir); + git_path_to_dir(&buf); + + state.cb = cb; + state.data = data; + state.dir_len = git_buf_len(&buf); + + error = git_path_direach(&buf, foreach_cb, &state); + git_buf_free(&buf); + + return error; +} + static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream) { loose_writestream *stream = (loose_writestream *)_stream; @@ -845,6 +928,7 @@ int git_odb_backend_loose( backend->parent.read_header = &loose_backend__read_header; backend->parent.writestream = &loose_backend__stream; backend->parent.exists = &loose_backend__exists; + backend->parent.foreach = &loose_backend__foreach; backend->parent.free = &loose_backend__free; *backend_out = (git_odb_backend *)backend; diff --git a/src/odb_pack.c b/src/odb_pack.c index 458f288d9..4b860e864 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -420,6 +420,25 @@ static int pack_backend__exists(git_odb_backend *backend, const git_oid *oid) return pack_entry_find(&e, (struct pack_backend *)backend, oid) == 0; } +static int pack_backend__foreach(git_odb_backend *_backend, int (*cb)(git_oid *oid, void *data), void *data) +{ + struct git_pack_file *p; + struct pack_backend *backend; + unsigned int i; + + assert(_backend && cb); + backend = (struct pack_backend *)_backend; + + /* Make sure we know about the packfiles */ + if (packfile_refresh_all(backend) < 0) + return -1; + + git_vector_foreach(&backend->packs, i, p) { + git_pack_foreach_entry(p, cb, &data); + } + return 0; +} + static void pack_backend__free(git_odb_backend *_backend) { struct pack_backend *backend; @@ -463,6 +482,7 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) backend->parent.read_prefix = &pack_backend__read_prefix; backend->parent.read_header = NULL; backend->parent.exists = &pack_backend__exists; + backend->parent.foreach = &pack_backend__foreach; backend->parent.free = &pack_backend__free; *backend_out = (git_odb_backend *)backend; diff --git a/src/pack.c b/src/pack.c index 808ceb70c..1d88eaa7d 100644 --- a/src/pack.c +++ b/src/pack.c @@ -686,6 +686,49 @@ static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_ } } +int git_pack_foreach_entry( + struct git_pack_file *p, + int (*cb)(git_oid *oid, void *data), + void *data) + +{ + const unsigned char *index = p->index_map.data, *current; + unsigned stride; + uint32_t i; + + if (index == NULL) { + int error; + + if ((error = pack_index_open(p)) < 0) + return error; + + assert(p->index_map.data); + + index = p->index_map.data; + } + + if (p->index_version > 1) { + index += 8; + } + + index += 4 * 256; + + if (p->index_version > 1) { + stride = 20; + } else { + stride = 24; + index += 4; + } + + current = index; + for (i = 0; i < p->num_objects; i++) { + cb((git_oid *)current, data); + current += stride; + } + + return 0; +} + static int pack_entry_find_offset( git_off_t *offset_out, git_oid *found_oid, diff --git a/src/pack.h b/src/pack.h index cd7a4d2e1..7e1f978b0 100644 --- a/src/pack.h +++ b/src/pack.h @@ -102,5 +102,9 @@ int git_pack_entry_find( struct git_pack_file *p, const git_oid *short_oid, unsigned int len); +int git_pack_foreach_entry( + struct git_pack_file *p, + int (*cb)(git_oid *oid, void *data), + void *data); #endif diff --git a/tests-clar/odb/foreach.c b/tests-clar/odb/foreach.c new file mode 100644 index 000000000..6cb4faad2 --- /dev/null +++ b/tests-clar/odb/foreach.c @@ -0,0 +1,36 @@ +#include "clar_libgit2.h" +#include "odb.h" +#include "git2/odb_backend.h" +#include "pack.h" + +static git_odb *_odb; +static git_repository *_repo; +static int nobj; + +void test_odb_foreach__initialize(void) +{ + cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); + git_repository_odb(&_odb, _repo); +} + +void test_odb_foreach__cleanup(void) +{ + git_odb_free(_odb); + git_repository_free(_repo); +} + +static int foreach_cb(git_oid *oid, void *data) +{ + GIT_UNUSED(data); + GIT_UNUSED(oid); + + nobj++; + + return 0; +} + +void test_odb_foreach__foreach(void) +{ + cl_git_pass(git_odb_foreach(_odb, foreach_cb, NULL)); + cl_assert(nobj == 1681); +} |