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"
22 bool git_object__strict_input_validation
= true;
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
);
28 const char *str
; /* type name string */
29 size_t size
; /* size in bytes of the object structure */
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
);
36 static git_object_def git_objects_table
[] = {
37 /* 0 = GIT_OBJECT__EXT1 */
38 { "", 0, NULL
, NULL
, NULL
},
40 /* 1 = GIT_OBJECT_COMMIT */
41 { "commit", sizeof(git_commit
), git_commit__parse
, git_commit__parse_raw
, git_commit__free
},
43 /* 2 = GIT_OBJECT_TREE */
44 { "tree", sizeof(git_tree
), git_tree__parse
, git_tree__parse_raw
, git_tree__free
},
46 /* 3 = GIT_OBJECT_BLOB */
47 { "blob", sizeof(git_blob
), git_blob__parse
, git_blob__parse_raw
, git_blob__free
},
49 /* 4 = GIT_OBJECT_TAG */
50 { "tag", sizeof(git_tag
), git_tag__parse
, git_tag__parse_raw
, git_tag__free
},
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
},
60 int git_object__from_raw(
61 git_object
**object_out
,
71 GIT_ASSERT_ARG(object_out
);
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");
80 if ((object_size
= git_object__size(type
)) == 0) {
81 git_error_set(GIT_ERROR_INVALID
, "the requested type is invalid");
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)
93 /* Parse raw object data */
94 def
= &git_objects_table
[type
];
95 GIT_ASSERT(def
->free
&& def
->parse_raw
);
97 if ((error
= def
->parse_raw(object
, data
, size
)) < 0) {
102 git_cached_obj_incref(object
);
103 *object_out
= object
;
108 int git_object__from_odb_object(
109 git_object
**object_out
,
110 git_repository
*repo
,
111 git_odb_object
*odb_obj
,
117 git_object
*object
= NULL
;
119 GIT_ASSERT_ARG(object_out
);
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
;
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
;
134 /* Allocate and initialize base object */
135 object
= git__calloc(1, object_size
);
136 GIT_ERROR_CHECK_ALLOC(object
);
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
;
143 /* Parse raw object data */
144 def
= &git_objects_table
[odb_obj
->cached
.type
];
145 GIT_ASSERT(def
->free
&& def
->parse
);
147 if ((error
= def
->parse(object
, odb_obj
)) < 0) {
149 * parse returns EINVALID on invalid data; downgrade
150 * that to a normal -1 error code.
156 *object_out
= git_cache_store_parsed(&repo
->objects
, object
);
160 void git_object__free(void *obj
)
162 git_object_t type
= ((git_object
*)obj
)->cached
.type
;
164 if (type
< 0 || ((size_t)type
) >= ARRAY_SIZE(git_objects_table
) ||
165 !git_objects_table
[type
].free
)
168 git_objects_table
[type
].free(obj
);
171 int git_object_lookup_prefix(
172 git_object
**object_out
,
173 git_repository
*repo
,
178 git_object
*object
= NULL
;
180 git_odb_object
*odb_obj
= NULL
;
183 GIT_ASSERT_ARG(repo
);
184 GIT_ASSERT_ARG(object_out
);
187 if (len
< GIT_OID_MINPREFIXLEN
) {
188 git_error_set(GIT_ERROR_OBJECT
, "ambiguous lookup - OID prefix is too short");
189 return GIT_EAMBIGUOUS
;
192 error
= git_repository_odb__weakptr(&odb
, repo
);
196 if (len
> GIT_OID_HEXSZ
)
199 if (len
== GIT_OID_HEXSZ
) {
200 git_cached_obj
*cached
= NULL
;
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
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
;
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
;
217 *object_out
= object
;
219 } else if (cached
->flags
== GIT_CACHE_STORE_RAW
) {
220 odb_obj
= (git_odb_object
*)cached
;
222 GIT_ASSERT(!"Wrong caching type in the global object cache");
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.
230 error
= git_odb_read(&odb_obj
, odb
, id
);
233 git_oid short_oid
= {{ 0 }};
235 git_oid__cpy_prefix(&short_oid
, id
, len
);
237 /* If len < GIT_OID_HEXSZ (a strict short oid was given), we have
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
244 * - We never explore the cache, go right to exploring the backends
245 * We chose the latter : we explore directly the backends.
247 error
= git_odb_read_prefix(&odb_obj
, odb
, &short_oid
, len
);
253 error
= git_object__from_odb_object(object_out
, repo
, odb_obj
, type
);
255 git_odb_object_free(odb_obj
);
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
);
264 void git_object_free(git_object
*object
)
269 git_cached_obj_decref(object
);
272 const git_oid
*git_object_id(const git_object
*obj
)
274 GIT_ASSERT_ARG_WITH_RETVAL(obj
, NULL
);
275 return &obj
->cached
.oid
;
278 git_object_t
git_object_type(const git_object
*obj
)
280 GIT_ASSERT_ARG_WITH_RETVAL(obj
, GIT_OBJECT_INVALID
);
281 return obj
->cached
.type
;
284 git_repository
*git_object_owner(const git_object
*obj
)
286 GIT_ASSERT_ARG_WITH_RETVAL(obj
, NULL
);
290 const char *git_object_type2string(git_object_t type
)
292 if (type
< 0 || ((size_t) type
) >= ARRAY_SIZE(git_objects_table
))
295 return git_objects_table
[type
].str
;
298 git_object_t
git_object_string2type(const char *str
)
301 return GIT_OBJECT_INVALID
;
303 return git_object_stringn2type(str
, strlen(str
));
306 git_object_t
git_object_stringn2type(const char *str
, size_t len
)
310 if (!str
|| !len
|| !*str
)
311 return GIT_OBJECT_INVALID
;
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
;
318 return GIT_OBJECT_INVALID
;
321 int git_object_typeisloose(git_object_t type
)
323 if (type
< 0 || ((size_t) type
) >= ARRAY_SIZE(git_objects_table
))
326 return (git_objects_table
[type
].size
> 0) ? 1 : 0;
329 size_t git_object__size(git_object_t type
)
331 if (type
< 0 || ((size_t) type
) >= ARRAY_SIZE(git_objects_table
))
334 return git_objects_table
[type
].size
;
337 static int dereference_object(git_object
**dereferenced
, git_object
*obj
)
339 git_object_t type
= git_object_type(obj
);
342 case GIT_OBJECT_COMMIT
:
343 return git_commit_tree((git_tree
**)dereferenced
, (git_commit
*)obj
);
346 return git_tag_target(dereferenced
, (git_tag
*)obj
);
348 case GIT_OBJECT_BLOB
:
349 case GIT_OBJECT_TREE
:
353 return GIT_EINVALIDSPEC
;
357 static int peel_error(int error
, const git_oid
*oid
, git_object_t type
)
359 const char *type_name
;
360 char hex_oid
[GIT_OID_HEXSZ
+ 1];
362 type_name
= git_object_type2string(type
);
364 git_oid_fmt(hex_oid
, oid
);
365 hex_oid
[GIT_OID_HEXSZ
] = '\0';
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
);
373 static int check_type_combination(git_object_t type
, git_object_t target
)
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
;
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
;
390 /* a tag may point to anything, so we let anything through */
393 return GIT_EINVALIDSPEC
;
401 const git_object
*object
,
402 git_object_t target_type
)
404 git_object
*source
, *deref
= NULL
;
407 GIT_ASSERT_ARG(object
);
408 GIT_ASSERT_ARG(peeled
);
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
);
416 if ((error
= check_type_combination(git_object_type(object
), target_type
)) < 0)
417 return peel_error(error
, git_object_id(object
), target_type
);
419 if (git_object_type(object
) == target_type
)
420 return git_object_dup(peeled
, (git_object
*)object
);
422 source
= (git_object
*)object
;
424 while (!(error
= dereference_object(&deref
, source
))) {
426 if (source
!= object
)
427 git_object_free(source
);
429 if (git_object_type(deref
) == target_type
) {
434 if (target_type
== GIT_OBJECT_ANY
&&
435 git_object_type(deref
) != git_object_type(object
))
445 if (source
!= object
)
446 git_object_free(source
);
448 git_object_free(deref
);
451 error
= peel_error(error
, git_object_id(object
), target_type
);
456 int git_object_dup(git_object
**dest
, git_object
*source
)
458 git_cached_obj_incref(source
);
463 int git_object_lookup_bypath(
465 const git_object
*treeish
,
470 git_tree
*tree
= NULL
;
471 git_tree_entry
*entry
= NULL
;
474 GIT_ASSERT_ARG(treeish
);
475 GIT_ASSERT_ARG(path
);
477 if ((error
= git_object_peel((git_object
**)&tree
, treeish
, GIT_OBJECT_TREE
)) < 0 ||
478 (error
= git_tree_entry_bypath(&entry
, tree
, path
)) < 0)
483 if (type
!= GIT_OBJECT_ANY
&& git_tree_entry_type(entry
) != type
)
485 git_error_set(GIT_ERROR_OBJECT
,
486 "object at path '%s' is not of the asked-for type %d",
488 error
= GIT_EINVALIDSPEC
;
492 error
= git_tree_entry_to_object(out
, git_object_owner(treeish
), entry
);
495 git_tree_entry_free(entry
);
500 static int git_object__short_id(git_str
*out
, const git_object
*obj
)
502 git_repository
*repo
;
503 int len
= GIT_ABBREV_DEFAULT
, error
;
510 repo
= git_object_owner(obj
);
512 if ((error
= git_repository__configmap_lookup(&len
, repo
, GIT_CONFIGMAP_ABBREV
)) < 0)
515 if ((error
= git_repository_odb(&odb
, repo
)) < 0)
518 while (len
< GIT_OID_HEXSZ
) {
519 /* set up short oid */
520 memcpy(&id
.id
, &obj
->cached
.oid
.id
, (len
+ 1) / 2);
522 id
.id
[len
/ 2] &= 0xf0;
524 error
= git_odb_exists_prefix(NULL
, odb
, &id
, len
);
525 if (error
!= GIT_EAMBIGUOUS
)
532 if (!error
&& !(error
= git_str_grow(out
, len
+ 1))) {
533 git_oid_tostr(out
->ptr
, len
+ 1, &id
);
542 int git_object_short_id(git_buf
*out
, const git_object
*obj
)
544 GIT_BUF_WRAP_PRIVATE(out
, git_object__short_id
, obj
);
547 bool git_object__is_valid(
548 git_repository
*repo
, const git_oid
*id
, git_object_t expected_type
)
551 git_object_t actual_type
;
555 if (!git_object__strict_input_validation
)
558 if ((error
= git_repository_odb__weakptr(&odb
, repo
)) < 0 ||
559 (error
= git_odb_read_header(&len
, &actual_type
, odb
, id
)) < 0)
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");
571 int git_object_rawcontent_is_valid(
577 git_object
*obj
= NULL
;
580 GIT_ASSERT_ARG(valid
);
583 /* Blobs are always valid; don't bother parsing. */
584 if (type
== GIT_OBJECT_BLOB
) {
589 error
= git_object__from_raw(&obj
, buf
, len
, type
);
590 git_object_free(obj
);
595 } else if (error
== GIT_EINVALID
) {