]> git.proxmox.com Git - libgit2.git/blame - src/object.c
New upstream version 1.4.3+dfsg.1
[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 6 */
eae0bfdc
PP
7
8#include "object.h"
9
e52ed7a5
VM
10#include "git2/object.h"
11
e52ed7a5
VM
12#include "repository.h"
13
e579e0f7 14#include "buf.h"
e52ed7a5 15#include "commit.h"
ac3d33df 16#include "hash.h"
e52ed7a5
VM
17#include "tree.h"
18#include "blob.h"
61d7328d 19#include "oid.h"
e52ed7a5
VM
20#include "tag.h"
21
f2dddf52 22bool git_object__strict_input_validation = true;
22a19f5b 23
ac3d33df 24extern int git_odb_hash(git_oid *out, const void *data, size_t len, git_object_t type);
22a2d3d5 25size_t git_object__size(git_object_t type);
ac3d33df 26
78606263 27typedef struct {
87d9869f 28 const char *str; /* type name string */
e52ed7a5 29 size_t size; /* size in bytes of the object structure */
78606263 30
3f27127d 31 int (*parse)(void *self, git_odb_object *obj);
ac3d33df 32 int (*parse_raw)(void *self, const char *data, size_t size);
78606263
RB
33 void (*free)(void *self);
34} git_object_def;
35
36static git_object_def git_objects_table[] = {
ac3d33df
JK
37 /* 0 = GIT_OBJECT__EXT1 */
38 { "", 0, NULL, NULL, NULL },
e52ed7a5 39
ac3d33df
JK
40 /* 1 = GIT_OBJECT_COMMIT */
41 { "commit", sizeof(git_commit), git_commit__parse, git_commit__parse_raw, git_commit__free },
e52ed7a5 42
ac3d33df
JK
43 /* 2 = GIT_OBJECT_TREE */
44 { "tree", sizeof(git_tree), git_tree__parse, git_tree__parse_raw, git_tree__free },
e52ed7a5 45
ac3d33df
JK
46 /* 3 = GIT_OBJECT_BLOB */
47 { "blob", sizeof(git_blob), git_blob__parse, git_blob__parse_raw, git_blob__free },
e52ed7a5 48
ac3d33df
JK
49 /* 4 = GIT_OBJECT_TAG */
50 { "tag", sizeof(git_tag), git_tag__parse, git_tag__parse_raw, git_tag__free },
e52ed7a5 51
ac3d33df
JK
52 /* 5 = GIT_OBJECT__EXT2 */
53 { "", 0, NULL, NULL, NULL },
54 /* 6 = GIT_OBJECT_OFS_DELTA */
55 { "OFS_DELTA", 0, NULL, NULL, NULL },
56 /* 7 = GIT_OBJECT_REF_DELTA */
57 { "REF_DELTA", 0, NULL, NULL, NULL },
e52ed7a5
VM
58};
59
ac3d33df
JK
60int git_object__from_raw(
61 git_object **object_out,
62 const char *data,
63 size_t size,
64 git_object_t type)
65{
66 git_object_def *def;
67 git_object *object;
68 size_t object_size;
69 int error;
70
c25aa7cd 71 GIT_ASSERT_ARG(object_out);
ac3d33df
JK
72 *object_out = NULL;
73
74 /* Validate type match */
75 if (type != GIT_OBJECT_BLOB && type != GIT_OBJECT_TREE && type != GIT_OBJECT_COMMIT && type != GIT_OBJECT_TAG) {
76 git_error_set(GIT_ERROR_INVALID, "the requested type is invalid");
77 return GIT_ENOTFOUND;
78 }
79
80 if ((object_size = git_object__size(type)) == 0) {
81 git_error_set(GIT_ERROR_INVALID, "the requested type is invalid");
82 return GIT_ENOTFOUND;
83 }
84
85 /* Allocate and initialize base object */
86 object = git__calloc(1, object_size);
87 GIT_ERROR_CHECK_ALLOC(object);
88 object->cached.flags = GIT_CACHE_STORE_PARSED;
89 object->cached.type = type;
22a2d3d5
UG
90 if ((error = git_odb_hash(&object->cached.oid, data, size, type)) < 0)
91 return error;
ac3d33df
JK
92
93 /* Parse raw object data */
94 def = &git_objects_table[type];
c25aa7cd 95 GIT_ASSERT(def->free && def->parse_raw);
ac3d33df
JK
96
97 if ((error = def->parse_raw(object, data, size)) < 0) {
98 def->free(object);
99 return error;
100 }
101
102 git_cached_obj_incref(object);
103 *object_out = object;
104
105 return 0;
106}
107
c6ac28fd
RB
108int git_object__from_odb_object(
109 git_object **object_out,
110 git_repository *repo,
111 git_odb_object *odb_obj,
ac3d33df 112 git_object_t type)
c6ac28fd
RB
113{
114 int error;
78606263
RB
115 size_t object_size;
116 git_object_def *def;
c6ac28fd
RB
117 git_object *object = NULL;
118
c25aa7cd 119 GIT_ASSERT_ARG(object_out);
78606263
RB
120 *object_out = NULL;
121
122 /* Validate type match */
ac3d33df
JK
123 if (type != GIT_OBJECT_ANY && type != odb_obj->cached.type) {
124 git_error_set(GIT_ERROR_INVALID,
909d5494 125 "the requested type does not match the type in the ODB");
c6ac28fd
RB
126 return GIT_ENOTFOUND;
127 }
128
78606263 129 if ((object_size = git_object__size(odb_obj->cached.type)) == 0) {
ac3d33df 130 git_error_set(GIT_ERROR_INVALID, "the requested type is invalid");
78606263
RB
131 return GIT_ENOTFOUND;
132 }
133
134 /* Allocate and initialize base object */
135 object = git__calloc(1, object_size);
ac3d33df 136 GIT_ERROR_CHECK_ALLOC(object);
c6ac28fd 137
c6ac28fd 138 git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid);
cf7850a4 139 object->cached.type = odb_obj->cached.type;
78606263 140 object->cached.size = odb_obj->cached.size;
c6ac28fd
RB
141 object->repo = repo;
142
78606263
RB
143 /* Parse raw object data */
144 def = &git_objects_table[odb_obj->cached.type];
c25aa7cd 145 GIT_ASSERT(def->free && def->parse);
c6ac28fd 146
e579e0f7
MB
147 if ((error = def->parse(object, odb_obj)) < 0) {
148 /*
149 * parse returns EINVALID on invalid data; downgrade
150 * that to a normal -1 error code.
151 */
78606263 152 def->free(object);
e579e0f7
MB
153 return -1;
154 }
c6ac28fd 155
e579e0f7
MB
156 *object_out = git_cache_store_parsed(&repo->objects, object);
157 return 0;
c6ac28fd
RB
158}
159
78606263
RB
160void git_object__free(void *obj)
161{
ac3d33df 162 git_object_t type = ((git_object *)obj)->cached.type;
78606263
RB
163
164 if (type < 0 || ((size_t)type) >= ARRAY_SIZE(git_objects_table) ||
165 !git_objects_table[type].free)
166 git__free(obj);
167 else
168 git_objects_table[type].free(obj);
169}
170
9462c471
VM
171int git_object_lookup_prefix(
172 git_object **object_out,
173 git_repository *repo,
174 const git_oid *id,
b8457baa 175 size_t len,
ac3d33df 176 git_object_t type)
5de079b8
VM
177{
178 git_object *object = NULL;
9462c471 179 git_odb *odb = NULL;
e583334c 180 git_odb_object *odb_obj = NULL;
e172cf08 181 int error = 0;
5de079b8 182
c25aa7cd
PP
183 GIT_ASSERT_ARG(repo);
184 GIT_ASSERT_ARG(object_out);
185 GIT_ASSERT_ARG(id);
5de079b8 186
8915a140 187 if (len < GIT_OID_MINPREFIXLEN) {
ac3d33df 188 git_error_set(GIT_ERROR_OBJECT, "ambiguous lookup - OID prefix is too short");
904b67e6 189 return GIT_EAMBIGUOUS;
8915a140 190 }
d0323a5f 191
9462c471 192 error = git_repository_odb__weakptr(&odb, repo);
e172cf08 193 if (error < 0)
9462c471
VM
194 return error;
195
3d9ef2dc
VM
196 if (len > GIT_OID_HEXSZ)
197 len = GIT_OID_HEXSZ;
bd1aa741 198
3d9ef2dc 199 if (len == GIT_OID_HEXSZ) {
5df18424
VM
200 git_cached_obj *cached = NULL;
201
dd453c4d
MP
202 /* We want to match the full id : we can first look up in the cache,
203 * since there is no need to check for non ambiguousity
204 */
5df18424
VM
205 cached = git_cache_get_any(&repo->objects, id);
206 if (cached != NULL) {
207 if (cached->flags == GIT_CACHE_STORE_PARSED) {
208 object = (git_object *)cached;
209
ac3d33df 210 if (type != GIT_OBJECT_ANY && type != object->cached.type) {
5df18424 211 git_object_free(object);
ac3d33df 212 git_error_set(GIT_ERROR_INVALID,
22a2d3d5 213 "the requested type does not match the type in the ODB");
5df18424
VM
214 return GIT_ENOTFOUND;
215 }
216
217 *object_out = object;
218 return 0;
219 } else if (cached->flags == GIT_CACHE_STORE_RAW) {
220 odb_obj = (git_odb_object *)cached;
221 } else {
c25aa7cd 222 GIT_ASSERT(!"Wrong caching type in the global object cache");
7d3ec3ca 223 }
5df18424
VM
224 } else {
225 /* Object was not found in the cache, let's explore the backends.
226 * We could just use git_odb_read_unique_short_oid,
227 * it is the same cost for packed and loose object backends,
228 * but it may be much more costly for sqlite and hiredis.
229 */
230 error = git_odb_read(&odb_obj, odb, id);
dd453c4d 231 }
dd453c4d 232 } else {
61d7328d 233 git_oid short_oid = {{ 0 }};
dd453c4d 234
61d7328d 235 git_oid__cpy_prefix(&short_oid, id, len);
dd453c4d 236
3d9ef2dc 237 /* If len < GIT_OID_HEXSZ (a strict short oid was given), we have
dd453c4d
MP
238 * 2 options :
239 * - We always search in the cache first. If we find that short oid is
87d9869f
VM
240 * ambiguous, we can stop. But in all the other cases, we must then
241 * explore all the backends (to find an object if there was match,
242 * or to check that oid is not ambiguous if we have found 1 match in
243 * the cache)
dd453c4d
MP
244 * - We never explore the cache, go right to exploring the backends
245 * We chose the latter : we explore directly the backends.
246 */
9462c471 247 error = git_odb_read_prefix(&odb_obj, odb, &short_oid, len);
5de079b8
VM
248 }
249
3aa351ea 250 if (error < 0)
282283ac 251 return error;
5de079b8 252
c6ac28fd 253 error = git_object__from_odb_object(object_out, repo, odb_obj, type);
5de079b8 254
45e79e37 255 git_odb_object_free(odb_obj);
72a3fe42 256
c6ac28fd 257 return error;
5de079b8
VM
258}
259
ac3d33df 260int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_object_t type) {
d0323a5f 261 return git_object_lookup_prefix(object_out, repo, id, GIT_OID_HEXSZ, type);
dd453c4d
MP
262}
263
45e79e37 264void git_object_free(git_object *object)
48c27f86
VM
265{
266 if (object == NULL)
267 return;
268
5df18424 269 git_cached_obj_decref(object);
48c27f86
VM
270}
271
17cdf252 272const git_oid *git_object_id(const git_object *obj)
e52ed7a5 273{
c25aa7cd 274 GIT_ASSERT_ARG_WITH_RETVAL(obj, NULL);
72a3fe42 275 return &obj->cached.oid;
e52ed7a5
VM
276}
277
ac3d33df 278git_object_t git_object_type(const git_object *obj)
e52ed7a5 279{
c25aa7cd 280 GIT_ASSERT_ARG_WITH_RETVAL(obj, GIT_OBJECT_INVALID);
cf7850a4 281 return obj->cached.type;
e52ed7a5
VM
282}
283
17cdf252 284git_repository *git_object_owner(const git_object *obj)
e52ed7a5 285{
c25aa7cd 286 GIT_ASSERT_ARG_WITH_RETVAL(obj, NULL);
e52ed7a5
VM
287 return obj->repo;
288}
289
ac3d33df 290const char *git_object_type2string(git_object_t type)
e52ed7a5
VM
291{
292 if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table))
293 return "";
294
295 return git_objects_table[type].str;
296}
297
ac3d33df 298git_object_t git_object_string2type(const char *str)
eae0bfdc
PP
299{
300 if (!str)
ac3d33df 301 return GIT_OBJECT_INVALID;
eae0bfdc
PP
302
303 return git_object_stringn2type(str, strlen(str));
304}
305
ac3d33df 306git_object_t git_object_stringn2type(const char *str, size_t len)
e52ed7a5
VM
307{
308 size_t i;
309
eae0bfdc 310 if (!str || !len || !*str)
ac3d33df 311 return GIT_OBJECT_INVALID;
e52ed7a5
VM
312
313 for (i = 0; i < ARRAY_SIZE(git_objects_table); i++)
eae0bfdc
PP
314 if (*git_objects_table[i].str &&
315 !git__prefixncmp(str, len, git_objects_table[i].str))
ac3d33df 316 return (git_object_t)i;
e52ed7a5 317
ac3d33df 318 return GIT_OBJECT_INVALID;
e52ed7a5
VM
319}
320
ac3d33df 321int git_object_typeisloose(git_object_t type)
e52ed7a5
VM
322{
323 if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table))
324 return 0;
325
78606263 326 return (git_objects_table[type].size > 0) ? 1 : 0;
e52ed7a5
VM
327}
328
ac3d33df 329size_t git_object__size(git_object_t type)
e52ed7a5
VM
330{
331 if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table))
332 return 0;
333
334 return git_objects_table[type].size;
335}
336
db9be945 337static int dereference_object(git_object **dereferenced, git_object *obj)
338{
ac3d33df 339 git_object_t type = git_object_type(obj);
db9be945 340
341 switch (type) {
ac3d33df 342 case GIT_OBJECT_COMMIT:
db9be945 343 return git_commit_tree((git_tree **)dereferenced, (git_commit*)obj);
db9be945 344
ac3d33df 345 case GIT_OBJECT_TAG:
db9be945 346 return git_tag_target(dereferenced, (git_tag*)obj);
d8057a5b 347
ac3d33df
JK
348 case GIT_OBJECT_BLOB:
349 case GIT_OBJECT_TREE:
753e17b0 350 return GIT_EPEEL;
db9be945 351
352 default:
bc05f30c 353 return GIT_EINVALIDSPEC;
db9be945 354 }
355}
356
ac3d33df 357static int peel_error(int error, const git_oid *oid, git_object_t type)
bc05f30c 358{
359 const char *type_name;
360 char hex_oid[GIT_OID_HEXSZ + 1];
361
362 type_name = git_object_type2string(type);
363
364 git_oid_fmt(hex_oid, oid);
365 hex_oid[GIT_OID_HEXSZ] = '\0';
366
ac3d33df
JK
367 git_error_set(GIT_ERROR_OBJECT, "the git_object of id '%s' can not be "
368 "successfully peeled into a %s (git_object_t=%i).", hex_oid, type_name, type);
bc05f30c 369
370 return error;
371}
372
ac3d33df 373static int check_type_combination(git_object_t type, git_object_t target)
753e17b0
CMN
374{
375 if (type == target)
376 return 0;
377
378 switch (type) {
ac3d33df
JK
379 case GIT_OBJECT_BLOB:
380 case GIT_OBJECT_TREE:
753e17b0
CMN
381 /* a blob or tree can never be peeled to anything but themselves */
382 return GIT_EINVALIDSPEC;
383 break;
ac3d33df 384 case GIT_OBJECT_COMMIT:
753e17b0 385 /* a commit can only be peeled to a tree */
ac3d33df 386 if (target != GIT_OBJECT_TREE && target != GIT_OBJECT_ANY)
753e17b0
CMN
387 return GIT_EINVALIDSPEC;
388 break;
ac3d33df 389 case GIT_OBJECT_TAG:
753e17b0
CMN
390 /* a tag may point to anything, so we let anything through */
391 break;
392 default:
393 return GIT_EINVALIDSPEC;
394 }
395
396 return 0;
397}
398
db9be945 399int git_object_peel(
d8057a5b 400 git_object **peeled,
cfbe4be3 401 const git_object *object,
ac3d33df 402 git_object_t target_type)
db9be945 403{
404 git_object *source, *deref = NULL;
bc05f30c 405 int error;
406
c25aa7cd
PP
407 GIT_ASSERT_ARG(object);
408 GIT_ASSERT_ARG(peeled);
db9be945 409
c25aa7cd 410 GIT_ASSERT_ARG(target_type == GIT_OBJECT_TAG ||
ac3d33df
JK
411 target_type == GIT_OBJECT_COMMIT ||
412 target_type == GIT_OBJECT_TREE ||
413 target_type == GIT_OBJECT_BLOB ||
414 target_type == GIT_OBJECT_ANY);
8915a140 415
753e17b0
CMN
416 if ((error = check_type_combination(git_object_type(object), target_type)) < 0)
417 return peel_error(error, git_object_id(object), target_type);
418
419 if (git_object_type(object) == target_type)
420 return git_object_dup(peeled, (git_object *)object);
421
cfbe4be3 422 source = (git_object *)object;
db9be945 423
bc05f30c 424 while (!(error = dereference_object(&deref, source))) {
db9be945 425
426 if (source != object)
427 git_object_free(source);
428
429 if (git_object_type(deref) == target_type) {
430 *peeled = deref;
431 return 0;
432 }
433
ac3d33df 434 if (target_type == GIT_OBJECT_ANY &&
d8057a5b
RB
435 git_object_type(deref) != git_object_type(object))
436 {
437 *peeled = deref;
438 return 0;
439 }
440
db9be945 441 source = deref;
442 deref = NULL;
443 }
444
db9be945 445 if (source != object)
446 git_object_free(source);
d8057a5b 447
db9be945 448 git_object_free(deref);
bc05f30c 449
450 if (error)
451 error = peel_error(error, git_object_id(object), target_type);
452
453 return error;
db9be945 454}
613d5eb9 455
575a54db
VM
456int git_object_dup(git_object **dest, git_object *source)
457{
458 git_cached_obj_incref(source);
459 *dest = source;
460 return 0;
461}
ceab4e26
BS
462
463int git_object_lookup_bypath(
464 git_object **out,
465 const git_object *treeish,
466 const char *path,
ac3d33df 467 git_object_t type)
ceab4e26
BS
468{
469 int error = -1;
470 git_tree *tree = NULL;
471 git_tree_entry *entry = NULL;
ceab4e26 472
c25aa7cd
PP
473 GIT_ASSERT_ARG(out);
474 GIT_ASSERT_ARG(treeish);
475 GIT_ASSERT_ARG(path);
ceab4e26 476
ac3d33df 477 if ((error = git_object_peel((git_object**)&tree, treeish, GIT_OBJECT_TREE)) < 0 ||
ba02079f 478 (error = git_tree_entry_bypath(&entry, tree, path)) < 0)
ceab4e26
BS
479 {
480 goto cleanup;
481 }
482
ac3d33df 483 if (type != GIT_OBJECT_ANY && git_tree_entry_type(entry) != type)
ba02079f 484 {
ac3d33df 485 git_error_set(GIT_ERROR_OBJECT,
ceab4e26
BS
486 "object at path '%s' is not of the asked-for type %d",
487 path, type);
488 error = GIT_EINVALIDSPEC;
ba02079f 489 goto cleanup;
ceab4e26
BS
490 }
491
ba02079f
BS
492 error = git_tree_entry_to_object(out, git_object_owner(treeish), entry);
493
ceab4e26
BS
494cleanup:
495 git_tree_entry_free(entry);
496 git_tree_free(tree);
497 return error;
498}
13f7ecd7 499
e579e0f7 500static int git_object__short_id(git_str *out, const git_object *obj)
13f7ecd7
RB
501{
502 git_repository *repo;
503 int len = GIT_ABBREV_DEFAULT, error;
504 git_oid id = {{0}};
505 git_odb *odb;
506
c25aa7cd
PP
507 GIT_ASSERT_ARG(out);
508 GIT_ASSERT_ARG(obj);
509
13f7ecd7
RB
510 repo = git_object_owner(obj);
511
22a2d3d5 512 if ((error = git_repository__configmap_lookup(&len, repo, GIT_CONFIGMAP_ABBREV)) < 0)
13f7ecd7
RB
513 return error;
514
515 if ((error = git_repository_odb(&odb, repo)) < 0)
516 return error;
517
518 while (len < GIT_OID_HEXSZ) {
519 /* set up short oid */
520 memcpy(&id.id, &obj->cached.oid.id, (len + 1) / 2);
521 if (len & 1)
522 id.id[len / 2] &= 0xf0;
523
524 error = git_odb_exists_prefix(NULL, odb, &id, len);
525 if (error != GIT_EAMBIGUOUS)
526 break;
527
ac3d33df 528 git_error_clear();
13f7ecd7
RB
529 len++;
530 }
531
e579e0f7 532 if (!error && !(error = git_str_grow(out, len + 1))) {
13f7ecd7
RB
533 git_oid_tostr(out->ptr, len + 1, &id);
534 out->size = len;
535 }
536
537 git_odb_free(odb);
538
539 return error;
540}
541
e579e0f7
MB
542int git_object_short_id(git_buf *out, const git_object *obj)
543{
544 GIT_BUF_WRAP_PRIVATE(out, git_object__short_id, obj);
545}
546
3ef01e77 547bool git_object__is_valid(
ac3d33df 548 git_repository *repo, const git_oid *id, git_object_t expected_type)
3ef01e77
ET
549{
550 git_odb *odb;
ac3d33df 551 git_object_t actual_type;
3ef01e77
ET
552 size_t len;
553 int error;
554
555 if (!git_object__strict_input_validation)
556 return true;
557
558 if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
559 (error = git_odb_read_header(&len, &actual_type, odb, id)) < 0)
560 return false;
561
ac3d33df
JK
562 if (expected_type != GIT_OBJECT_ANY && expected_type != actual_type) {
563 git_error_set(GIT_ERROR_INVALID,
3ef01e77
ET
564 "the requested type does not match the type in the ODB");
565 return false;
566 }
567
568 return true;
569}
e579e0f7
MB
570
571int git_object_rawcontent_is_valid(
572 int *valid,
573 const char *buf,
574 size_t len,
575 git_object_t type)
576{
577 git_object *obj = NULL;
578 int error;
579
580 GIT_ASSERT_ARG(valid);
581 GIT_ASSERT_ARG(buf);
582
583 /* Blobs are always valid; don't bother parsing. */
584 if (type == GIT_OBJECT_BLOB) {
585 *valid = 1;
586 return 0;
587 }
588
589 error = git_object__from_raw(&obj, buf, len, type);
590 git_object_free(obj);
591
592 if (error == 0) {
593 *valid = 1;
594 return 0;
595 } else if (error == GIT_EINVALID) {
596 *valid = 0;
597 return 0;
598 }
599
600 return error;
601}