diff --git a/src/diff_output.c b/src/diff_output.c index 8873a4dc7..dbef7ddc1 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -292,6 +292,7 @@ static int get_blob_content( git_blob **blob) { int error; + git_odb_object *odb_obj = NULL; if (git_oid_iszero(&file->oid)) return 0; @@ -303,7 +304,8 @@ static int get_blob_content( /* peek at object header to avoid loading if too large */ if ((error = git_repository_odb__weakptr(&odb, ctxt->repo)) < 0 || - (error = git_odb_read_header(&len, &type, odb, &file->oid)) < 0) + (error = git_odb__read_header_or_object( + &odb_obj, &len, &type, odb, &file->oid)) < 0) return error; assert(type == GIT_OBJ_BLOB); @@ -317,7 +319,14 @@ static int get_blob_content( if (ctxt->delta->binary == 1) return 0; - if ((error = git_blob_lookup(blob, ctxt->repo, &file->oid)) < 0) + if (odb_obj != NULL) { + error = git_object__from_odb_object( + (git_object **)blob, ctxt->repo, odb_obj, GIT_OBJ_BLOB); + git_odb_object_free(odb_obj); + } else + error = git_blob_lookup(blob, ctxt->repo, &file->oid); + + if (error) return error; map->data = (void *)git_blob_rawcontent(*blob); diff --git a/src/object.c b/src/object.c index 5130d97ac..2e45eb86a 100644 --- a/src/object.c +++ b/src/object.c @@ -77,6 +77,58 @@ static int create_object(git_object **object_out, git_otype type) return 0; } +int git_object__from_odb_object( + git_object **object_out, + git_repository *repo, + git_odb_object *odb_obj, + git_otype type) +{ + int error; + git_object *object = NULL; + + if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) { + giterr_set(GITERR_ODB, "The requested type does not match the type in the ODB"); + return GIT_ENOTFOUND; + } + + type = odb_obj->raw.type; + + if ((error = create_object(&object, type)) < 0) + return error; + + /* Initialize parent object */ + git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid); + object->repo = repo; + + switch (type) { + case GIT_OBJ_COMMIT: + error = git_commit__parse((git_commit *)object, odb_obj); + break; + + case GIT_OBJ_TREE: + error = git_tree__parse((git_tree *)object, odb_obj); + break; + + case GIT_OBJ_TAG: + error = git_tag__parse((git_tag *)object, odb_obj); + break; + + case GIT_OBJ_BLOB: + error = git_blob__parse((git_blob *)object, odb_obj); + break; + + default: + break; + } + + if (error < 0) + git_object__free(object); + else + *object_out = git_cache_try_store(&repo->objects, object); + + return error; +} + int git_object_lookup_prefix( git_object **object_out, git_repository *repo, @@ -148,53 +200,11 @@ int git_object_lookup_prefix( if (error < 0) return error; - if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) { - git_odb_object_free(odb_obj); - giterr_set(GITERR_ODB, "The given type does not match the type on the ODB"); - return GIT_ENOTFOUND; - } - - type = odb_obj->raw.type; - - if (create_object(&object, type) < 0) { - git_odb_object_free(odb_obj); - return -1; - } - - /* Initialize parent object */ - git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid); - object->repo = repo; - - switch (type) { - case GIT_OBJ_COMMIT: - error = git_commit__parse((git_commit *)object, odb_obj); - break; - - case GIT_OBJ_TREE: - error = git_tree__parse((git_tree *)object, odb_obj); - break; - - case GIT_OBJ_TAG: - error = git_tag__parse((git_tag *)object, odb_obj); - break; - - case GIT_OBJ_BLOB: - error = git_blob__parse((git_blob *)object, odb_obj); - break; - - default: - break; - } + error = git_object__from_odb_object(object_out, repo, odb_obj, type); git_odb_object_free(odb_obj); - if (error < 0) { - git_object__free(object); - return -1; - } - - *object_out = git_cache_try_store(&repo->objects, object); - return 0; + return error; } int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type) { diff --git a/src/object.h b/src/object.h new file mode 100644 index 000000000..bc12aad04 --- /dev/null +++ b/src/object.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009-2012 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_object_h__ +#define INCLUDE_object_h__ + +/** Base git object for inheritance */ +struct git_object { + git_cached_obj cached; + git_repository *repo; + git_otype type; +}; + +/* fully free the object; internal method, DO NOT EXPORT */ +void git_object__free(void *object); + +GIT_INLINE(int) git_object__dup(git_object **dest, git_object *source) +{ + git_cached_obj_incref(source); + *dest = source; + return 0; +} + +int git_object__from_odb_object( + git_object **object_out, + git_repository *repo, + git_odb_object *odb_obj, + git_otype type); + +int git_object__resolve_to_type(git_object **obj, git_otype type); + +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); + +#endif diff --git a/src/odb.c b/src/odb.c index 83c7a80fc..0e03e40ee 100644 --- a/src/odb.c +++ b/src/odb.c @@ -513,20 +513,37 @@ int git_odb_exists(git_odb *db, const git_oid *id) } int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id) +{ + int error; + git_odb_object *object; + + error = git_odb__read_header_or_object(&object, len_p, type_p, db, id); + + if (object) + git_odb_object_free(object); + + return error; +} + +int git_odb__read_header_or_object( + git_odb_object **out, size_t *len_p, git_otype *type_p, + git_odb *db, const git_oid *id) { unsigned int i; int error = GIT_ENOTFOUND; git_odb_object *object; - assert(db && id); + assert(db && id && out && len_p && type_p); if ((object = git_cache_get(&db->cache, id)) != NULL) { *len_p = object->raw.len; *type_p = object->raw.type; - git_odb_object_free(object); + *out = object; return 0; } + *out = NULL; + for (i = 0; i < db->backends.length && error < 0; ++i) { backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *b = internal->backend; @@ -547,7 +564,8 @@ 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_free(object); + *out = object; + return 0; } diff --git a/src/odb.h b/src/odb.h index 696e12943..e9e33dde8 100644 --- a/src/odb.h +++ b/src/odb.h @@ -84,4 +84,12 @@ int git_odb__error_notfound(const char *message, const git_oid *oid); */ int git_odb__error_ambiguous(const char *message); +/* + * Attempt to read object header or just return whole object if it could + * not be read. + */ +int git_odb__read_header_or_object( + git_odb_object **out, size_t *len_p, git_otype *type_p, + git_odb *db, const git_oid *id); + #endif diff --git a/src/repository.h b/src/repository.h index 4695edf3a..82988ba0a 100644 --- a/src/repository.h +++ b/src/repository.h @@ -18,6 +18,7 @@ #include "refs.h" #include "buffer.h" #include "odb.h" +#include "object.h" #include "attr.h" #include "strmap.h" @@ -75,13 +76,6 @@ enum { GIT_REPOSITORY_INIT__IS_REINIT = (1u << 18), }; -/** Base git object for inheritance */ -struct git_object { - git_cached_obj cached; - git_repository *repo; - git_otype type; -}; - /** Internal structure for repository object */ struct git_repository { git_odb *_odb; @@ -102,21 +96,6 @@ struct git_repository { git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX]; }; -/* fully free the object; internal method, DO NOT EXPORT */ -void git_object__free(void *object); - -GIT_INLINE(int) git_object__dup(git_object **dest, git_object *source) -{ - git_cached_obj_incref(source); - *dest = source; - return 0; -} - -int git_object__resolve_to_type(git_object **obj, git_otype type); - -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); - GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo) { return &repo->attrcache; @@ -136,7 +115,7 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo); int git_repository_index__weakptr(git_index **out, git_repository *repo); /* - * CVAR cache + * CVAR cache * * Efficient access to the most used config variables of a repository. * The cache is cleared everytime the config backend is replaced.