]> git.proxmox.com Git - libgit2.git/blame - src/object.c
Merge pull request #1385 from carlosmn/refs-iter
[libgit2.git] / src / object.c
CommitLineData
e52ed7a5 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
e52ed7a5 3 *
bb742ede
VM
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
e52ed7a5
VM
6 */
7#include <stdarg.h>
8
9#include "git2/object.h"
10
11#include "common.h"
12#include "repository.h"
13
14#include "commit.h"
15#include "tree.h"
16#include "blob.h"
17#include "tag.h"
18
19static const int OBJECT_BASE_SIZE = 4096;
20
78606263 21typedef struct {
87d9869f 22 const char *str; /* type name string */
e52ed7a5 23 size_t size; /* size in bytes of the object structure */
78606263 24
3f27127d 25 int (*parse)(void *self, git_odb_object *obj);
78606263
RB
26 void (*free)(void *self);
27} git_object_def;
28
29static git_object_def git_objects_table[] = {
e52ed7a5 30 /* 0 = GIT_OBJ__EXT1 */
3f27127d 31 { "", 0, NULL, NULL },
e52ed7a5
VM
32
33 /* 1 = GIT_OBJ_COMMIT */
3f27127d 34 { "commit", sizeof(git_commit), git_commit__parse, git_commit__free },
e52ed7a5
VM
35
36 /* 2 = GIT_OBJ_TREE */
3f27127d 37 { "tree", sizeof(git_tree), git_tree__parse, git_tree__free },
e52ed7a5
VM
38
39 /* 3 = GIT_OBJ_BLOB */
3f27127d 40 { "blob", sizeof(git_blob), git_blob__parse, git_blob__free },
e52ed7a5
VM
41
42 /* 4 = GIT_OBJ_TAG */
3f27127d 43 { "tag", sizeof(git_tag), git_tag__parse, git_tag__free },
e52ed7a5
VM
44
45 /* 5 = GIT_OBJ__EXT2 */
3f27127d 46 { "", 0, NULL, NULL },
e52ed7a5 47 /* 6 = GIT_OBJ_OFS_DELTA */
3f27127d 48 { "OFS_DELTA", 0, NULL, NULL },
e52ed7a5 49 /* 7 = GIT_OBJ_REF_DELTA */
3f27127d 50 { "REF_DELTA", 0, NULL, NULL },
e52ed7a5
VM
51};
52
c6ac28fd
RB
53int git_object__from_odb_object(
54 git_object **object_out,
55 git_repository *repo,
56 git_odb_object *odb_obj,
57 git_otype type)
58{
59 int error;
78606263
RB
60 size_t object_size;
61 git_object_def *def;
c6ac28fd
RB
62 git_object *object = NULL;
63
78606263
RB
64 assert(object_out);
65 *object_out = NULL;
66
67 /* Validate type match */
8842c75f
VM
68 if (type != GIT_OBJ_ANY && type != odb_obj->cached.type) {
69 giterr_set(GITERR_INVALID,
70 "The requested type does not match the type in the ODB");
c6ac28fd
RB
71 return GIT_ENOTFOUND;
72 }
73
78606263
RB
74 if ((object_size = git_object__size(odb_obj->cached.type)) == 0) {
75 giterr_set(GITERR_INVALID, "The requested type is invalid");
76 return GIT_ENOTFOUND;
77 }
78
79 /* Allocate and initialize base object */
80 object = git__calloc(1, object_size);
81 GITERR_CHECK_ALLOC(object);
c6ac28fd 82
c6ac28fd 83 git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid);
cf7850a4 84 object->cached.type = odb_obj->cached.type;
78606263 85 object->cached.size = odb_obj->cached.size;
c6ac28fd
RB
86 object->repo = repo;
87
78606263
RB
88 /* Parse raw object data */
89 def = &git_objects_table[odb_obj->cached.type];
3f27127d 90 assert(def->free && def->parse);
c6ac28fd 91
3f27127d 92 if ((error = def->parse(object, odb_obj)) < 0)
78606263 93 def->free(object);
3f27127d
RB
94 else
95 *object_out = git_cache_store_parsed(&repo->objects, object);
c6ac28fd 96
3f27127d 97 return error;
c6ac28fd
RB
98}
99
78606263
RB
100void git_object__free(void *obj)
101{
102 git_otype type = ((git_object *)obj)->cached.type;
103
104 if (type < 0 || ((size_t)type) >= ARRAY_SIZE(git_objects_table) ||
105 !git_objects_table[type].free)
106 git__free(obj);
107 else
108 git_objects_table[type].free(obj);
109}
110
9462c471
VM
111int git_object_lookup_prefix(
112 git_object **object_out,
113 git_repository *repo,
114 const git_oid *id,
b8457baa 115 size_t len,
9462c471 116 git_otype type)
5de079b8
VM
117{
118 git_object *object = NULL;
9462c471 119 git_odb *odb = NULL;
72a3fe42 120 git_odb_object *odb_obj;
e172cf08 121 int error = 0;
5de079b8
VM
122
123 assert(repo && object_out && id);
124
8915a140
RB
125 if (len < GIT_OID_MINPREFIXLEN) {
126 giterr_set(GITERR_OBJECT, "Ambiguous lookup - OID prefix is too short");
904b67e6 127 return GIT_EAMBIGUOUS;
8915a140 128 }
d0323a5f 129
9462c471 130 error = git_repository_odb__weakptr(&odb, repo);
e172cf08 131 if (error < 0)
9462c471
VM
132 return error;
133
d0323a5f 134 if (len > GIT_OID_HEXSZ)
dd453c4d 135 len = GIT_OID_HEXSZ;
bd1aa741 136
87d9869f 137 if (len == GIT_OID_HEXSZ) {
5df18424
VM
138 git_cached_obj *cached = NULL;
139
dd453c4d
MP
140 /* We want to match the full id : we can first look up in the cache,
141 * since there is no need to check for non ambiguousity
142 */
5df18424
VM
143 cached = git_cache_get_any(&repo->objects, id);
144 if (cached != NULL) {
145 if (cached->flags == GIT_CACHE_STORE_PARSED) {
146 object = (git_object *)cached;
147
cf7850a4 148 if (type != GIT_OBJ_ANY && type != object->cached.type) {
5df18424
VM
149 git_object_free(object);
150 giterr_set(GITERR_INVALID,
151 "The requested type does not match the type in ODB");
152 return GIT_ENOTFOUND;
153 }
154
155 *object_out = object;
156 return 0;
157 } else if (cached->flags == GIT_CACHE_STORE_RAW) {
158 odb_obj = (git_odb_object *)cached;
159 } else {
160 assert(!"Wrong caching type in the global object cache");
7d3ec3ca 161 }
5df18424
VM
162 } else {
163 /* Object was not found in the cache, let's explore the backends.
164 * We could just use git_odb_read_unique_short_oid,
165 * it is the same cost for packed and loose object backends,
166 * but it may be much more costly for sqlite and hiredis.
167 */
168 error = git_odb_read(&odb_obj, odb, id);
dd453c4d 169 }
dd453c4d
MP
170 } else {
171 git_oid short_oid;
172
173 /* We copy the first len*4 bits from id and fill the remaining with 0s */
174 memcpy(short_oid.id, id->id, (len + 1) / 2);
175 if (len % 2)
176 short_oid.id[len / 2] &= 0xF0;
177 memset(short_oid.id + (len + 1) / 2, 0, (GIT_OID_HEXSZ - len) / 2);
178
179 /* If len < GIT_OID_HEXSZ (a strict short oid was given), we have
180 * 2 options :
181 * - We always search in the cache first. If we find that short oid is
87d9869f
VM
182 * ambiguous, we can stop. But in all the other cases, we must then
183 * explore all the backends (to find an object if there was match,
184 * or to check that oid is not ambiguous if we have found 1 match in
185 * the cache)
dd453c4d
MP
186 * - We never explore the cache, go right to exploring the backends
187 * We chose the latter : we explore directly the backends.
188 */
9462c471 189 error = git_odb_read_prefix(&odb_obj, odb, &short_oid, len);
5de079b8
VM
190 }
191
3aa351ea 192 if (error < 0)
282283ac 193 return error;
5de079b8 194
c6ac28fd 195 error = git_object__from_odb_object(object_out, repo, odb_obj, type);
5de079b8 196
45e79e37 197 git_odb_object_free(odb_obj);
72a3fe42 198
c6ac28fd 199 return error;
5de079b8
VM
200}
201
dd453c4d 202int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type) {
d0323a5f 203 return git_object_lookup_prefix(object_out, repo, id, GIT_OID_HEXSZ, type);
dd453c4d
MP
204}
205
45e79e37 206void git_object_free(git_object *object)
48c27f86
VM
207{
208 if (object == NULL)
209 return;
210
5df18424 211 git_cached_obj_decref(object);
48c27f86
VM
212}
213
17cdf252 214const git_oid *git_object_id(const git_object *obj)
e52ed7a5
VM
215{
216 assert(obj);
72a3fe42 217 return &obj->cached.oid;
e52ed7a5
VM
218}
219
17cdf252 220git_otype git_object_type(const git_object *obj)
e52ed7a5
VM
221{
222 assert(obj);
cf7850a4 223 return obj->cached.type;
e52ed7a5
VM
224}
225
17cdf252 226git_repository *git_object_owner(const git_object *obj)
e52ed7a5
VM
227{
228 assert(obj);
229 return obj->repo;
230}
231
232const char *git_object_type2string(git_otype type)
233{
234 if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table))
235 return "";
236
237 return git_objects_table[type].str;
238}
239
240git_otype git_object_string2type(const char *str)
241{
242 size_t i;
243
244 if (!str || !*str)
245 return GIT_OBJ_BAD;
246
247 for (i = 0; i < ARRAY_SIZE(git_objects_table); i++)
248 if (!strcmp(str, git_objects_table[i].str))
249 return (git_otype)i;
250
251 return GIT_OBJ_BAD;
252}
253
254int git_object_typeisloose(git_otype type)
255{
256 if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table))
257 return 0;
258
78606263 259 return (git_objects_table[type].size > 0) ? 1 : 0;
e52ed7a5
VM
260}
261
262size_t git_object__size(git_otype type)
263{
264 if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table))
265 return 0;
266
267 return git_objects_table[type].size;
268}
269
db9be945 270static int dereference_object(git_object **dereferenced, git_object *obj)
271{
272 git_otype type = git_object_type(obj);
273
274 switch (type) {
275 case GIT_OBJ_COMMIT:
276 return git_commit_tree((git_tree **)dereferenced, (git_commit*)obj);
db9be945 277
278 case GIT_OBJ_TAG:
279 return git_tag_target(dereferenced, (git_tag*)obj);
d8057a5b
RB
280
281 case GIT_OBJ_BLOB:
bc05f30c 282 return GIT_ENOTFOUND;
d8057a5b
RB
283
284 case GIT_OBJ_TREE:
bc05f30c 285 return GIT_EAMBIGUOUS;
db9be945 286
287 default:
bc05f30c 288 return GIT_EINVALIDSPEC;
db9be945 289 }
290}
291
bc05f30c 292static int peel_error(int error, const git_oid *oid, git_otype type)
293{
294 const char *type_name;
295 char hex_oid[GIT_OID_HEXSZ + 1];
296
297 type_name = git_object_type2string(type);
298
299 git_oid_fmt(hex_oid, oid);
300 hex_oid[GIT_OID_HEXSZ] = '\0';
301
302 giterr_set(GITERR_OBJECT, "The git_object of id '%s' can not be "
303 "successfully peeled into a %s (git_otype=%i).", hex_oid, type_name, type);
304
305 return error;
306}
307
db9be945 308int git_object_peel(
d8057a5b 309 git_object **peeled,
cfbe4be3 310 const git_object *object,
d8057a5b 311 git_otype target_type)
db9be945 312{
313 git_object *source, *deref = NULL;
bc05f30c 314 int error;
315
d8057a5b 316 assert(object && peeled);
db9be945 317
318 if (git_object_type(object) == target_type)
575a54db 319 return git_object_dup(peeled, (git_object *)object);
db9be945 320
0cce210a
RB
321 assert(target_type == GIT_OBJ_TAG ||
322 target_type == GIT_OBJ_COMMIT ||
323 target_type == GIT_OBJ_TREE ||
324 target_type == GIT_OBJ_BLOB ||
325 target_type == GIT_OBJ_ANY);
8915a140 326
cfbe4be3 327 source = (git_object *)object;
db9be945 328
bc05f30c 329 while (!(error = dereference_object(&deref, source))) {
db9be945 330
331 if (source != object)
332 git_object_free(source);
333
334 if (git_object_type(deref) == target_type) {
335 *peeled = deref;
336 return 0;
337 }
338
d8057a5b
RB
339 if (target_type == GIT_OBJ_ANY &&
340 git_object_type(deref) != git_object_type(object))
341 {
342 *peeled = deref;
343 return 0;
344 }
345
db9be945 346 source = deref;
347 deref = NULL;
348 }
349
db9be945 350 if (source != object)
351 git_object_free(source);
d8057a5b 352
db9be945 353 git_object_free(deref);
bc05f30c 354
355 if (error)
356 error = peel_error(error, git_object_id(object), target_type);
357
358 return error;
db9be945 359}
613d5eb9 360
575a54db
VM
361int git_object_dup(git_object **dest, git_object *source)
362{
363 git_cached_obj_incref(source);
364 *dest = source;
365 return 0;
366}