]>
Commit | Line | Data |
---|---|---|
e52ed7a5 VM |
1 | /* |
2 | * This file is free software; you can redistribute it and/or modify | |
3 | * it under the terms of the GNU General Public License, version 2, | |
4 | * as published by the Free Software Foundation. | |
5 | * | |
6 | * In addition to the permissions in the GNU General Public License, | |
7 | * the authors give you unlimited permission to link the compiled | |
8 | * version of this file into combinations with other programs, | |
9 | * and to distribute those combinations without any restriction | |
10 | * coming from the use of this file. (The General Public License | |
11 | * restrictions do apply in other respects; for example, they cover | |
12 | * modification of the file, and distribution when not linked into | |
13 | * a combined executable.) | |
14 | * | |
15 | * This file is distributed in the hope that it will be useful, but | |
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; see the file COPYING. If not, write to | |
22 | * the Free Software Foundation, 51 Franklin Street, Fifth Floor, | |
23 | * Boston, MA 02110-1301, USA. | |
24 | */ | |
25 | #include <stdarg.h> | |
26 | ||
27 | #include "git2/object.h" | |
28 | ||
29 | #include "common.h" | |
30 | #include "repository.h" | |
31 | ||
32 | #include "commit.h" | |
33 | #include "tree.h" | |
34 | #include "blob.h" | |
35 | #include "tag.h" | |
36 | ||
37 | static const int OBJECT_BASE_SIZE = 4096; | |
38 | ||
39 | static struct { | |
40 | const char *str; /* type name string */ | |
41 | int loose; /* valid loose object type flag */ | |
42 | size_t size; /* size in bytes of the object structure */ | |
43 | } git_objects_table[] = { | |
44 | /* 0 = GIT_OBJ__EXT1 */ | |
45 | { "", 0, 0}, | |
46 | ||
47 | /* 1 = GIT_OBJ_COMMIT */ | |
48 | { "commit", 1, sizeof(struct git_commit)}, | |
49 | ||
50 | /* 2 = GIT_OBJ_TREE */ | |
51 | { "tree", 1, sizeof(struct git_tree) }, | |
52 | ||
53 | /* 3 = GIT_OBJ_BLOB */ | |
54 | { "blob", 1, sizeof(struct git_blob) }, | |
55 | ||
56 | /* 4 = GIT_OBJ_TAG */ | |
57 | { "tag", 1, sizeof(struct git_tag) }, | |
58 | ||
59 | /* 5 = GIT_OBJ__EXT2 */ | |
60 | { "", 0, 0 }, | |
61 | ||
62 | /* 6 = GIT_OBJ_OFS_DELTA */ | |
63 | { "OFS_DELTA", 0, 0 }, | |
64 | ||
65 | /* 7 = GIT_OBJ_REF_DELTA */ | |
66 | { "REF_DELTA", 0, 0 } | |
67 | }; | |
68 | ||
5de079b8 VM |
69 | static int create_object(git_object **object_out, git_otype type) |
70 | { | |
71 | git_object *object = NULL; | |
72 | ||
73 | assert(object_out); | |
74 | ||
75 | *object_out = NULL; | |
76 | ||
77 | switch (type) { | |
78 | case GIT_OBJ_COMMIT: | |
79 | case GIT_OBJ_TAG: | |
80 | case GIT_OBJ_BLOB: | |
72a3fe42 | 81 | case GIT_OBJ_TREE: |
5de079b8 VM |
82 | object = git__malloc(git_object__size(type)); |
83 | if (object == NULL) | |
84 | return GIT_ENOMEM; | |
85 | memset(object, 0x0, git_object__size(type)); | |
86 | break; | |
5de079b8 VM |
87 | |
88 | default: | |
6623f5c9 | 89 | return git__throw(GIT_EINVALIDTYPE, "The given type is invalid"); |
5de079b8 VM |
90 | } |
91 | ||
72a3fe42 | 92 | object->type = type; |
5de079b8 VM |
93 | |
94 | *object_out = object; | |
95 | return GIT_SUCCESS; | |
96 | } | |
97 | ||
dd453c4d | 98 | int git_object_lookup_short_oid(git_object **object_out, git_repository *repo, const git_oid *id, unsigned int len, git_otype type) |
5de079b8 VM |
99 | { |
100 | git_object *object = NULL; | |
72a3fe42 | 101 | git_odb_object *odb_obj; |
5de079b8 | 102 | int error = GIT_SUCCESS; |
dd453c4d | 103 | git_oid out_oid; |
5de079b8 VM |
104 | |
105 | assert(repo && object_out && id); | |
106 | ||
ac2b94ad MP |
107 | if (len < GIT_OID_MINPREFIXLEN) |
108 | return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to lookup object. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN); | |
dd453c4d MP |
109 | if (len > GIT_OID_HEXSZ) { |
110 | len = GIT_OID_HEXSZ; | |
111 | } | |
bd1aa741 | 112 | |
dd453c4d MP |
113 | if (len == GIT_OID_HEXSZ) { |
114 | /* We want to match the full id : we can first look up in the cache, | |
115 | * since there is no need to check for non ambiguousity | |
116 | */ | |
117 | object = git_cache_get(&repo->objects, id); | |
118 | if (object != NULL) { | |
119 | if (type != GIT_OBJ_ANY && type != object->type) | |
120 | return git__throw(GIT_EINVALIDTYPE, "Failed to lookup object. The given type does not match the type on the ODB"); | |
121 | ||
122 | *object_out = object; | |
123 | return GIT_SUCCESS; | |
124 | } | |
125 | ||
126 | /* Object was not found in the cache, let's explore the backends. | |
127 | * We could just use git_odb_read_unique_short_oid, | |
128 | * it is the same cost for packed and loose object backends, | |
129 | * but it may be much more costly for sqlite and hiredis. | |
130 | */ | |
131 | error = git_odb_read(&odb_obj, repo->db, id); | |
132 | git_oid_cpy(&out_oid, id); | |
133 | } else { | |
134 | git_oid short_oid; | |
135 | ||
136 | /* We copy the first len*4 bits from id and fill the remaining with 0s */ | |
137 | memcpy(short_oid.id, id->id, (len + 1) / 2); | |
138 | if (len % 2) | |
139 | short_oid.id[len / 2] &= 0xF0; | |
140 | memset(short_oid.id + (len + 1) / 2, 0, (GIT_OID_HEXSZ - len) / 2); | |
141 | ||
142 | /* If len < GIT_OID_HEXSZ (a strict short oid was given), we have | |
143 | * 2 options : | |
144 | * - We always search in the cache first. If we find that short oid is | |
145 | * ambiguous, we can stop. But in all the other cases, we must then | |
146 | * explore all the backends (to find an object if there was match, | |
147 | * or to check that oid is not ambiguous if we have found 1 match in | |
148 | * the cache) | |
149 | * - We never explore the cache, go right to exploring the backends | |
150 | * We chose the latter : we explore directly the backends. | |
151 | */ | |
152 | error = git_odb_read_unique_short_oid(&out_oid, &odb_obj, repo->db, &short_oid, len); | |
5de079b8 VM |
153 | } |
154 | ||
5de079b8 | 155 | if (error < GIT_SUCCESS) |
75eb97fe | 156 | return git__rethrow(error, "Failed to lookup object"); |
5de079b8 | 157 | |
72a3fe42 VM |
158 | if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) { |
159 | git_odb_object_close(odb_obj); | |
6623f5c9 | 160 | return git__throw(GIT_EINVALIDTYPE, "Failed to lookup object. The given type does not match the type on the ODB"); |
5de079b8 VM |
161 | } |
162 | ||
72a3fe42 | 163 | type = odb_obj->raw.type; |
5de079b8 VM |
164 | |
165 | if ((error = create_object(&object, type)) < GIT_SUCCESS) | |
75eb97fe | 166 | return git__rethrow(error, "Failed to lookup object"); |
5de079b8 VM |
167 | |
168 | /* Initialize parent object */ | |
dd453c4d | 169 | git_oid_cpy(&object->cached.oid, &out_oid); |
5de079b8 | 170 | object->repo = repo; |
5de079b8 VM |
171 | |
172 | switch (type) { | |
173 | case GIT_OBJ_COMMIT: | |
72a3fe42 | 174 | error = git_commit__parse((git_commit *)object, odb_obj); |
5de079b8 VM |
175 | break; |
176 | ||
177 | case GIT_OBJ_TREE: | |
72a3fe42 | 178 | error = git_tree__parse((git_tree *)object, odb_obj); |
5de079b8 VM |
179 | break; |
180 | ||
181 | case GIT_OBJ_TAG: | |
72a3fe42 | 182 | error = git_tag__parse((git_tag *)object, odb_obj); |
5de079b8 VM |
183 | break; |
184 | ||
185 | case GIT_OBJ_BLOB: | |
72a3fe42 | 186 | error = git_blob__parse((git_blob *)object, odb_obj); |
5de079b8 VM |
187 | break; |
188 | ||
189 | default: | |
190 | break; | |
191 | } | |
192 | ||
72a3fe42 VM |
193 | git_odb_object_close(odb_obj); |
194 | ||
5de079b8 | 195 | if (error < GIT_SUCCESS) { |
48c27f86 | 196 | git_object__free(object); |
75eb97fe | 197 | return git__rethrow(error, "Failed to lookup object"); |
5de079b8 VM |
198 | } |
199 | ||
72a3fe42 | 200 | *object_out = git_cache_try_store(&repo->objects, object); |
5de079b8 VM |
201 | return GIT_SUCCESS; |
202 | } | |
203 | ||
dd453c4d MP |
204 | int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type) { |
205 | return git_object_lookup_short_oid(object_out, repo, id, GIT_OID_HEXSZ, type); | |
206 | } | |
207 | ||
72a3fe42 | 208 | void git_object__free(void *_obj) |
e52ed7a5 | 209 | { |
72a3fe42 | 210 | git_object *object = (git_object *)_obj; |
e52ed7a5 VM |
211 | |
212 | assert(object); | |
213 | ||
72a3fe42 | 214 | switch (object->type) { |
e52ed7a5 VM |
215 | case GIT_OBJ_COMMIT: |
216 | git_commit__free((git_commit *)object); | |
217 | break; | |
218 | ||
219 | case GIT_OBJ_TREE: | |
220 | git_tree__free((git_tree *)object); | |
221 | break; | |
222 | ||
223 | case GIT_OBJ_TAG: | |
224 | git_tag__free((git_tag *)object); | |
225 | break; | |
226 | ||
227 | case GIT_OBJ_BLOB: | |
228 | git_blob__free((git_blob *)object); | |
229 | break; | |
230 | ||
231 | default: | |
232 | free(object); | |
233 | break; | |
234 | } | |
235 | } | |
236 | ||
48c27f86 VM |
237 | void git_object_close(git_object *object) |
238 | { | |
239 | if (object == NULL) | |
240 | return; | |
241 | ||
72a3fe42 | 242 | git_cached_obj_decref((git_cached_obj *)object, git_object__free); |
48c27f86 VM |
243 | } |
244 | ||
17cdf252 | 245 | const git_oid *git_object_id(const git_object *obj) |
e52ed7a5 VM |
246 | { |
247 | assert(obj); | |
72a3fe42 | 248 | return &obj->cached.oid; |
e52ed7a5 VM |
249 | } |
250 | ||
17cdf252 | 251 | git_otype git_object_type(const git_object *obj) |
e52ed7a5 VM |
252 | { |
253 | assert(obj); | |
72a3fe42 | 254 | return obj->type; |
e52ed7a5 VM |
255 | } |
256 | ||
17cdf252 | 257 | git_repository *git_object_owner(const git_object *obj) |
e52ed7a5 VM |
258 | { |
259 | assert(obj); | |
260 | return obj->repo; | |
261 | } | |
262 | ||
263 | const char *git_object_type2string(git_otype type) | |
264 | { | |
265 | if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table)) | |
266 | return ""; | |
267 | ||
268 | return git_objects_table[type].str; | |
269 | } | |
270 | ||
271 | git_otype git_object_string2type(const char *str) | |
272 | { | |
273 | size_t i; | |
274 | ||
275 | if (!str || !*str) | |
276 | return GIT_OBJ_BAD; | |
277 | ||
278 | for (i = 0; i < ARRAY_SIZE(git_objects_table); i++) | |
279 | if (!strcmp(str, git_objects_table[i].str)) | |
280 | return (git_otype)i; | |
281 | ||
282 | return GIT_OBJ_BAD; | |
283 | } | |
284 | ||
285 | int git_object_typeisloose(git_otype type) | |
286 | { | |
287 | if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table)) | |
288 | return 0; | |
289 | ||
290 | return git_objects_table[type].loose; | |
291 | } | |
292 | ||
293 | size_t git_object__size(git_otype type) | |
294 | { | |
295 | if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table)) | |
296 | return 0; | |
297 | ||
298 | return git_objects_table[type].size; | |
299 | } | |
300 |