2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
10 #include "git2/object.h"
12 #include "repository.h"
21 bool git_object__strict_input_validation
= true;
23 extern int git_odb_hash(git_oid
*out
, const void *data
, size_t len
, git_object_t type
);
24 size_t git_object__size(git_object_t type
);
27 const char *str
; /* type name string */
28 size_t size
; /* size in bytes of the object structure */
30 int (*parse
)(void *self
, git_odb_object
*obj
);
31 int (*parse_raw
)(void *self
, const char *data
, size_t size
);
32 void (*free
)(void *self
);
35 static git_object_def git_objects_table
[] = {
36 /* 0 = GIT_OBJECT__EXT1 */
37 { "", 0, NULL
, NULL
, NULL
},
39 /* 1 = GIT_OBJECT_COMMIT */
40 { "commit", sizeof(git_commit
), git_commit__parse
, git_commit__parse_raw
, git_commit__free
},
42 /* 2 = GIT_OBJECT_TREE */
43 { "tree", sizeof(git_tree
), git_tree__parse
, git_tree__parse_raw
, git_tree__free
},
45 /* 3 = GIT_OBJECT_BLOB */
46 { "blob", sizeof(git_blob
), git_blob__parse
, git_blob__parse_raw
, git_blob__free
},
48 /* 4 = GIT_OBJECT_TAG */
49 { "tag", sizeof(git_tag
), git_tag__parse
, git_tag__parse_raw
, git_tag__free
},
51 /* 5 = GIT_OBJECT__EXT2 */
52 { "", 0, NULL
, NULL
, NULL
},
53 /* 6 = GIT_OBJECT_OFS_DELTA */
54 { "OFS_DELTA", 0, NULL
, NULL
, NULL
},
55 /* 7 = GIT_OBJECT_REF_DELTA */
56 { "REF_DELTA", 0, NULL
, NULL
, NULL
},
59 int git_object__from_raw(
60 git_object
**object_out
,
73 /* Validate type match */
74 if (type
!= GIT_OBJECT_BLOB
&& type
!= GIT_OBJECT_TREE
&& type
!= GIT_OBJECT_COMMIT
&& type
!= GIT_OBJECT_TAG
) {
75 git_error_set(GIT_ERROR_INVALID
, "the requested type is invalid");
79 if ((object_size
= git_object__size(type
)) == 0) {
80 git_error_set(GIT_ERROR_INVALID
, "the requested type is invalid");
84 /* Allocate and initialize base object */
85 object
= git__calloc(1, object_size
);
86 GIT_ERROR_CHECK_ALLOC(object
);
87 object
->cached
.flags
= GIT_CACHE_STORE_PARSED
;
88 object
->cached
.type
= type
;
89 if ((error
= git_odb_hash(&object
->cached
.oid
, data
, size
, type
)) < 0)
92 /* Parse raw object data */
93 def
= &git_objects_table
[type
];
94 assert(def
->free
&& def
->parse_raw
);
96 if ((error
= def
->parse_raw(object
, data
, size
)) < 0) {
101 git_cached_obj_incref(object
);
102 *object_out
= object
;
107 int git_object__from_odb_object(
108 git_object
**object_out
,
109 git_repository
*repo
,
110 git_odb_object
*odb_obj
,
116 git_object
*object
= NULL
;
121 /* Validate type match */
122 if (type
!= GIT_OBJECT_ANY
&& type
!= odb_obj
->cached
.type
) {
123 git_error_set(GIT_ERROR_INVALID
,
124 "the requested type does not match the type in the ODB");
125 return GIT_ENOTFOUND
;
128 if ((object_size
= git_object__size(odb_obj
->cached
.type
)) == 0) {
129 git_error_set(GIT_ERROR_INVALID
, "the requested type is invalid");
130 return GIT_ENOTFOUND
;
133 /* Allocate and initialize base object */
134 object
= git__calloc(1, object_size
);
135 GIT_ERROR_CHECK_ALLOC(object
);
137 git_oid_cpy(&object
->cached
.oid
, &odb_obj
->cached
.oid
);
138 object
->cached
.type
= odb_obj
->cached
.type
;
139 object
->cached
.size
= odb_obj
->cached
.size
;
142 /* Parse raw object data */
143 def
= &git_objects_table
[odb_obj
->cached
.type
];
144 assert(def
->free
&& def
->parse
);
146 if ((error
= def
->parse(object
, odb_obj
)) < 0)
149 *object_out
= git_cache_store_parsed(&repo
->objects
, object
);
154 void git_object__free(void *obj
)
156 git_object_t type
= ((git_object
*)obj
)->cached
.type
;
158 if (type
< 0 || ((size_t)type
) >= ARRAY_SIZE(git_objects_table
) ||
159 !git_objects_table
[type
].free
)
162 git_objects_table
[type
].free(obj
);
165 int git_object_lookup_prefix(
166 git_object
**object_out
,
167 git_repository
*repo
,
172 git_object
*object
= NULL
;
174 git_odb_object
*odb_obj
= NULL
;
177 assert(repo
&& object_out
&& id
);
179 if (len
< GIT_OID_MINPREFIXLEN
) {
180 git_error_set(GIT_ERROR_OBJECT
, "ambiguous lookup - OID prefix is too short");
181 return GIT_EAMBIGUOUS
;
184 error
= git_repository_odb__weakptr(&odb
, repo
);
188 if (len
> GIT_OID_HEXSZ
)
191 if (len
== GIT_OID_HEXSZ
) {
192 git_cached_obj
*cached
= NULL
;
194 /* We want to match the full id : we can first look up in the cache,
195 * since there is no need to check for non ambiguousity
197 cached
= git_cache_get_any(&repo
->objects
, id
);
198 if (cached
!= NULL
) {
199 if (cached
->flags
== GIT_CACHE_STORE_PARSED
) {
200 object
= (git_object
*)cached
;
202 if (type
!= GIT_OBJECT_ANY
&& type
!= object
->cached
.type
) {
203 git_object_free(object
);
204 git_error_set(GIT_ERROR_INVALID
,
205 "the requested type does not match the type in the ODB");
206 return GIT_ENOTFOUND
;
209 *object_out
= object
;
211 } else if (cached
->flags
== GIT_CACHE_STORE_RAW
) {
212 odb_obj
= (git_odb_object
*)cached
;
214 assert(!"Wrong caching type in the global object cache");
217 /* Object was not found in the cache, let's explore the backends.
218 * We could just use git_odb_read_unique_short_oid,
219 * it is the same cost for packed and loose object backends,
220 * but it may be much more costly for sqlite and hiredis.
222 error
= git_odb_read(&odb_obj
, odb
, id
);
225 git_oid short_oid
= {{ 0 }};
227 git_oid__cpy_prefix(&short_oid
, id
, len
);
229 /* If len < GIT_OID_HEXSZ (a strict short oid was given), we have
231 * - We always search in the cache first. If we find that short oid is
232 * ambiguous, we can stop. But in all the other cases, we must then
233 * explore all the backends (to find an object if there was match,
234 * or to check that oid is not ambiguous if we have found 1 match in
236 * - We never explore the cache, go right to exploring the backends
237 * We chose the latter : we explore directly the backends.
239 error
= git_odb_read_prefix(&odb_obj
, odb
, &short_oid
, len
);
245 error
= git_object__from_odb_object(object_out
, repo
, odb_obj
, type
);
247 git_odb_object_free(odb_obj
);
252 int git_object_lookup(git_object
**object_out
, git_repository
*repo
, const git_oid
*id
, git_object_t type
) {
253 return git_object_lookup_prefix(object_out
, repo
, id
, GIT_OID_HEXSZ
, type
);
256 void git_object_free(git_object
*object
)
261 git_cached_obj_decref(object
);
264 const git_oid
*git_object_id(const git_object
*obj
)
267 return &obj
->cached
.oid
;
270 git_object_t
git_object_type(const git_object
*obj
)
273 return obj
->cached
.type
;
276 git_repository
*git_object_owner(const git_object
*obj
)
282 const char *git_object_type2string(git_object_t type
)
284 if (type
< 0 || ((size_t) type
) >= ARRAY_SIZE(git_objects_table
))
287 return git_objects_table
[type
].str
;
290 git_object_t
git_object_string2type(const char *str
)
293 return GIT_OBJECT_INVALID
;
295 return git_object_stringn2type(str
, strlen(str
));
298 git_object_t
git_object_stringn2type(const char *str
, size_t len
)
302 if (!str
|| !len
|| !*str
)
303 return GIT_OBJECT_INVALID
;
305 for (i
= 0; i
< ARRAY_SIZE(git_objects_table
); i
++)
306 if (*git_objects_table
[i
].str
&&
307 !git__prefixncmp(str
, len
, git_objects_table
[i
].str
))
308 return (git_object_t
)i
;
310 return GIT_OBJECT_INVALID
;
313 int git_object_typeisloose(git_object_t type
)
315 if (type
< 0 || ((size_t) type
) >= ARRAY_SIZE(git_objects_table
))
318 return (git_objects_table
[type
].size
> 0) ? 1 : 0;
321 size_t git_object__size(git_object_t type
)
323 if (type
< 0 || ((size_t) type
) >= ARRAY_SIZE(git_objects_table
))
326 return git_objects_table
[type
].size
;
329 static int dereference_object(git_object
**dereferenced
, git_object
*obj
)
331 git_object_t type
= git_object_type(obj
);
334 case GIT_OBJECT_COMMIT
:
335 return git_commit_tree((git_tree
**)dereferenced
, (git_commit
*)obj
);
338 return git_tag_target(dereferenced
, (git_tag
*)obj
);
340 case GIT_OBJECT_BLOB
:
341 case GIT_OBJECT_TREE
:
345 return GIT_EINVALIDSPEC
;
349 static int peel_error(int error
, const git_oid
*oid
, git_object_t type
)
351 const char *type_name
;
352 char hex_oid
[GIT_OID_HEXSZ
+ 1];
354 type_name
= git_object_type2string(type
);
356 git_oid_fmt(hex_oid
, oid
);
357 hex_oid
[GIT_OID_HEXSZ
] = '\0';
359 git_error_set(GIT_ERROR_OBJECT
, "the git_object of id '%s' can not be "
360 "successfully peeled into a %s (git_object_t=%i).", hex_oid
, type_name
, type
);
365 static int check_type_combination(git_object_t type
, git_object_t target
)
371 case GIT_OBJECT_BLOB
:
372 case GIT_OBJECT_TREE
:
373 /* a blob or tree can never be peeled to anything but themselves */
374 return GIT_EINVALIDSPEC
;
376 case GIT_OBJECT_COMMIT
:
377 /* a commit can only be peeled to a tree */
378 if (target
!= GIT_OBJECT_TREE
&& target
!= GIT_OBJECT_ANY
)
379 return GIT_EINVALIDSPEC
;
382 /* a tag may point to anything, so we let anything through */
385 return GIT_EINVALIDSPEC
;
393 const git_object
*object
,
394 git_object_t target_type
)
396 git_object
*source
, *deref
= NULL
;
399 assert(object
&& peeled
);
401 assert(target_type
== GIT_OBJECT_TAG
||
402 target_type
== GIT_OBJECT_COMMIT
||
403 target_type
== GIT_OBJECT_TREE
||
404 target_type
== GIT_OBJECT_BLOB
||
405 target_type
== GIT_OBJECT_ANY
);
407 if ((error
= check_type_combination(git_object_type(object
), target_type
)) < 0)
408 return peel_error(error
, git_object_id(object
), target_type
);
410 if (git_object_type(object
) == target_type
)
411 return git_object_dup(peeled
, (git_object
*)object
);
413 source
= (git_object
*)object
;
415 while (!(error
= dereference_object(&deref
, source
))) {
417 if (source
!= object
)
418 git_object_free(source
);
420 if (git_object_type(deref
) == target_type
) {
425 if (target_type
== GIT_OBJECT_ANY
&&
426 git_object_type(deref
) != git_object_type(object
))
436 if (source
!= object
)
437 git_object_free(source
);
439 git_object_free(deref
);
442 error
= peel_error(error
, git_object_id(object
), target_type
);
447 int git_object_dup(git_object
**dest
, git_object
*source
)
449 git_cached_obj_incref(source
);
454 int git_object_lookup_bypath(
456 const git_object
*treeish
,
461 git_tree
*tree
= NULL
;
462 git_tree_entry
*entry
= NULL
;
464 assert(out
&& treeish
&& path
);
466 if ((error
= git_object_peel((git_object
**)&tree
, treeish
, GIT_OBJECT_TREE
)) < 0 ||
467 (error
= git_tree_entry_bypath(&entry
, tree
, path
)) < 0)
472 if (type
!= GIT_OBJECT_ANY
&& git_tree_entry_type(entry
) != type
)
474 git_error_set(GIT_ERROR_OBJECT
,
475 "object at path '%s' is not of the asked-for type %d",
477 error
= GIT_EINVALIDSPEC
;
481 error
= git_tree_entry_to_object(out
, git_object_owner(treeish
), entry
);
484 git_tree_entry_free(entry
);
489 int git_object_short_id(git_buf
*out
, const git_object
*obj
)
491 git_repository
*repo
;
492 int len
= GIT_ABBREV_DEFAULT
, error
;
498 git_buf_sanitize(out
);
499 repo
= git_object_owner(obj
);
501 if ((error
= git_repository__configmap_lookup(&len
, repo
, GIT_CONFIGMAP_ABBREV
)) < 0)
504 if ((error
= git_repository_odb(&odb
, repo
)) < 0)
507 while (len
< GIT_OID_HEXSZ
) {
508 /* set up short oid */
509 memcpy(&id
.id
, &obj
->cached
.oid
.id
, (len
+ 1) / 2);
511 id
.id
[len
/ 2] &= 0xf0;
513 error
= git_odb_exists_prefix(NULL
, odb
, &id
, len
);
514 if (error
!= GIT_EAMBIGUOUS
)
521 if (!error
&& !(error
= git_buf_grow(out
, len
+ 1))) {
522 git_oid_tostr(out
->ptr
, len
+ 1, &id
);
531 bool git_object__is_valid(
532 git_repository
*repo
, const git_oid
*id
, git_object_t expected_type
)
535 git_object_t actual_type
;
539 if (!git_object__strict_input_validation
)
542 if ((error
= git_repository_odb__weakptr(&odb
, repo
)) < 0 ||
543 (error
= git_odb_read_header(&len
, &actual_type
, odb
, id
)) < 0)
546 if (expected_type
!= GIT_OBJECT_ANY
&& expected_type
!= actual_type
) {
547 git_error_set(GIT_ERROR_INVALID
,
548 "the requested type does not match the type in the ODB");