]> git.proxmox.com Git - libgit2.git/blob - src/object.c
Upload to experimental
[libgit2.git] / src / object.c
1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
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.
6 */
7
8 #include "object.h"
9
10 #include "git2/object.h"
11
12 #include "repository.h"
13
14 #include "buf.h"
15 #include "commit.h"
16 #include "hash.h"
17 #include "tree.h"
18 #include "blob.h"
19 #include "oid.h"
20 #include "tag.h"
21
22 bool git_object__strict_input_validation = true;
23
24 extern int git_odb_hash(git_oid *out, const void *data, size_t len, git_object_t type);
25 size_t git_object__size(git_object_t type);
26
27 typedef struct {
28 const char *str; /* type name string */
29 size_t size; /* size in bytes of the object structure */
30
31 int (*parse)(void *self, git_odb_object *obj);
32 int (*parse_raw)(void *self, const char *data, size_t size);
33 void (*free)(void *self);
34 } git_object_def;
35
36 static git_object_def git_objects_table[] = {
37 /* 0 = GIT_OBJECT__EXT1 */
38 { "", 0, NULL, NULL, NULL },
39
40 /* 1 = GIT_OBJECT_COMMIT */
41 { "commit", sizeof(git_commit), git_commit__parse, git_commit__parse_raw, git_commit__free },
42
43 /* 2 = GIT_OBJECT_TREE */
44 { "tree", sizeof(git_tree), git_tree__parse, git_tree__parse_raw, git_tree__free },
45
46 /* 3 = GIT_OBJECT_BLOB */
47 { "blob", sizeof(git_blob), git_blob__parse, git_blob__parse_raw, git_blob__free },
48
49 /* 4 = GIT_OBJECT_TAG */
50 { "tag", sizeof(git_tag), git_tag__parse, git_tag__parse_raw, git_tag__free },
51
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 },
58 };
59
60 int 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
71 GIT_ASSERT_ARG(object_out);
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;
90 if ((error = git_odb_hash(&object->cached.oid, data, size, type)) < 0)
91 return error;
92
93 /* Parse raw object data */
94 def = &git_objects_table[type];
95 GIT_ASSERT(def->free && def->parse_raw);
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
108 int git_object__from_odb_object(
109 git_object **object_out,
110 git_repository *repo,
111 git_odb_object *odb_obj,
112 git_object_t type)
113 {
114 int error;
115 size_t object_size;
116 git_object_def *def;
117 git_object *object = NULL;
118
119 GIT_ASSERT_ARG(object_out);
120 *object_out = NULL;
121
122 /* Validate type match */
123 if (type != GIT_OBJECT_ANY && type != odb_obj->cached.type) {
124 git_error_set(GIT_ERROR_INVALID,
125 "the requested type does not match the type in the ODB");
126 return GIT_ENOTFOUND;
127 }
128
129 if ((object_size = git_object__size(odb_obj->cached.type)) == 0) {
130 git_error_set(GIT_ERROR_INVALID, "the requested type is invalid");
131 return GIT_ENOTFOUND;
132 }
133
134 /* Allocate and initialize base object */
135 object = git__calloc(1, object_size);
136 GIT_ERROR_CHECK_ALLOC(object);
137
138 git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid);
139 object->cached.type = odb_obj->cached.type;
140 object->cached.size = odb_obj->cached.size;
141 object->repo = repo;
142
143 /* Parse raw object data */
144 def = &git_objects_table[odb_obj->cached.type];
145 GIT_ASSERT(def->free && def->parse);
146
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 */
152 def->free(object);
153 return -1;
154 }
155
156 *object_out = git_cache_store_parsed(&repo->objects, object);
157 return 0;
158 }
159
160 void git_object__free(void *obj)
161 {
162 git_object_t type = ((git_object *)obj)->cached.type;
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
171 int git_object_lookup_prefix(
172 git_object **object_out,
173 git_repository *repo,
174 const git_oid *id,
175 size_t len,
176 git_object_t type)
177 {
178 git_object *object = NULL;
179 git_odb *odb = NULL;
180 git_odb_object *odb_obj = NULL;
181 int error = 0;
182
183 GIT_ASSERT_ARG(repo);
184 GIT_ASSERT_ARG(object_out);
185 GIT_ASSERT_ARG(id);
186
187 if (len < GIT_OID_MINPREFIXLEN) {
188 git_error_set(GIT_ERROR_OBJECT, "ambiguous lookup - OID prefix is too short");
189 return GIT_EAMBIGUOUS;
190 }
191
192 error = git_repository_odb__weakptr(&odb, repo);
193 if (error < 0)
194 return error;
195
196 if (len > GIT_OID_HEXSZ)
197 len = GIT_OID_HEXSZ;
198
199 if (len == GIT_OID_HEXSZ) {
200 git_cached_obj *cached = NULL;
201
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 */
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
210 if (type != GIT_OBJECT_ANY && type != object->cached.type) {
211 git_object_free(object);
212 git_error_set(GIT_ERROR_INVALID,
213 "the requested type does not match the type in the ODB");
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 {
222 GIT_ASSERT(!"Wrong caching type in the global object cache");
223 }
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);
231 }
232 } else {
233 git_oid short_oid = {{ 0 }};
234
235 git_oid__cpy_prefix(&short_oid, id, len);
236
237 /* If len < GIT_OID_HEXSZ (a strict short oid was given), we have
238 * 2 options :
239 * - We always search in the cache first. If we find that short oid is
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)
244 * - We never explore the cache, go right to exploring the backends
245 * We chose the latter : we explore directly the backends.
246 */
247 error = git_odb_read_prefix(&odb_obj, odb, &short_oid, len);
248 }
249
250 if (error < 0)
251 return error;
252
253 error = git_object__from_odb_object(object_out, repo, odb_obj, type);
254
255 git_odb_object_free(odb_obj);
256
257 return error;
258 }
259
260 int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_object_t type) {
261 return git_object_lookup_prefix(object_out, repo, id, GIT_OID_HEXSZ, type);
262 }
263
264 void git_object_free(git_object *object)
265 {
266 if (object == NULL)
267 return;
268
269 git_cached_obj_decref(object);
270 }
271
272 const git_oid *git_object_id(const git_object *obj)
273 {
274 GIT_ASSERT_ARG_WITH_RETVAL(obj, NULL);
275 return &obj->cached.oid;
276 }
277
278 git_object_t git_object_type(const git_object *obj)
279 {
280 GIT_ASSERT_ARG_WITH_RETVAL(obj, GIT_OBJECT_INVALID);
281 return obj->cached.type;
282 }
283
284 git_repository *git_object_owner(const git_object *obj)
285 {
286 GIT_ASSERT_ARG_WITH_RETVAL(obj, NULL);
287 return obj->repo;
288 }
289
290 const char *git_object_type2string(git_object_t type)
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
298 git_object_t git_object_string2type(const char *str)
299 {
300 if (!str)
301 return GIT_OBJECT_INVALID;
302
303 return git_object_stringn2type(str, strlen(str));
304 }
305
306 git_object_t git_object_stringn2type(const char *str, size_t len)
307 {
308 size_t i;
309
310 if (!str || !len || !*str)
311 return GIT_OBJECT_INVALID;
312
313 for (i = 0; i < ARRAY_SIZE(git_objects_table); i++)
314 if (*git_objects_table[i].str &&
315 !git__prefixncmp(str, len, git_objects_table[i].str))
316 return (git_object_t)i;
317
318 return GIT_OBJECT_INVALID;
319 }
320
321 int git_object_typeisloose(git_object_t type)
322 {
323 if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table))
324 return 0;
325
326 return (git_objects_table[type].size > 0) ? 1 : 0;
327 }
328
329 size_t git_object__size(git_object_t type)
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
337 static int dereference_object(git_object **dereferenced, git_object *obj)
338 {
339 git_object_t type = git_object_type(obj);
340
341 switch (type) {
342 case GIT_OBJECT_COMMIT:
343 return git_commit_tree((git_tree **)dereferenced, (git_commit*)obj);
344
345 case GIT_OBJECT_TAG:
346 return git_tag_target(dereferenced, (git_tag*)obj);
347
348 case GIT_OBJECT_BLOB:
349 case GIT_OBJECT_TREE:
350 return GIT_EPEEL;
351
352 default:
353 return GIT_EINVALIDSPEC;
354 }
355 }
356
357 static int peel_error(int error, const git_oid *oid, git_object_t type)
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
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);
369
370 return error;
371 }
372
373 static int check_type_combination(git_object_t type, git_object_t target)
374 {
375 if (type == target)
376 return 0;
377
378 switch (type) {
379 case GIT_OBJECT_BLOB:
380 case GIT_OBJECT_TREE:
381 /* a blob or tree can never be peeled to anything but themselves */
382 return GIT_EINVALIDSPEC;
383 break;
384 case GIT_OBJECT_COMMIT:
385 /* a commit can only be peeled to a tree */
386 if (target != GIT_OBJECT_TREE && target != GIT_OBJECT_ANY)
387 return GIT_EINVALIDSPEC;
388 break;
389 case GIT_OBJECT_TAG:
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
399 int git_object_peel(
400 git_object **peeled,
401 const git_object *object,
402 git_object_t target_type)
403 {
404 git_object *source, *deref = NULL;
405 int error;
406
407 GIT_ASSERT_ARG(object);
408 GIT_ASSERT_ARG(peeled);
409
410 GIT_ASSERT_ARG(target_type == GIT_OBJECT_TAG ||
411 target_type == GIT_OBJECT_COMMIT ||
412 target_type == GIT_OBJECT_TREE ||
413 target_type == GIT_OBJECT_BLOB ||
414 target_type == GIT_OBJECT_ANY);
415
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
422 source = (git_object *)object;
423
424 while (!(error = dereference_object(&deref, source))) {
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
434 if (target_type == GIT_OBJECT_ANY &&
435 git_object_type(deref) != git_object_type(object))
436 {
437 *peeled = deref;
438 return 0;
439 }
440
441 source = deref;
442 deref = NULL;
443 }
444
445 if (source != object)
446 git_object_free(source);
447
448 git_object_free(deref);
449
450 if (error)
451 error = peel_error(error, git_object_id(object), target_type);
452
453 return error;
454 }
455
456 int git_object_dup(git_object **dest, git_object *source)
457 {
458 git_cached_obj_incref(source);
459 *dest = source;
460 return 0;
461 }
462
463 int git_object_lookup_bypath(
464 git_object **out,
465 const git_object *treeish,
466 const char *path,
467 git_object_t type)
468 {
469 int error = -1;
470 git_tree *tree = NULL;
471 git_tree_entry *entry = NULL;
472
473 GIT_ASSERT_ARG(out);
474 GIT_ASSERT_ARG(treeish);
475 GIT_ASSERT_ARG(path);
476
477 if ((error = git_object_peel((git_object**)&tree, treeish, GIT_OBJECT_TREE)) < 0 ||
478 (error = git_tree_entry_bypath(&entry, tree, path)) < 0)
479 {
480 goto cleanup;
481 }
482
483 if (type != GIT_OBJECT_ANY && git_tree_entry_type(entry) != type)
484 {
485 git_error_set(GIT_ERROR_OBJECT,
486 "object at path '%s' is not of the asked-for type %d",
487 path, type);
488 error = GIT_EINVALIDSPEC;
489 goto cleanup;
490 }
491
492 error = git_tree_entry_to_object(out, git_object_owner(treeish), entry);
493
494 cleanup:
495 git_tree_entry_free(entry);
496 git_tree_free(tree);
497 return error;
498 }
499
500 static int git_object__short_id(git_str *out, const git_object *obj)
501 {
502 git_repository *repo;
503 int len = GIT_ABBREV_DEFAULT, error;
504 git_oid id = {{0}};
505 git_odb *odb;
506
507 GIT_ASSERT_ARG(out);
508 GIT_ASSERT_ARG(obj);
509
510 repo = git_object_owner(obj);
511
512 if ((error = git_repository__configmap_lookup(&len, repo, GIT_CONFIGMAP_ABBREV)) < 0)
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
528 git_error_clear();
529 len++;
530 }
531
532 if (!error && !(error = git_str_grow(out, len + 1))) {
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
542 int 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
547 bool git_object__is_valid(
548 git_repository *repo, const git_oid *id, git_object_t expected_type)
549 {
550 git_odb *odb;
551 git_object_t actual_type;
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
562 if (expected_type != GIT_OBJECT_ANY && expected_type != actual_type) {
563 git_error_set(GIT_ERROR_INVALID,
564 "the requested type does not match the type in the ODB");
565 return false;
566 }
567
568 return true;
569 }
570
571 int 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 }