source src/odb.c
Line | Flow | Count | Block(s) | Source |
---|---|---|---|---|
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 "odb.h" | ||
9 | - | |||
10 | - | #include <zlib.h> | ||
11 | - | #include "git2/object.h" | ||
12 | - | #include "git2/sys/odb_backend.h" | ||
13 | - | #include "futils.h" | ||
14 | - | #include "hash.h" | ||
15 | - | #include "delta.h" | ||
16 | - | #include "filter.h" | ||
17 | - | #include "repository.h" | ||
18 | - | #include "blob.h" | ||
19 | - | |||
20 | - | #include "git2/odb_backend.h" | ||
21 | - | #include "git2/oid.h" | ||
22 | - | #include "git2/oidarray.h" | ||
23 | - | |||
24 | - | #define GIT_ALTERNATES_FILE "info/alternates" | ||
25 | - | |||
26 | - | /* | ||
27 | - | * We work under the assumption that most objects for long-running | ||
28 | - | * operations will be packed | ||
29 | - | */ | ||
30 | - | #define GIT_LOOSE_PRIORITY 1 | ||
31 | - | #define GIT_PACKED_PRIORITY 2 | ||
32 | - | |||
33 | - | #define GIT_ALTERNATES_MAX_DEPTH 5 | ||
34 | - | |||
35 | - | bool git_odb__strict_hash_verification = true; | ||
36 | - | |||
37 | - | typedef struct | ||
38 | - | { | ||
39 | - | git_odb_backend *backend; | ||
40 | - | int priority; | ||
41 | - | bool is_alternate; | ||
42 | - | ino_t disk_inode; | ||
43 | - | } backend_internal; | ||
44 | - | |||
45 | 174793 | 2 | static git_cache *odb_cache(git_odb *odb) | |
46 | - | { | ||
47 | 174793 | 2 | if (odb->rc.owner != NULL) { | |
48 | 173764 | 3 | git_repository *owner = odb->rc.owner; | |
49 | 173764 | 3 | return &owner->objects; | |
50 | - | } | ||
51 | - | |||
52 | 1029 | 4 | return &odb->own_cache; | |
53 | - | } | ||
54 | - | |||
55 | - | static int odb_otype_fast(git_object_t *type_p, git_odb *db, const git_oid *id); | ||
56 | - | static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth); | ||
57 | - | static int error_null_oid(int error, const char *message); | ||
58 | - | |||
59 | 93435 | 2 | static git_object_t odb_hardcoded_type(const git_oid *id) | |
60 | - | { | ||
61 | - | static git_oid empty_tree = {{ 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, | ||
62 | - | 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04 }}; | ||
63 | - | |||
64 | 93435 | 2,3 | if (!git_oid_cmp(id, &empty_tree)) | |
65 | 20 | 4 | return GIT_OBJECT_TREE; | |
66 | - | |||
67 | 93355 | 5 | return GIT_OBJECT_INVALID; | |
68 | - | } | ||
69 | - | |||
70 | 80390 | 2 | static int odb_read_hardcoded(bool *found, git_rawobj *raw, const git_oid *id) | |
71 | - | { | ||
72 | - | git_object_t type; | ||
73 | - | |||
74 | 80390 | 2 | *found = false; | |
75 | - | |||
76 | 80390 | 2,3 | if ((type = odb_hardcoded_type(id)) == GIT_OBJECT_INVALID) | |
77 | 80350 | 4 | return 0; | |
78 | - | |||
79 | 11 | 5 | raw->type = type; | |
80 | 11 | 5 | raw->len = 0; | |
81 | 11 | 5 | raw->data = git__calloc(1, sizeof(uint8_t)); | |
82 | 11 | 6,7 | GIT_ERROR_CHECK_ALLOC(raw->data); | |
83 | - | |||
84 | 11 | 8 | *found = true; | |
85 | 11 | 8 | return 0; | |
86 | - | } | ||
87 | - | |||
88 | - | 2 | suppressed: function cannot be solved git_odb__format_object_header (automatic due to inconsistent arc counts in .gcda files)int git_odb__format_object_header( | |
89 | - | size_t *written, | ||
90 | - | char *hdr, | ||
91 | - | size_t hdr_size, | ||
92 | - | git_object_size_t obj_len, | ||
93 | - | git_object_t obj_type) | ||
94 | - | { | ||
95 | - | 2 | suppressed: function cannot be solved git_odb__format_object_header (automatic due to inconsistent arc counts in .gcda files) const char *type_str = git_object_type2string(obj_type); | |
96 | - | 3-5 | suppressed: function cannot be solved git_odb__format_object_header (automatic due to inconsistent arc counts in .gcda files) int hdr_max = (hdr_size > INT_MAX-2) ? (INT_MAX-2) : (int)hdr_size; | |
97 | - | int len; | ||
98 | - | |||
99 | - | 6 | suppressed: function cannot be solved git_odb__format_object_header (automatic due to inconsistent arc counts in .gcda files) len = p_snprintf(hdr, hdr_max, "%s %"PRId64, type_str, (int64_t)obj_len); | |
100 | - | |||
101 | - | 6,7 | suppressed: function cannot be solved git_odb__format_object_header (automatic due to inconsistent arc counts in .gcda files) if (len < 0 || len >= hdr_max) { | |
102 | - | 8 | suppressed: function cannot be solved git_odb__format_object_header (automatic due to inconsistent arc counts in .gcda files) git_error_set(GIT_ERROR_OS, "object header creation failed"); | |
103 | - | 9 | suppressed: function cannot be solved git_odb__format_object_header (automatic due to inconsistent arc counts in .gcda files) return -1; | |
104 | - | } | ||
105 | - | |||
106 | - | 10 | suppressed: function cannot be solved git_odb__format_object_header (automatic due to inconsistent arc counts in .gcda files) *written = (size_t)(len + 1); | |
107 | - | 10 | suppressed: function cannot be solved git_odb__format_object_header (automatic due to inconsistent arc counts in .gcda files) return 0; | |
108 | - | } | ||
109 | - | |||
110 | - | 2 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files)int git_odb__hashobj(git_oid *id, git_rawobj *obj) | |
111 | - | { | ||
112 | - | git_buf_vec vec[2]; | ||
113 | - | char header[64]; | ||
114 | - | size_t hdrlen; | ||
115 | - | int error; | ||
116 | - | |||
117 | - | 2-4 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) assert(id && obj); | |
118 | - | |||
119 | - | 5,6 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) if (!git_object_typeisloose(obj->type)) { | |
120 | - | 7 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) git_error_set(GIT_ERROR_INVALID, "invalid object type"); | |
121 | - | 8 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) return -1; | |
122 | - | } | ||
123 | - | |||
124 | - | 9,10 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) if (!obj->data && obj->len != 0) { | |
125 | - | 11 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) git_error_set(GIT_ERROR_INVALID, "invalid object"); | |
126 | - | 12 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) return -1; | |
127 | - | } | ||
128 | - | |||
129 | - | 13,14 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) if ((error = git_odb__format_object_header(&hdrlen, | |
130 | - | header, sizeof(header), obj->len, obj->type)) < 0) | ||
131 | - | 15 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) return error; | |
132 | - | |||
133 | - | 16 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) vec[0].data = header; | |
134 | - | 16 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) vec[0].len = hdrlen; | |
135 | - | 16 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) vec[1].data = obj->data; | |
136 | - | 16 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) vec[1].len = obj->len; | |
137 | - | |||
138 | - | 16 | suppressed: function cannot be solved git_odb__hashobj (automatic due to inconsistent arc counts in .gcda files) return git_hash_vec(id, vec, 2); | |
139 | - | } | ||
140 | - | |||
141 | - | |||
142 | 79396 | 2 | static git_odb_object *odb_object__alloc(const git_oid *oid, git_rawobj *source) | |
143 | - | { | ||
144 | 79396 | 2 | git_odb_object *object = git__calloc(1, sizeof(git_odb_object)); | |
145 | - | |||
146 | 80499 | 3 | if (object != NULL) { | |
147 | 80472 | 4 | git_oid_cpy(&object->cached.oid, oid); | |
148 | 80175 | 5 | object->cached.type = source->type; | |
149 | 80175 | 5 | object->cached.size = source->len; | |
150 | 80175 | 5 | object->buffer = source->data; | |
151 | - | } | ||
152 | - | |||
153 | 80202 | 6 | return object; | |
154 | - | } | ||
155 | - | |||
156 | - | 2 | suppressed: function cannot be solved git_odb_object__free (automatic due to inconsistent arc counts in .gcda files)void git_odb_object__free(void *object) | |
157 | - | { | ||
158 | - | 2 | suppressed: function cannot be solved git_odb_object__free (automatic due to inconsistent arc counts in .gcda files) if (object != NULL) { | |
159 | - | 3 | suppressed: function cannot be solved git_odb_object__free (automatic due to inconsistent arc counts in .gcda files) git__free(((git_odb_object *)object)->buffer); | |
160 | - | 4 | suppressed: function cannot be solved git_odb_object__free (automatic due to inconsistent arc counts in .gcda files) git__free(object); | |
161 | - | } | ||
162 | - | 5 | suppressed: function cannot be solved git_odb_object__free (automatic due to inconsistent arc counts in .gcda files)} | |
163 | - | |||
164 | 3 | 2 | const git_oid *git_odb_object_id(git_odb_object *object) | |
165 | - | { | ||
166 | 3 | 2 | return &object->cached.oid; | |
167 | - | } | ||
168 | - | |||
169 | 52251 | 2 | const void *git_odb_object_data(git_odb_object *object) | |
170 | - | { | ||
171 | 52251 | 2 | return object->buffer; | |
172 | - | } | ||
173 | - | |||
174 | 50639 | 2 | size_t git_odb_object_size(git_odb_object *object) | |
175 | - | { | ||
176 | 50639 | 2 | return object->cached.size; | |
177 | - | } | ||
178 | - | |||
179 | 17909 | 2 | git_object_t git_odb_object_type(git_odb_object *object) | |
180 | - | { | ||
181 | 17909 | 2 | return object->cached.type; | |
182 | - | } | ||
183 | - | |||
184 | 25672 | 2 | int git_odb_object_dup(git_odb_object **dest, git_odb_object *source) | |
185 | - | { | ||
186 | 25672 | 2 | git_cached_obj_incref(source); | |
187 | 25685 | 3 | *dest = source; | |
188 | 25685 | 3 | return 0; | |
189 | - | } | ||
190 | - | |||
191 | 131598 | 2 | void git_odb_object_free(git_odb_object *object) | |
192 | - | { | ||
193 | 131598 | 2 | if (object == NULL) | |
194 | 132163 | 3,5 | return; | |
195 | - | |||
196 | 131415 | 4 | git_cached_obj_decref(object); | |
197 | - | } | ||
198 | - | |||
199 | 4928 | 2 | int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_object_t type) | |
200 | - | { | ||
201 | - | size_t hdr_len; | ||
202 | - | char hdr[64], buffer[FILEIO_BUFSIZE]; | ||
203 | - | git_hash_ctx ctx; | ||
204 | 4928 | 2 | ssize_t read_len = 0; | |
205 | 4928 | 2 | int error = 0; | |
206 | - | |||
207 | 4928 | 2,3 | if (!git_object_typeisloose(type)) { | |
208 | 3 | 4 | git_error_set(GIT_ERROR_INVALID, "invalid object type for hash"); | |
209 | 3 | 5 | return -1; | |
210 | - | } | ||
211 | - | |||
212 | 4925 | 6,7 | if ((error = git_hash_ctx_init(&ctx)) < 0) | |
213 | ##### | 8 | return error; | |
214 | - | |||
215 | 4926 | 9,10 | if ((error = git_odb__format_object_header(&hdr_len, hdr, | |
216 | - | sizeof(hdr), size, type)) < 0) | ||
217 | ##### | 11 | goto done; | |
218 | - | |||
219 | 4926 | 12,13 | if ((error = git_hash_update(&ctx, hdr, hdr_len)) < 0) | |
220 | ##### | 14 | goto done; | |
221 | - | |||
222 | 9847 | 15,20-22 | while (size > 0 && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) { | |
223 | 4922 | 16,17 | if ((error = git_hash_update(&ctx, buffer, read_len)) < 0) | |
224 | ##### | 18 | goto done; | |
225 | - | |||
226 | 4921 | 19 | size -= read_len; | |
227 | - | } | ||
228 | - | |||
229 | - | /* If p_read returned an error code, the read obviously failed. | ||
230 | - | * If size is not zero, the file was truncated after we originally | ||
231 | - | * stat'd it, so we consider this a read failure too */ | ||
232 | 4925 | 23,24 | if (read_len < 0 || size > 0) { | |
233 | ##### | 25 | git_error_set(GIT_ERROR_OS, "error reading file for hashing"); | |
234 | ##### | 26 | error = -1; | |
235 | - | |||
236 | ##### | 26 | goto done; | |
237 | - | } | ||
238 | - | |||
239 | 4925 | 27 | error = git_hash_final(out, &ctx); | |
240 | - | |||
241 | - | done: | ||
242 | 4925 | 28 | git_hash_ctx_cleanup(&ctx); | |
243 | 4925 | 29 | return error; | |
244 | - | } | ||
245 | - | |||
246 | 5173 | 2 | int git_odb__hashfd_filtered( | |
247 | - | git_oid *out, git_file fd, size_t size, git_object_t type, git_filter_list *fl) | ||
248 | - | { | ||
249 | - | int error; | ||
250 | 5173 | 2 | git_buf raw = GIT_BUF_INIT; | |
251 | - | |||
252 | 5173 | 2 | if (!fl) | |
253 | 4911 | 3 | return git_odb__hashfd(out, fd, size, type); | |
254 | - | |||
255 | - | /* size of data is used in header, so we have to read the whole file | ||
256 | - | * into memory to apply filters before beginning to calculate the hash | ||
257 | - | */ | ||
258 | - | |||
259 | 262 | 4,5 | if (!(error = git_futils_readbuffer_fd(&raw, fd, size))) { | |
260 | 262 | 6 | git_buf post = GIT_BUF_INIT; | |
261 | - | |||
262 | 262 | 6 | error = git_filter_list_apply_to_data(&post, fl, &raw); | |
263 | - | |||
264 | 262 | 7 | git_buf_dispose(&raw); | |
265 | - | |||
266 | 262 | 8 | if (!error) | |
267 | 262 | 9 | error = git_odb_hash(out, post.ptr, post.size, type); | |
268 | - | |||
269 | 262 | 10,11 | git_buf_dispose(&post); | |
270 | - | } | ||
271 | - | |||
272 | 262 | 12 | return error; | |
273 | - | } | ||
274 | - | |||
275 | 14 | 2 | int git_odb__hashlink(git_oid *out, const char *path) | |
276 | - | { | ||
277 | - | struct stat st; | ||
278 | - | int size; | ||
279 | - | int result; | ||
280 | - | |||
281 | 14 | 2,3 | if (git_path_lstat(path, &st) < 0) | |
282 | ##### | 4 | return -1; | |
283 | - | |||
284 | 14 | 5-7 | if (!git__is_int(st.st_size) || (int)st.st_size < 0) { | |
285 | ##### | 8 | git_error_set(GIT_ERROR_FILESYSTEM, "file size overflow for 32-bit systems"); | |
286 | ##### | 9 | return -1; | |
287 | - | } | ||
288 | - | |||
289 | 14 | 10 | size = (int)st.st_size; | |
290 | - | |||
291 | 14 | 10 | if (S_ISLNK(st.st_mode)) { | |
292 | - | char *link_data; | ||
293 | - | int read_len; | ||
294 | - | size_t alloc_size; | ||
295 | - | |||
296 | 14 | 11-17,29 | GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, size, 1); | |
297 | 14 | 18 | link_data = git__malloc(alloc_size); | |
298 | 14 | 19,20 | GIT_ERROR_CHECK_ALLOC(link_data); | |
299 | - | |||
300 | 14 | 21 | read_len = p_readlink(path, link_data, size); | |
301 | 14 | 22 | link_data[size] = '\0'; | |
302 | 14 | 22 | if (read_len != size) { | |
303 | ##### | 23 | git_error_set(GIT_ERROR_OS, "failed to read symlink data for '%s'", path); | |
304 | ##### | 24 | git__free(link_data); | |
305 | ##### | 25 | return -1; | |
306 | - | } | ||
307 | - | |||
308 | 14 | 26 | result = git_odb_hash(out, link_data, size, GIT_OBJECT_BLOB); | |
309 | 14 | 27,28 | git__free(link_data); | |
310 | - | } else { | ||
311 | ##### | 30 | int fd = git_futils_open_ro(path); | |
312 | ##### | 31 | if (fd < 0) | |
313 | ##### | 32 | return -1; | |
314 | ##### | 33 | result = git_odb__hashfd(out, fd, size, GIT_OBJECT_BLOB); | |
315 | ##### | 34 | p_close(fd); | |
316 | - | } | ||
317 | - | |||
318 | 14 | 35 | return result; | |
319 | - | } | ||
320 | - | |||
321 | 16 | 2 | int git_odb_hashfile(git_oid *out, const char *path, git_object_t type) | |
322 | - | { | ||
323 | - | uint64_t size; | ||
324 | 16 | 2 | int fd, error = 0; | |
325 | - | |||
326 | 16 | 2,3 | if ((fd = git_futils_open_ro(path)) < 0) | |
327 | ##### | 4 | return fd; | |
328 | - | |||
329 | 16 | 5,6 | if ((error = git_futils_filesize(&size, fd)) < 0) | |
330 | ##### | 7 | goto done; | |
331 | - | |||
332 | 16 | 8,9 | if (!git__is_sizet(size)) { | |
333 | ##### | 10 | git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems"); | |
334 | ##### | 11 | error = -1; | |
335 | ##### | 11 | goto done; | |
336 | - | } | ||
337 | - | |||
338 | 16 | 12 | error = git_odb__hashfd(out, fd, (size_t)size, type); | |
339 | - | |||
340 | - | done: | ||
341 | 16 | 13 | p_close(fd); | |
342 | 16 | 14 | return error; | |
343 | - | } | ||
344 | - | |||
345 | 83100 | 2 | int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type) | |
346 | - | { | ||
347 | - | git_rawobj raw; | ||
348 | - | |||
349 | 83100 | 2,3 | assert(id); | |
350 | - | |||
351 | 83100 | 4 | raw.data = (void *)data; | |
352 | 83100 | 4 | raw.len = len; | |
353 | 83100 | 4 | raw.type = type; | |
354 | - | |||
355 | 83100 | 4 | return git_odb__hashobj(id, &raw); | |
356 | - | } | ||
357 | - | |||
358 | - | /** | ||
359 | - | * FAKE WSTREAM | ||
360 | - | */ | ||
361 | - | |||
362 | - | typedef struct { | ||
363 | - | git_odb_stream stream; | ||
364 | - | char *buffer; | ||
365 | - | size_t size, written; | ||
366 | - | git_object_t type; | ||
367 | - | } fake_wstream; | ||
368 | - | |||
369 | 1 | 2 | static int fake_wstream__fwrite(git_odb_stream *_stream, const git_oid *oid) | |
370 | - | { | ||
371 | 1 | 2 | fake_wstream *stream = (fake_wstream *)_stream; | |
372 | 1 | 2 | return _stream->backend->write(_stream->backend, oid, stream->buffer, stream->size, stream->type); | |
373 | - | } | ||
374 | - | |||
375 | 1 | 2 | static int fake_wstream__write(git_odb_stream *_stream, const char *data, size_t len) | |
376 | - | { | ||
377 | 1 | 2 | fake_wstream *stream = (fake_wstream *)_stream; | |
378 | - | |||
379 | 1 | 2,3 | assert(stream->written + len <= stream->size); | |
380 | - | |||
381 | 1 | 4 | memcpy(stream->buffer + stream->written, data, len); | |
382 | 1 | 4 | stream->written += len; | |
383 | 1 | 4 | return 0; | |
384 | - | } | ||
385 | - | |||
386 | 1 | 2 | static void fake_wstream__free(git_odb_stream *_stream) | |
387 | - | { | ||
388 | 1 | 2 | fake_wstream *stream = (fake_wstream *)_stream; | |
389 | - | |||
390 | 1 | 2 | git__free(stream->buffer); | |
391 | 1 | 3 | git__free(stream); | |
392 | 1 | 4 | } | |
393 | - | |||
394 | 1 | 2 | static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, git_object_size_t size, git_object_t type) | |
395 | - | { | ||
396 | - | fake_wstream *stream; | ||
397 | - | size_t blobsize; | ||
398 | - | |||
399 | 1 | 2-5 | GIT_ERROR_CHECK_BLOBSIZE(size); | |
400 | 1 | 6 | blobsize = (size_t)size; | |
401 | - | |||
402 | 1 | 6 | stream = git__calloc(1, sizeof(fake_wstream)); | |
403 | 1 | 7,8 | GIT_ERROR_CHECK_ALLOC(stream); | |
404 | - | |||
405 | 1 | 9 | stream->size = blobsize; | |
406 | 1 | 9 | stream->type = type; | |
407 | 1 | 9 | stream->buffer = git__malloc(blobsize); | |
408 | 1 | 10 | if (stream->buffer == NULL) { | |
409 | ##### | 11 | git__free(stream); | |
410 | ##### | 12 | return -1; | |
411 | - | } | ||
412 | - | |||
413 | 1 | 13 | stream->stream.backend = backend; | |
414 | 1 | 13 | stream->stream.read = NULL; /* read only */ | |
415 | 1 | 13 | stream->stream.write = &fake_wstream__write; | |
416 | 1 | 13 | stream->stream.finalize_write = &fake_wstream__fwrite; | |
417 | 1 | 13 | stream->stream.free = &fake_wstream__free; | |
418 | 1 | 13 | stream->stream.mode = GIT_STREAM_WRONLY; | |
419 | - | |||
420 | 1 | 13 | *stream_p = (git_odb_stream *)stream; | |
421 | 1 | 13 | return 0; | |
422 | - | } | ||
423 | - | |||
424 | - | /*********************************************************** | ||
425 | - | * | ||
426 | - | * OBJECT DATABASE PUBLIC API | ||
427 | - | * | ||
428 | - | * Public calls for the ODB functionality | ||
429 | - | * | ||
430 | - | ***********************************************************/ | ||
431 | - | |||
432 | 7882 | 2 | static int backend_sort_cmp(const void *a, const void *b) | |
433 | - | { | ||
434 | 7882 | 2 | const backend_internal *backend_a = (const backend_internal *)(a); | |
435 | 7882 | 2 | const backend_internal *backend_b = (const backend_internal *)(b); | |
436 | - | |||
437 | 7882 | 2 | if (backend_b->priority == backend_a->priority) { | |
438 | 135 | 3 | if (backend_a->is_alternate) | |
439 | 120 | 4 | return -1; | |
440 | 15 | 5 | if (backend_b->is_alternate) | |
441 | 15 | 6 | return 1; | |
442 | ##### | 7 | return 0; | |
443 | - | } | ||
444 | 7747 | 8 | return (backend_b->priority - backend_a->priority); | |
445 | - | } | ||
446 | - | |||
447 | 3790 | 2 | int git_odb_new(git_odb **out) | |
448 | - | { | ||
449 | 3790 | 2 | git_odb *db = git__calloc(1, sizeof(*db)); | |
450 | 3792 | 3,4 | GIT_ERROR_CHECK_ALLOC(db); | |
451 | - | |||
452 | 3792 | 5,6 | if (git_cache_init(&db->own_cache) < 0) { | |
453 | ##### | 7 | git__free(db); | |
454 | ##### | 8 | return -1; | |
455 | - | } | ||
456 | 3791 | 9,10 | if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) { | |
457 | ##### | 11 | git_cache_dispose(&db->own_cache); | |
458 | ##### | 12 | git__free(db); | |
459 | ##### | 13 | return -1; | |
460 | - | } | ||
461 | - | |||
462 | 3791 | 14 | *out = db; | |
463 | 3791 | 14 | GIT_REFCOUNT_INC(db); | |
464 | 3792 | 15 | return 0; | |
465 | - | } | ||
466 | - | |||
467 | - | 2 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files)static int add_backend_internal( | |
468 | - | git_odb *odb, git_odb_backend *backend, | ||
469 | - | int priority, bool is_alternate, ino_t disk_inode) | ||
470 | - | { | ||
471 | - | backend_internal *internal; | ||
472 | - | |||
473 | - | 2-4 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) assert(odb && backend); | |
474 | - | |||
475 | - | 5-7 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) GIT_ERROR_CHECK_VERSION(backend, GIT_ODB_BACKEND_VERSION, "git_odb_backend"); | |
476 | - | |||
477 | - | /* Check if the backend is already owned by another ODB */ | ||
478 | - | 8-10 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) assert(!backend->odb || backend->odb == odb); | |
479 | - | |||
480 | - | 11 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) internal = git__malloc(sizeof(backend_internal)); | |
481 | - | 12,13 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) GIT_ERROR_CHECK_ALLOC(internal); | |
482 | - | |||
483 | - | 14 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) internal->backend = backend; | |
484 | - | 14 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) internal->priority = priority; | |
485 | - | 14 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) internal->is_alternate = is_alternate; | |
486 | - | 14 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) internal->disk_inode = disk_inode; | |
487 | - | |||
488 | - | 14,15 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) if (git_vector_insert(&odb->backends, internal) < 0) { | |
489 | - | 16 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) git__free(internal); | |
490 | - | 17 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) return -1; | |
491 | - | } | ||
492 | - | |||
493 | - | 18 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) git_vector_sort(&odb->backends); | |
494 | - | 19 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) internal->backend->odb = odb; | |
495 | - | 19 | suppressed: function cannot be solved add_backend_internal (automatic due to inconsistent arc counts in .gcda files) return 0; | |
496 | - | } | ||
497 | - | |||
498 | 54 | 2 | int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority) | |
499 | - | { | ||
500 | 54 | 2 | return add_backend_internal(odb, backend, priority, false, 0); | |
501 | - | } | ||
502 | - | |||
503 | 4 | 2 | int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority) | |
504 | - | { | ||
505 | 4 | 2 | return add_backend_internal(odb, backend, priority, true, 0); | |
506 | - | } | ||
507 | - | |||
508 | 2 | 2 | size_t git_odb_num_backends(git_odb *odb) | |
509 | - | { | ||
510 | 2 | 2,3 | assert(odb); | |
511 | 2 | 4 | return odb->backends.length; | |
512 | - | } | ||
513 | - | |||
514 | 1 | 2 | static int git_odb__error_unsupported_in_backend(const char *action) | |
515 | - | { | ||
516 | 1 | 2 | git_error_set(GIT_ERROR_ODB, | |
517 | - | "cannot %s - unsupported in the loaded odb backends", action); | ||
518 | 1 | 3 | return -1; | |
519 | - | } | ||
520 | - | |||
521 | - | |||
522 | 12 | 2 | int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos) | |
523 | - | { | ||
524 | - | backend_internal *internal; | ||
525 | - | |||
526 | 12 | 2-4 | assert(out && odb); | |
527 | 12 | 5 | internal = git_vector_get(&odb->backends, pos); | |
528 | - | |||
529 | 12 | 6,7 | if (internal && internal->backend) { | |
530 | 12 | 8 | *out = internal->backend; | |
531 | 12 | 8 | return 0; | |
532 | - | } | ||
533 | - | |||
534 | ##### | 9 | git_error_set(GIT_ERROR_ODB, "no ODB backend loaded at index %" PRIuZ, pos); | |
535 | ##### | 10 | return GIT_ENOTFOUND; | |
536 | - | } | ||
537 | - | |||
538 | 3786 | 2 | int git_odb__add_default_backends( | |
539 | - | git_odb *db, const char *objects_dir, | ||
540 | - | bool as_alternates, int alternate_depth) | ||
541 | - | { | ||
542 | - | size_t i; | ||
543 | - | struct stat st; | ||
544 | - | ino_t inode; | ||
545 | - | git_odb_backend *loose, *packed; | ||
546 | - | |||
547 | - | /* TODO: inodes are not really relevant on Win32, so we need to find | ||
548 | - | * a cross-platform workaround for this */ | ||
549 | - | #ifdef GIT_WIN32 | ||
550 | - | GIT_UNUSED(i); | ||
551 | - | GIT_UNUSED(st); | ||
552 | - | |||
553 | - | inode = 0; | ||
554 | - | #else | ||
555 | 3786 | 2,3 | if (p_stat(objects_dir, &st) < 0) { | |
556 | ##### | 4 | if (as_alternates) | |
557 | - | /* this should warn */ | ||
558 | ##### | 5 | return 0; | |
559 | - | |||
560 | ##### | 6 | git_error_set(GIT_ERROR_ODB, "failed to load object database in '%s'", objects_dir); | |
561 | ##### | 7 | return -1; | |
562 | - | } | ||
563 | - | |||
564 | 3786 | 8 | inode = st.st_ino; | |
565 | - | |||
566 | 3850 | 8,12,13 | for (i = 0; i < db->backends.length; ++i) { | |
567 | 64 | 9 | backend_internal *backend = git_vector_get(&db->backends, i); | |
568 | 64 | 10 | if (backend->disk_inode == inode) | |
569 | ##### | 11 | return 0; | |
570 | - | } | ||
571 | - | #endif | ||
572 | - | |||
573 | - | /* add the loose object backend */ | ||
574 | 3788 | 14,15,17 | if (git_odb_backend_loose(&loose, objects_dir, -1, db->do_fsync, 0, 0) < 0 || | |
575 | 3787 | 16 | add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, inode) < 0) | |
576 | ##### | 18 | return -1; | |
577 | - | |||
578 | - | /* add the packed file backend */ | ||
579 | 3788 | 19,20,22 | if (git_odb_backend_pack(&packed, objects_dir) < 0 || | |
580 | 3767 | 21 | add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates, inode) < 0) | |
581 | ##### | 23 | return -1; | |
582 | - | |||
583 | 3776 | 24 | return load_alternates(db, objects_dir, alternate_depth); | |
584 | - | } | ||
585 | - | |||
586 | 3772 | 2 | static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth) | |
587 | - | { | ||
588 | 3772 | 2 | git_buf alternates_path = GIT_BUF_INIT; | |
589 | 3772 | 2 | git_buf alternates_buf = GIT_BUF_INIT; | |
590 | - | char *buffer; | ||
591 | - | const char *alternate; | ||
592 | 3772 | 2 | int result = 0; | |
593 | - | |||
594 | - | /* Git reports an error, we just ignore anything deeper */ | ||
595 | 3772 | 2 | if (alternate_depth > GIT_ALTERNATES_MAX_DEPTH) | |
596 | ##### | 3 | return 0; | |
597 | - | |||
598 | 3784 | 4,5 | if (git_buf_joinpath(&alternates_path, objects_dir, GIT_ALTERNATES_FILE) < 0) | |
599 | ##### | 6 | return -1; | |
600 | - | |||
601 | 3784 | 7,8 | if (git_path_exists(alternates_path.ptr) == false) { | |
602 | 3772 | 9 | git_buf_dispose(&alternates_path); | |
603 | 3767 | 10 | return 0; | |
604 | - | } | ||
605 | - | |||
606 | 8 | 11,12 | if (git_futils_readbuffer(&alternates_buf, alternates_path.ptr) < 0) { | |
607 | ##### | 13 | git_buf_dispose(&alternates_path); | |
608 | ##### | 14 | return -1; | |
609 | - | } | ||
610 | - | |||
611 | 8 | 15 | buffer = (char *)alternates_buf.ptr; | |
612 | - | |||
613 | - | /* add each alternate as a new backend; one alternate per line */ | ||
614 | 16 | 15,28,29 | while ((alternate = git__strtok(&buffer, "\r\n")) != NULL) { | |
615 | 8 | 16,17 | if (*alternate == '\0' || *alternate == '#') | |
616 | ##### | 18 | continue; | |
617 | - | |||
618 | - | /* | ||
619 | - | * Relative path: build based on the current `objects` | ||
620 | - | * folder. However, relative paths are only allowed in | ||
621 | - | * the current repository. | ||
622 | - | */ | ||
623 | 8 | 19,20 | if (*alternate == '.' && !alternate_depth) { | |
624 | ##### | 21,22 | if ((result = git_buf_joinpath(&alternates_path, objects_dir, alternate)) < 0) | |
625 | ##### | 23 | break; | |
626 | ##### | 24 | alternate = git_buf_cstr(&alternates_path); | |
627 | - | } | ||
628 | - | |||
629 | 8 | 25,26 | if ((result = git_odb__add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0) | |
630 | ##### | 27 | break; | |
631 | - | } | ||
632 | - | |||
633 | 8 | 30 | git_buf_dispose(&alternates_path); | |
634 | 8 | 31 | git_buf_dispose(&alternates_buf); | |
635 | - | |||
636 | 8 | 32 | return result; | |
637 | - | } | ||
638 | - | |||
639 | 6 | 2 | int git_odb_add_disk_alternate(git_odb *odb, const char *path) | |
640 | - | { | ||
641 | 6 | 2 | return git_odb__add_default_backends(odb, path, true, 0); | |
642 | - | } | ||
643 | - | |||
644 | 82 | 2 | int git_odb_open(git_odb **out, const char *objects_dir) | |
645 | - | { | ||
646 | - | git_odb *db; | ||
647 | - | |||
648 | 82 | 2-4 | assert(out && objects_dir); | |
649 | - | |||
650 | 82 | 5 | *out = NULL; | |
651 | - | |||
652 | 82 | 5,6 | if (git_odb_new(&db) < 0) | |
653 | ##### | 7 | return -1; | |
654 | - | |||
655 | 82 | 8,9 | if (git_odb__add_default_backends(db, objects_dir, 0, 0) < 0) { | |
656 | ##### | 10 | git_odb_free(db); | |
657 | ##### | 11 | return -1; | |
658 | - | } | ||
659 | - | |||
660 | 82 | 12 | *out = db; | |
661 | 82 | 12 | return 0; | |
662 | - | } | ||
663 | - | |||
664 | 3693 | 2 | int git_odb__set_caps(git_odb *odb, int caps) | |
665 | - | { | ||
666 | 3693 | 2 | if (caps == GIT_ODB_CAP_FROM_OWNER) { | |
667 | 3693 | 3 | git_repository *repo = odb->rc.owner; | |
668 | - | int val; | ||
669 | - | |||
670 | 3693 | 3 | if (!repo) { | |
671 | ##### | 4 | git_error_set(GIT_ERROR_ODB, "cannot access repository to set odb caps"); | |
672 | ##### | 5 | return -1; | |
673 | - | } | ||
674 | - | |||
675 | 3693 | 6,7 | if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_FSYNCOBJECTFILES)) | |
676 | 3691 | 8,9 | odb->do_fsync = !!val; | |
677 | - | } | ||
678 | - | |||
679 | 3691 | 10 | return 0; | |
680 | - | } | ||
681 | - | |||
682 | 3785 | 2 | static void odb_free(git_odb *db) | |
683 | - | { | ||
684 | - | size_t i; | ||
685 | - | |||
686 | 11418 | 2,6,7 | for (i = 0; i < db->backends.length; ++i) { | |
687 | 7626 | 3 | backend_internal *internal = git_vector_get(&db->backends, i); | |
688 | 7612 | 4 | git_odb_backend *backend = internal->backend; | |
689 | - | |||
690 | 7612 | 4 | backend->free(backend); | |
691 | - | |||
692 | 7633 | 5 | git__free(internal); | |
693 | - | } | ||
694 | - | |||
695 | 3792 | 8 | git_vector_free(&db->backends); | |
696 | 3791 | 9 | git_cache_dispose(&db->own_cache); | |
697 | - | |||
698 | 3790 | 10 | git__memzero(db, sizeof(*db)); | |
699 | 3791 | 11 | git__free(db); | |
700 | 3791 | 12 | } | |
701 | - | |||
702 | 12649 | 2 | void git_odb_free(git_odb *db) | |
703 | - | { | ||
704 | 12649 | 2 | if (db == NULL) | |
705 | 12661 | 3,8 | return; | |
706 | - | |||
707 | 12101 | 4-7 | GIT_REFCOUNT_DEC(db, odb_free); | |
708 | - | } | ||
709 | - | |||
710 | 2138 | 2 | static int odb_exists_1( | |
711 | - | git_odb *db, | ||
712 | - | const git_oid *id, | ||
713 | - | bool only_refreshed) | ||
714 | - | { | ||
715 | - | size_t i; | ||
716 | 2138 | 2 | bool found = false; | |
717 | - | |||
718 | 5835 | 2,10-12 | for (i = 0; i < db->backends.length && !found; ++i) { | |
719 | 3697 | 3 | backend_internal *internal = git_vector_get(&db->backends, i); | |
720 | 3697 | 4 | git_odb_backend *b = internal->backend; | |
721 | - | |||
722 | 3697 | 4,5 | if (only_refreshed && !b->refresh) | |
723 | 624 | 6 | continue; | |
724 | - | |||
725 | 3073 | 7 | if (b->exists != NULL) | |
726 | 3073 | 8,9 | found = (bool)b->exists(b, id); | |
727 | - | } | ||
728 | - | |||
729 | 2138 | 13 | return (int)found; | |
730 | - | } | ||
731 | - | |||
732 | 7273 | 2 | static int odb_freshen_1( | |
733 | - | git_odb *db, | ||
734 | - | const git_oid *id, | ||
735 | - | bool only_refreshed) | ||
736 | - | { | ||
737 | - | size_t i; | ||
738 | 7273 | 2 | bool found = false; | |
739 | - | |||
740 | 21743 | 2,13-15 | for (i = 0; i < db->backends.length && !found; ++i) { | |
741 | 14470 | 3 | backend_internal *internal = git_vector_get(&db->backends, i); | |
742 | 14470 | 4 | git_odb_backend *b = internal->backend; | |
743 | - | |||
744 | 14470 | 4,5 | if (only_refreshed && !b->refresh) | |
745 | 1647 | 6 | continue; | |
746 | - | |||
747 | 12823 | 7 | if (b->freshen != NULL) | |
748 | 12820 | 8,9 | found = !b->freshen(b, id); | |
749 | 3 | 10 | else if (b->exists != NULL) | |
750 | 3 | 11,12 | found = b->exists(b, id); | |
751 | - | } | ||
752 | - | |||
753 | 7273 | 16 | return (int)found; | |
754 | - | } | ||
755 | - | |||
756 | 5625 | 2 | int git_odb__freshen(git_odb *db, const git_oid *id) | |
757 | - | { | ||
758 | 5625 | 2-4 | assert(db && id); | |
759 | - | |||
760 | 5625 | 5,6 | if (odb_freshen_1(db, id, false)) | |
761 | 3977 | 7 | return 1; | |
762 | - | |||
763 | 1648 | 8,9 | if (!git_odb_refresh(db)) | |
764 | 1648 | 10 | return odb_freshen_1(db, id, true); | |
765 | - | |||
766 | - | /* Failed to refresh, hence not found */ | ||
767 | ##### | 11 | return 0; | |
768 | - | } | ||
769 | - | |||
770 | 1513 | 2 | int git_odb_exists(git_odb *db, const git_oid *id) | |
771 | - | { | ||
772 | - | git_odb_object *object; | ||
773 | - | |||
774 | 1513 | 2-4 | assert(db && id); | |
775 | - | |||
776 | 1513 | 5,6 | if (git_oid_is_zero(id)) | |
777 | 1 | 7 | return 0; | |
778 | - | |||
779 | 1512 | 8-10 | if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { | |
780 | ##### | 11 | git_odb_object_free(object); | |
781 | ##### | 12 | return 1; | |
782 | - | } | ||
783 | - | |||
784 | 1512 | 13,14 | if (odb_exists_1(db, id, false)) | |
785 | 886 | 15 | return 1; | |
786 | - | |||
787 | 626 | 16,17 | if (!git_odb_refresh(db)) | |
788 | 626 | 18 | return odb_exists_1(db, id, true); | |
789 | - | |||
790 | - | /* Failed to refresh, hence not found */ | ||
791 | ##### | 19 | return 0; | |
792 | - | } | ||
793 | - | |||
794 | 108 | 2 | static int odb_exists_prefix_1(git_oid *out, git_odb *db, | |
795 | - | const git_oid *key, size_t len, bool only_refreshed) | ||
796 | - | { | ||
797 | - | size_t i; | ||
798 | 108 | 2 | int error = GIT_ENOTFOUND, num_found = 0; | |
799 | 108 | 2 | git_oid last_found = {{0}}, found; | |
800 | - | |||
801 | 278 | 2,21,22 | for (i = 0; i < db->backends.length; ++i) { | |
802 | 199 | 3 | backend_internal *internal = git_vector_get(&db->backends, i); | |
803 | 199 | 4 | git_odb_backend *b = internal->backend; | |
804 | - | |||
805 | 199 | 4,5 | if (only_refreshed && !b->refresh) | |
806 | 1 | 6 | continue; | |
807 | - | |||
808 | 198 | 7 | if (!b->exists_prefix) | |
809 | ##### | 8 | continue; | |
810 | - | |||
811 | 198 | 9 | error = b->exists_prefix(&found, b, key, len); | |
812 | 198 | 10,11 | if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) | |
813 | 89 | 12 | continue; | |
814 | 109 | 13 | if (error) | |
815 | 18 | 14 | return error; | |
816 | - | |||
817 | - | /* make sure found item doesn't introduce ambiguity */ | ||
818 | 91 | 15 | if (num_found) { | |
819 | 18 | 16,17 | if (git_oid__cmp(&last_found, &found)) | |
820 | 11 | 18 | return git_odb__error_ambiguous("multiple matches for prefix"); | |
821 | - | } else { | ||
822 | 73 | 19 | git_oid_cpy(&last_found, &found); | |
823 | 73 | 20 | num_found++; | |
824 | - | } | ||
825 | - | } | ||
826 | - | |||
827 | 79 | 23 | if (!num_found) | |
828 | 17 | 24 | return GIT_ENOTFOUND; | |
829 | - | |||
830 | 62 | 25 | if (out) | |
831 | 57 | 26 | git_oid_cpy(out, &last_found); | |
832 | - | |||
833 | 62 | 27 | return 0; | |
834 | - | } | ||
835 | - | |||
836 | 44 | 2 | int git_odb_exists_prefix( | |
837 | - | git_oid *out, git_odb *db, const git_oid *short_id, size_t len) | ||
838 | - | { | ||
839 | - | int error; | ||
840 | 44 | 2 | git_oid key = {{0}}; | |
841 | - | |||
842 | 44 | 2-4 | assert(db && short_id); | |
843 | - | |||
844 | 44 | 5 | if (len < GIT_OID_MINPREFIXLEN) | |
845 | ##### | 6 | return git_odb__error_ambiguous("prefix length too short"); | |
846 | - | |||
847 | 44 | 7 | if (len >= GIT_OID_HEXSZ) { | |
848 | 2 | 8,9 | if (git_odb_exists(db, short_id)) { | |
849 | 2 | 10 | if (out) | |
850 | 1 | 11 | git_oid_cpy(out, short_id); | |
851 | 2 | 12 | return 0; | |
852 | - | } else { | ||
853 | ##### | 13 | return git_odb__error_notfound( | |
854 | - | "no match for id prefix", short_id, len); | ||
855 | - | } | ||
856 | - | } | ||
857 | - | |||
858 | 42 | 14 | git_oid__cpy_prefix(&key, short_id, len); | |
859 | - | |||
860 | 42 | 15 | error = odb_exists_prefix_1(out, db, &key, len, false); | |
861 | - | |||
862 | 42 | 16-18 | if (error == GIT_ENOTFOUND && !git_odb_refresh(db)) | |
863 | 1 | 19 | error = odb_exists_prefix_1(out, db, &key, len, true); | |
864 | - | |||
865 | 42 | 20 | if (error == GIT_ENOTFOUND) | |
866 | 1 | 21 | return git_odb__error_notfound("no match for id prefix", &key, len); | |
867 | - | |||
868 | 41 | 22 | return error; | |
869 | - | } | ||
870 | - | |||
871 | 5 | 2 | int git_odb_expand_ids( | |
872 | - | git_odb *db, | ||
873 | - | git_odb_expand_id *ids, | ||
874 | - | size_t count) | ||
875 | - | { | ||
876 | - | size_t i; | ||
877 | - | |||
878 | 5 | 2-4 | assert(db && ids); | |
879 | - | |||
880 | 95 | 5,27,28 | for (i = 0; i < count; i++) { | |
881 | 90 | 6 | git_odb_expand_id *query = &ids[i]; | |
882 | 90 | 6 | int error = GIT_EAMBIGUOUS; | |
883 | - | |||
884 | 90 | 6 | if (!query->type) | |
885 | 18 | 7 | query->type = GIT_OBJECT_ANY; | |
886 | - | |||
887 | - | /* if we have a short OID, expand it first */ | ||
888 | 90 | 8,9 | if (query->length >= GIT_OID_MINPREFIXLEN && query->length < GIT_OID_HEXSZ) { | |
889 | - | git_oid actual_id; | ||
890 | - | |||
891 | 65 | 10 | error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false); | |
892 | 65 | 11 | if (!error) { | |
893 | 30 | 12 | git_oid_cpy(&query->id, &actual_id); | |
894 | 65 | 13,14 | query->length = GIT_OID_HEXSZ; | |
895 | - | } | ||
896 | - | } | ||
897 | - | |||
898 | - | /* | ||
899 | - | * now we ought to have a 40-char OID, either because we've expanded it | ||
900 | - | * or because the user passed a full OID. Ensure its type is right. | ||
901 | - | */ | ||
902 | 90 | 15 | if (query->length >= GIT_OID_HEXSZ) { | |
903 | - | git_object_t actual_type; | ||
904 | - | |||
905 | 50 | 16 | error = odb_otype_fast(&actual_type, db, &query->id); | |
906 | 50 | 17 | if (!error) { | |
907 | 40 | 18,19 | if (query->type != GIT_OBJECT_ANY && query->type != actual_type) | |
908 | 8 | 20 | error = GIT_ENOTFOUND; | |
909 | - | else | ||
910 | 50 | 21,22 | query->type = actual_type; | |
911 | - | } | ||
912 | - | } | ||
913 | - | |||
914 | 90 | 23 | switch (error) { | |
915 | - | /* no errors, so we've successfully expanded the OID */ | ||
916 | - | case 0: | ||
917 | 32 | 24 | continue; | |
918 | - | |||
919 | - | /* the object is missing or ambiguous */ | ||
920 | - | case GIT_ENOTFOUND: | ||
921 | - | case GIT_EAMBIGUOUS: | ||
922 | 58 | 25 | memset(&query->id, 0, sizeof(git_oid)); | |
923 | 58 | 25 | query->length = 0; | |
924 | 58 | 25 | query->type = 0; | |
925 | 58 | 25 | break; | |
926 | - | |||
927 | - | /* something went very wrong with the ODB; bail hard */ | ||
928 | - | default: | ||
929 | ##### | 26 | return error; | |
930 | - | } | ||
931 | - | } | ||
932 | - | |||
933 | 5 | 29 | git_error_clear(); | |
934 | 5 | 30 | return 0; | |
935 | - | } | ||
936 | - | |||
937 | 11801 | 2 | int git_odb_read_header(size_t *len_p, git_object_t *type_p, git_odb *db, const git_oid *id) | |
938 | - | { | ||
939 | - | int error; | ||
940 | - | git_odb_object *object; | ||
941 | - | |||
942 | 11801 | 2 | error = git_odb__read_header_or_object(&object, len_p, type_p, db, id); | |
943 | - | |||
944 | 11801 | 3 | if (object) | |
945 | 376 | 4 | git_odb_object_free(object); | |
946 | - | |||
947 | 11801 | 5 | return error; | |
948 | - | } | ||
949 | - | |||
950 | 13121 | 2 | static int odb_read_header_1( | |
951 | - | size_t *len_p, git_object_t *type_p, git_odb *db, | ||
952 | - | const git_oid *id, bool only_refreshed) | ||
953 | - | { | ||
954 | - | size_t i; | ||
955 | - | git_object_t ht; | ||
956 | 13121 | 2 | bool passthrough = false; | |
957 | - | int error; | ||
958 | - | |||
959 | 13121 | 2-4 | if (!only_refreshed && (ht = odb_hardcoded_type(id)) != GIT_OBJECT_INVALID) { | |
960 | 9 | 5 | *type_p = ht; | |
961 | 9 | 5 | *len_p = 0; | |
962 | 9 | 5 | return 0; | |
963 | - | } | ||
964 | - | |||
965 | 23326 | 6,18,19 | for (i = 0; i < db->backends.length; ++i) { | |
966 | 23230 | 7 | backend_internal *internal = git_vector_get(&db->backends, i); | |
967 | 23230 | 8 | git_odb_backend *b = internal->backend; | |
968 | - | |||
969 | 23230 | 8,9 | if (only_refreshed && !b->refresh) | |
970 | 15 | 10 | continue; | |
971 | - | |||
972 | 23215 | 11 | if (!b->read_header) { | |
973 | ##### | 12 | passthrough = true; | |
974 | ##### | 12 | continue; | |
975 | - | } | ||
976 | - | |||
977 | 23215 | 13 | error = b->read_header(len_p, type_p, b, id); | |
978 | - | |||
979 | 23215 | 14 | switch (error) { | |
980 | - | case GIT_PASSTHROUGH: | ||
981 | ##### | 15 | passthrough = true; | |
982 | ##### | 15 | break; | |
983 | - | case GIT_ENOTFOUND: | ||
984 | 10199 | 16 | break; | |
985 | - | default: | ||
986 | 13016 | 17 | return error; | |
987 | - | } | ||
988 | - | } | ||
989 | - | |||
990 | 96 | 20 | return passthrough ? GIT_PASSTHROUGH : GIT_ENOTFOUND; | |
991 | - | } | ||
992 | - | |||
993 | 13377 | 2 | int git_odb__read_header_or_object( | |
994 | - | git_odb_object **out, size_t *len_p, git_object_t *type_p, | ||
995 | - | git_odb *db, const git_oid *id) | ||
996 | - | { | ||
997 | 13377 | 2 | int error = GIT_ENOTFOUND; | |
998 | - | git_odb_object *object; | ||
999 | - | |||
1000 | 13377 | 2-7 | assert(db && id && out && len_p && type_p); | |
1001 | - | |||
1002 | 13377 | 8 | *out = NULL; | |
1003 | - | |||
1004 | 13377 | 8,9 | if (git_oid_is_zero(id)) | |
1005 | ##### | 10 | return error_null_oid(GIT_ENOTFOUND, "cannot read object"); | |
1006 | - | |||
1007 | 13377 | 11-13 | if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { | |
1008 | 376 | 14 | *len_p = object->cached.size; | |
1009 | 376 | 14 | *type_p = object->cached.type; | |
1010 | 376 | 14 | *out = object; | |
1011 | 376 | 14 | return 0; | |
1012 | - | } | ||
1013 | - | |||
1014 | 13001 | 15 | error = odb_read_header_1(len_p, type_p, db, id, false); | |
1015 | - | |||
1016 | 13001 | 16-18 | if (error == GIT_ENOTFOUND && !git_odb_refresh(db)) | |
1017 | 77 | 19 | error = odb_read_header_1(len_p, type_p, db, id, true); | |
1018 | - | |||
1019 | 13001 | 20 | if (error == GIT_ENOTFOUND) | |
1020 | 14 | 21 | return git_odb__error_notfound("cannot read header for", id, GIT_OID_HEXSZ); | |
1021 | - | |||
1022 | - | /* we found the header; return early */ | ||
1023 | 12987 | 22 | if (!error) | |
1024 | 12987 | 23 | return 0; | |
1025 | - | |||
1026 | ##### | 24 | if (error == GIT_PASSTHROUGH) { | |
1027 | - | /* | ||
1028 | - | * no backend has header-reading functionality | ||
1029 | - | * so try using `git_odb_read` instead | ||
1030 | - | */ | ||
1031 | ##### | 25 | error = git_odb_read(&object, db, id); | |
1032 | ##### | 26 | if (!error) { | |
1033 | ##### | 27 | *len_p = object->cached.size; | |
1034 | ##### | 27 | *type_p = object->cached.type; | |
1035 | ##### | 27 | *out = object; | |
1036 | - | } | ||
1037 | - | } | ||
1038 | - | |||
1039 | ##### | 28 | return error; | |
1040 | - | } | ||
1041 | - | |||
1042 | - | 2 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files)static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id, | |
1043 | - | bool only_refreshed) | ||
1044 | - | { | ||
1045 | - | size_t i; | ||
1046 | - | git_rawobj raw; | ||
1047 | - | git_odb_object *object; | ||
1048 | - | git_oid hashed; | ||
1049 | - | 2 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) bool found = false; | |
1050 | - | 2 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) int error = 0; | |
1051 | - | |||
1052 | - | 2 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if (!only_refreshed) { | |
1053 | - | 3,4 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if ((error = odb_read_hardcoded(&found, &raw, id)) < 0) | |
1054 | - | 5 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) return error; | |
1055 | - | } | ||
1056 | - | |||
1057 | - | 6,19-21 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) for (i = 0; i < db->backends.length && !found; ++i) { | |
1058 | - | 7 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) backend_internal *internal = git_vector_get(&db->backends, i); | |
1059 | - | 8 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) git_odb_backend *b = internal->backend; | |
1060 | - | |||
1061 | - | 8,9 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if (only_refreshed && !b->refresh) | |
1062 | - | 10 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) continue; | |
1063 | - | |||
1064 | - | 11 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if (b->read != NULL) { | |
1065 | - | 12 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) error = b->read(&raw.data, &raw.len, &raw.type, b, id); | |
1066 | - | 13,14 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if (error == GIT_PASSTHROUGH || error == GIT_ENOTFOUND) | |
1067 | - | 15 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) continue; | |
1068 | - | |||
1069 | - | 16 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if (error < 0) | |
1070 | - | 17 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) return error; | |
1071 | - | |||
1072 | - | 18 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) found = true; | |
1073 | - | } | ||
1074 | - | } | ||
1075 | - | |||
1076 | - | 22 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if (!found) | |
1077 | - | 23 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) return GIT_ENOTFOUND; | |
1078 | - | |||
1079 | - | 24 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if (git_odb__strict_hash_verification) { | |
1080 | - | 25,26 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0) | |
1081 | - | 27 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) goto out; | |
1082 | - | |||
1083 | - | 28,29 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if (!git_oid_equal(id, &hashed)) { | |
1084 | - | 30 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) error = git_odb__error_mismatch(id, &hashed); | |
1085 | - | 31 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) goto out; | |
1086 | - | } | ||
1087 | - | } | ||
1088 | - | |||
1089 | - | 32 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) git_error_clear(); | |
1090 | - | 33,34 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if ((object = odb_object__alloc(id, &raw)) == NULL) { | |
1091 | - | 35 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) error = -1; | |
1092 | - | 35 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) goto out; | |
1093 | - | } | ||
1094 | - | |||
1095 | - | 36-38 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) *out = git_cache_store_raw(odb_cache(db), object); | |
1096 | - | |||
1097 | - | out: | ||
1098 | - | 39 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) if (error) | |
1099 | - | 40 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) git__free(raw.data); | |
1100 | - | 41 | suppressed: function cannot be solved odb_read_1 (automatic due to inconsistent arc counts in .gcda files) return error; | |
1101 | - | } | ||
1102 | - | |||
1103 | - | 2 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files)int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) | |
1104 | - | { | ||
1105 | - | int error; | ||
1106 | - | |||
1107 | - | 2-5 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) assert(out && db && id); | |
1108 | - | |||
1109 | - | 6,7 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) if (git_oid_is_zero(id)) | |
1110 | - | 8 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) return error_null_oid(GIT_ENOTFOUND, "cannot read object"); | |
1111 | - | |||
1112 | - | 9,10 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) *out = git_cache_get_raw(odb_cache(db), id); | |
1113 | - | 11 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) if (*out != NULL) | |
1114 | - | 12 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) return 0; | |
1115 | - | |||
1116 | - | 13 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) error = odb_read_1(out, db, id, false); | |
1117 | - | |||
1118 | - | 14-16 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) if (error == GIT_ENOTFOUND && !git_odb_refresh(db)) | |
1119 | - | 17 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) error = odb_read_1(out, db, id, true); | |
1120 | - | |||
1121 | - | 18 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) if (error == GIT_ENOTFOUND) | |
1122 | - | 19 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) return git_odb__error_notfound("no match for id", id, GIT_OID_HEXSZ); | |
1123 | - | |||
1124 | - | 20 | suppressed: function cannot be solved git_odb_read (automatic due to inconsistent arc counts in .gcda files) return error; | |
1125 | - | } | ||
1126 | - | |||
1127 | 50 | 2 | static int odb_otype_fast(git_object_t *type_p, git_odb *db, const git_oid *id) | |
1128 | - | { | ||
1129 | - | git_odb_object *object; | ||
1130 | - | size_t _unused; | ||
1131 | - | int error; | ||
1132 | - | |||
1133 | 50 | 2,3 | if (git_oid_is_zero(id)) | |
1134 | 5 | 4 | return error_null_oid(GIT_ENOTFOUND, "cannot get object type"); | |
1135 | - | |||
1136 | 45 | 5-7 | if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { | |
1137 | 2 | 8 | *type_p = object->cached.type; | |
1138 | 2 | 8 | git_odb_object_free(object); | |
1139 | 2 | 9 | return 0; | |
1140 | - | } | ||
1141 | - | |||
1142 | 43 | 10 | error = odb_read_header_1(&_unused, type_p, db, id, false); | |
1143 | - | |||
1144 | 43 | 11 | if (error == GIT_PASSTHROUGH) { | |
1145 | ##### | 12 | error = odb_read_1(&object, db, id, false); | |
1146 | ##### | 13 | if (!error) | |
1147 | ##### | 14 | *type_p = object->cached.type; | |
1148 | ##### | 15 | git_odb_object_free(object); | |
1149 | - | } | ||
1150 | - | |||
1151 | 43 | 16 | return error; | |
1152 | - | } | ||
1153 | - | |||
1154 | 476 | 2 | static int read_prefix_1(git_odb_object **out, git_odb *db, | |
1155 | - | const git_oid *key, size_t len, bool only_refreshed) | ||
1156 | - | { | ||
1157 | - | size_t i; | ||
1158 | 476 | 2 | int error = 0; | |
1159 | 476 | 2 | git_oid found_full_oid = {{0}}; | |
1160 | 476 | 2 | git_rawobj raw = {0}; | |
1161 | 476 | 2 | void *data = NULL; | |
1162 | 476 | 2 | bool found = false; | |
1163 | - | git_odb_object *object; | ||
1164 | - | |||
1165 | 1428 | 2,28,29 | for (i = 0; i < db->backends.length; ++i) { | |
1166 | 958 | 3 | backend_internal *internal = git_vector_get(&db->backends, i); | |
1167 | 958 | 4 | git_odb_backend *b = internal->backend; | |
1168 | - | |||
1169 | 958 | 4,5 | if (only_refreshed && !b->refresh) | |
1170 | 2 | 6 | continue; | |
1171 | - | |||
1172 | 956 | 7 | if (b->read_prefix != NULL) { | |
1173 | - | git_oid full_oid; | ||
1174 | 956 | 8 | error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, key, len); | |
1175 | - | |||
1176 | 956 | 9,10 | if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) { | |
1177 | 474 | 11 | error = 0; | |
1178 | 474 | 11 | continue; | |
1179 | - | } | ||
1180 | - | |||
1181 | 482 | 12 | if (error) | |
1182 | 6 | 13,27 | goto out; | |
1183 | - | |||
1184 | 477 | 14 | git__free(data); | |
1185 | 477 | 15 | data = raw.data; | |
1186 | - | |||
1187 | 477 | 15-17 | if (found && git_oid__cmp(&full_oid, &found_full_oid)) { | |
1188 | 1 | 18 | git_buf buf = GIT_BUF_INIT; | |
1189 | - | |||
1190 | 1 | 18,19 | git_buf_printf(&buf, "multiple matches for prefix: %s", | |
1191 | - | git_oid_tostr_s(&full_oid)); | ||
1192 | 1 | 20,21 | git_buf_printf(&buf, " %s", | |
1193 | - | git_oid_tostr_s(&found_full_oid)); | ||
1194 | - | |||
1195 | 1 | 22 | error = git_odb__error_ambiguous(buf.ptr); | |
1196 | 1 | 23 | git_buf_dispose(&buf); | |
1197 | 1 | 24,25 | goto out; | |
1198 | - | } | ||
1199 | - | |||
1200 | 476 | 26 | found_full_oid = full_oid; | |
1201 | 476 | 26 | found = true; | |
1202 | - | } | ||
1203 | - | } | ||
1204 | - | |||
1205 | 470 | 30 | if (!found) | |
1206 | 2 | 31 | return GIT_ENOTFOUND; | |
1207 | - | |||
1208 | 468 | 32 | if (git_odb__strict_hash_verification) { | |
1209 | - | git_oid hash; | ||
1210 | - | |||
1211 | 466 | 33,34 | if ((error = git_odb_hash(&hash, raw.data, raw.len, raw.type)) < 0) | |
1212 | ##### | 35,41 | goto out; | |
1213 | - | |||
1214 | 466 | 36,37 | if (!git_oid_equal(&found_full_oid, &hash)) { | |
1215 | 466 | 38,39 | error = git_odb__error_mismatch(&found_full_oid, &hash); | |
1216 | ##### | 40 | goto out; | |
1217 | - | } | ||
1218 | - | } | ||
1219 | - | |||
1220 | 468 | 42,43 | if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) { | |
1221 | ##### | 44 | error = -1; | |
1222 | ##### | 44 | goto out; | |
1223 | - | } | ||
1224 | - | |||
1225 | 468 | 45-47 | *out = git_cache_store_raw(odb_cache(db), object); | |
1226 | - | |||
1227 | - | out: | ||
1228 | 474 | 48 | if (error) | |
1229 | 6 | 49 | git__free(raw.data); | |
1230 | - | |||
1231 | 474 | 50 | return error; | |
1232 | - | } | ||
1233 | - | |||
1234 | 476 | 2 | int git_odb_read_prefix( | |
1235 | - | git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len) | ||
1236 | - | { | ||
1237 | 476 | 2 | git_oid key = {{0}}; | |
1238 | - | int error; | ||
1239 | - | |||
1240 | 476 | 2-4 | assert(out && db); | |
1241 | - | |||
1242 | 476 | 5 | if (len < GIT_OID_MINPREFIXLEN) | |
1243 | ##### | 6 | return git_odb__error_ambiguous("prefix length too short"); | |
1244 | - | |||
1245 | 476 | 7 | if (len > GIT_OID_HEXSZ) | |
1246 | ##### | 8 | len = GIT_OID_HEXSZ; | |
1247 | - | |||
1248 | 476 | 9 | if (len == GIT_OID_HEXSZ) { | |
1249 | 4 | 10,11 | *out = git_cache_get_raw(odb_cache(db), short_id); | |
1250 | 4 | 12 | if (*out != NULL) | |
1251 | 1 | 13 | return 0; | |
1252 | - | } | ||
1253 | - | |||
1254 | 475 | 14 | git_oid__cpy_prefix(&key, short_id, len); | |
1255 | - | |||
1256 | 475 | 15 | error = read_prefix_1(out, db, &key, len, false); | |
1257 | - | |||
1258 | 475 | 16-18 | if (error == GIT_ENOTFOUND && !git_odb_refresh(db)) | |
1259 | 1 | 19 | error = read_prefix_1(out, db, &key, len, true); | |
1260 | - | |||
1261 | 475 | 20 | if (error == GIT_ENOTFOUND) | |
1262 | 1 | 21 | return git_odb__error_notfound("no match for prefix", &key, len); | |
1263 | - | |||
1264 | 474 | 22 | return error; | |
1265 | - | } | ||
1266 | - | |||
1267 | 6 | 2 | int git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload) | |
1268 | - | { | ||
1269 | - | unsigned int i; | ||
1270 | - | backend_internal *internal; | ||
1271 | - | |||
1272 | 12 | 2,6-8 | git_vector_foreach(&db->backends, i, internal) { | |
1273 | 9 | 3 | git_odb_backend *b = internal->backend; | |
1274 | 9 | 3 | int error = b->foreach(b, cb, payload); | |
1275 | 9 | 4 | if (error != 0) | |
1276 | 3 | 5 | return error; | |
1277 | - | } | ||
1278 | - | |||
1279 | 3 | 9 | return 0; | |
1280 | - | } | ||
1281 | - | |||
1282 | 2407 | 2 | int git_odb_write( | |
1283 | - | git_oid *oid, git_odb *db, const void *data, size_t len, git_object_t type) | ||
1284 | - | { | ||
1285 | - | size_t i; | ||
1286 | 2407 | 2 | int error = GIT_ERROR; | |
1287 | - | git_odb_stream *stream; | ||
1288 | - | |||
1289 | 2407 | 2-4 | assert(oid && db); | |
1290 | - | |||
1291 | 2407 | 5 | git_odb_hash(oid, data, len, type); | |
1292 | - | |||
1293 | 2407 | 6,7 | if (git_oid_is_zero(oid)) | |
1294 | ##### | 8 | return error_null_oid(GIT_EINVALID, "cannot write object"); | |
1295 | - | |||
1296 | 2407 | 9,10 | if (git_odb__freshen(db, oid)) | |
1297 | 1514 | 11 | return 0; | |
1298 | - | |||
1299 | 2670 | 12,18-20 | for (i = 0; i < db->backends.length && error < 0; ++i) { | |
1300 | 1777 | 13 | backend_internal *internal = git_vector_get(&db->backends, i); | |
1301 | 1777 | 14 | git_odb_backend *b = internal->backend; | |
1302 | - | |||
1303 | - | /* we don't write in alternates! */ | ||
1304 | 1777 | 14 | if (internal->is_alternate) | |
1305 | ##### | 15 | continue; | |
1306 | - | |||
1307 | 1777 | 16 | if (b->write != NULL) | |
1308 | 892 | 17 | error = b->write(b, oid, data, len, type); | |
1309 | - | } | ||
1310 | - | |||
1311 | 893 | 21,22 | if (!error || error == GIT_PASSTHROUGH) | |
1312 | 892 | 23 | return 0; | |
1313 | - | |||
1314 | - | /* if no backends were able to write the object directly, we try a | ||
1315 | - | * streaming write to the backends; just write the whole object into the | ||
1316 | - | * stream in one push | ||
1317 | - | */ | ||
1318 | 1 | 24,25 | if ((error = git_odb_open_wstream(&stream, db, len, type)) != 0) | |
1319 | 1 | 26 | return error; | |
1320 | - | |||
1321 | ##### | 27 | stream->write(stream, data, len); | |
1322 | ##### | 28 | error = stream->finalize_write(stream, oid); | |
1323 | ##### | 29 | git_odb_stream_free(stream); | |
1324 | - | |||
1325 | ##### | 30 | return error; | |
1326 | - | } | ||
1327 | - | |||
1328 | 2890 | 2 | static int hash_header(git_hash_ctx *ctx, git_object_size_t size, git_object_t type) | |
1329 | - | { | ||
1330 | - | char header[64]; | ||
1331 | - | size_t hdrlen; | ||
1332 | - | int error; | ||
1333 | - | |||
1334 | 2890 | 2,3 | if ((error = git_odb__format_object_header(&hdrlen, | |
1335 | - | header, sizeof(header), size, type)) < 0) | ||
1336 | ##### | 4 | return error; | |
1337 | - | |||
1338 | 2890 | 5 | return git_hash_update(ctx, header, hdrlen); | |
1339 | - | } | ||
1340 | - | |||
1341 | 2891 | 2 | int git_odb_open_wstream( | |
1342 | - | git_odb_stream **stream, git_odb *db, git_object_size_t size, git_object_t type) | ||
1343 | - | { | ||
1344 | 2891 | 2 | size_t i, writes = 0; | |
1345 | 2891 | 2 | int error = GIT_ERROR; | |
1346 | 2891 | 2 | git_hash_ctx *ctx = NULL; | |
1347 | - | |||
1348 | 2891 | 2-4 | assert(stream && db); | |
1349 | - | |||
1350 | 8670 | 5,13-15 | for (i = 0; i < db->backends.length && error < 0; ++i) { | |
1351 | 5779 | 6 | backend_internal *internal = git_vector_get(&db->backends, i); | |
1352 | 5779 | 7 | git_odb_backend *b = internal->backend; | |
1353 | - | |||
1354 | - | /* we don't write in alternates! */ | ||
1355 | 5779 | 7 | if (internal->is_alternate) | |
1356 | ##### | 8 | continue; | |
1357 | - | |||
1358 | 5779 | 9 | if (b->writestream != NULL) { | |
1359 | 2889 | 10 | ++writes; | |
1360 | 2889 | 10 | error = b->writestream(stream, b, size, type); | |
1361 | 2890 | 11 | } else if (b->write != NULL) { | |
1362 | 1 | 12 | ++writes; | |
1363 | 1 | 12 | error = init_fake_wstream(stream, b, size, type); | |
1364 | - | } | ||
1365 | - | } | ||
1366 | - | |||
1367 | 2891 | 16 | if (error < 0) { | |
1368 | 1 | 17 | if (error == GIT_PASSTHROUGH) | |
1369 | ##### | 18 | error = 0; | |
1370 | 1 | 19 | else if (!writes) | |
1371 | 1 | 20 | error = git_odb__error_unsupported_in_backend("write object"); | |
1372 | - | |||
1373 | 1 | 21 | goto done; | |
1374 | - | } | ||
1375 | - | |||
1376 | 2890 | 22 | ctx = git__malloc(sizeof(git_hash_ctx)); | |
1377 | 2890 | 23,24 | GIT_ERROR_CHECK_ALLOC(ctx); | |
1378 | - | |||
1379 | 2890 | 25-28 | if ((error = git_hash_ctx_init(ctx)) < 0 || | |
1380 | - | (error = hash_header(ctx, size, type)) < 0) | ||
1381 | - | goto done; | ||
1382 | - | |||
1383 | 2890 | 29 | (*stream)->hash_ctx = ctx; | |
1384 | 2890 | 29 | (*stream)->declared_size = size; | |
1385 | 2890 | 29 | (*stream)->received_bytes = 0; | |
1386 | - | |||
1387 | - | done: | ||
1388 | 2891 | 30 | if (error) | |
1389 | 1 | 31 | git__free(ctx); | |
1390 | 2891 | 32 | return error; | |
1391 | - | } | ||
1392 | - | |||
1393 | 2 | 2 | static int git_odb_stream__invalid_length( | |
1394 | - | const git_odb_stream *stream, | ||
1395 | - | const char *action) | ||
1396 | - | { | ||
1397 | 2 | 2 | git_error_set(GIT_ERROR_ODB, | |
1398 | - | "cannot %s - " | ||
1399 | - | "Invalid length. %"PRId64" was expected. The " | ||
1400 | - | "total size of the received chunks amounts to %"PRId64".", | ||
1401 | - | action, stream->declared_size, stream->received_bytes); | ||
1402 | - | |||
1403 | 2 | 3 | return -1; | |
1404 | - | } | ||
1405 | - | |||
1406 | 2861 | 2 | int git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len) | |
1407 | - | { | ||
1408 | 2861 | 2 | git_hash_update(stream->hash_ctx, buffer, len); | |
1409 | - | |||
1410 | 2861 | 3 | stream->received_bytes += len; | |
1411 | - | |||
1412 | 2861 | 3 | if (stream->received_bytes > stream->declared_size) | |
1413 | 1 | 4 | return git_odb_stream__invalid_length(stream, | |
1414 | - | "stream_write()"); | ||
1415 | - | |||
1416 | 2860 | 5 | return stream->write(stream, buffer, len); | |
1417 | - | } | ||
1418 | - | |||
1419 | 2889 | 2 | int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream) | |
1420 | - | { | ||
1421 | 2889 | 2 | if (stream->received_bytes != stream->declared_size) | |
1422 | 1 | 3 | return git_odb_stream__invalid_length(stream, | |
1423 | - | "stream_finalize_write()"); | ||
1424 | - | |||
1425 | 2888 | 4 | git_hash_final(out, stream->hash_ctx); | |
1426 | - | |||
1427 | 2888 | 5,6 | if (git_odb__freshen(stream->backend->odb, out)) | |
1428 | 2134 | 7 | return 0; | |
1429 | - | |||
1430 | 754 | 8 | return stream->finalize_write(stream, out); | |
1431 | - | } | ||
1432 | - | |||
1433 | 3352 | 2 | int git_odb_stream_read(git_odb_stream *stream, char *buffer, size_t len) | |
1434 | - | { | ||
1435 | 3352 | 2 | return stream->read(stream, buffer, len); | |
1436 | - | } | ||
1437 | - | |||
1438 | 2939 | 2 | void git_odb_stream_free(git_odb_stream *stream) | |
1439 | - | { | ||
1440 | 2939 | 2 | if (stream == NULL) | |
1441 | 2939 | 3,7 | return; | |
1442 | - | |||
1443 | 2939 | 4 | git_hash_ctx_cleanup(stream->hash_ctx); | |
1444 | 2939 | 5 | git__free(stream->hash_ctx); | |
1445 | 2939 | 6 | stream->free(stream); | |
1446 | - | } | ||
1447 | - | |||
1448 | 49 | 2 | int git_odb_open_rstream( | |
1449 | - | git_odb_stream **stream, | ||
1450 | - | size_t *len, | ||
1451 | - | git_object_t *type, | ||
1452 | - | git_odb *db, | ||
1453 | - | const git_oid *oid) | ||
1454 | - | { | ||
1455 | 49 | 2 | size_t i, reads = 0; | |
1456 | 49 | 2 | int error = GIT_ERROR; | |
1457 | - | |||
1458 | 49 | 2-4 | assert(stream && db); | |
1459 | - | |||
1460 | 147 | 5,9-11 | for (i = 0; i < db->backends.length && error < 0; ++i) { | |
1461 | 98 | 6 | backend_internal *internal = git_vector_get(&db->backends, i); | |
1462 | 98 | 7 | git_odb_backend *b = internal->backend; | |
1463 | - | |||
1464 | 98 | 7 | if (b->readstream != NULL) { | |
1465 | 49 | 8 | ++reads; | |
1466 | 49 | 8 | error = b->readstream(stream, len, type, b, oid); | |
1467 | - | } | ||
1468 | - | } | ||
1469 | - | |||
1470 | 49 | 12 | if (error == GIT_PASSTHROUGH) | |
1471 | ##### | 13 | error = 0; | |
1472 | 49 | 14,15 | if (error < 0 && !reads) | |
1473 | ##### | 16 | error = git_odb__error_unsupported_in_backend("read object streamed"); | |
1474 | - | |||
1475 | 49 | 17 | return error; | |
1476 | - | } | ||
1477 | - | |||
1478 | 72 | 2 | int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_indexer_progress_cb progress_cb, void *progress_payload) | |
1479 | - | { | ||
1480 | 72 | 2 | size_t i, writes = 0; | |
1481 | 72 | 2 | int error = GIT_ERROR; | |
1482 | - | |||
1483 | 72 | 2-4 | assert(out && db); | |
1484 | - | |||
1485 | 144 | 5,11-13 | for (i = 0; i < db->backends.length && error < 0; ++i) { | |
1486 | 72 | 6 | backend_internal *internal = git_vector_get(&db->backends, i); | |
1487 | 72 | 7 | git_odb_backend *b = internal->backend; | |
1488 | - | |||
1489 | - | /* we don't write in alternates! */ | ||
1490 | 72 | 7 | if (internal->is_alternate) | |
1491 | ##### | 8 | continue; | |
1492 | - | |||
1493 | 72 | 9 | if (b->writepack != NULL) { | |
1494 | 72 | 10 | ++writes; | |
1495 | 72 | 10 | error = b->writepack(out, b, db, progress_cb, progress_payload); | |
1496 | - | } | ||
1497 | - | } | ||
1498 | - | |||
1499 | 72 | 14 | if (error == GIT_PASSTHROUGH) | |
1500 | ##### | 15 | error = 0; | |
1501 | 72 | 16,17 | if (error < 0 && !writes) | |
1502 | ##### | 18 | error = git_odb__error_unsupported_in_backend("write pack"); | |
1503 | - | |||
1504 | 72 | 19 | return error; | |
1505 | - | } | ||
1506 | - | |||
1507 | ##### | 2 | void *git_odb_backend_data_alloc(git_odb_backend *backend, size_t len) | |
1508 | - | { | ||
1509 | - | GIT_UNUSED(backend); | ||
1510 | ##### | 2 | return git__malloc(len); | |
1511 | - | } | ||
1512 | - | |||
1513 | - | #ifndef GIT_DEPRECATE_HARD | ||
1514 | ##### | 2 | void *git_odb_backend_malloc(git_odb_backend *backend, size_t len) | |
1515 | - | { | ||
1516 | ##### | 2 | return git_odb_backend_data_alloc(backend, len); | |
1517 | - | } | ||
1518 | - | #endif | ||
1519 | - | |||
1520 | ##### | 2 | void git_odb_backend_data_free(git_odb_backend *backend, void *data) | |
1521 | - | { | ||
1522 | - | GIT_UNUSED(backend); | ||
1523 | ##### | 2 | git__free(data); | |
1524 | ##### | 3 | } | |
1525 | - | |||
1526 | 2416 | 2 | int git_odb_refresh(struct git_odb *db) | |
1527 | - | { | ||
1528 | - | size_t i; | ||
1529 | 2416 | 2,3 | assert(db); | |
1530 | - | |||
1531 | 7260 | 4,10,11 | for (i = 0; i < db->backends.length; ++i) { | |
1532 | 4844 | 5 | backend_internal *internal = git_vector_get(&db->backends, i); | |
1533 | 4844 | 6 | git_odb_backend *b = internal->backend; | |
1534 | - | |||
1535 | 4844 | 6 | if (b->refresh != NULL) { | |
1536 | 2413 | 7 | int error = b->refresh(b); | |
1537 | 2413 | 8 | if (error < 0) | |
1538 | ##### | 9 | return error; | |
1539 | - | } | ||
1540 | - | } | ||
1541 | - | |||
1542 | 2416 | 12 | return 0; | |
1543 | - | } | ||
1544 | - | |||
1545 | 2 | 2 | int git_odb__error_mismatch(const git_oid *expected, const git_oid *actual) | |
1546 | - | { | ||
1547 | - | char expected_oid[GIT_OID_HEXSZ + 1], actual_oid[GIT_OID_HEXSZ + 1]; | ||
1548 | - | |||
1549 | 2 | 2 | git_oid_tostr(expected_oid, sizeof(expected_oid), expected); | |
1550 | 2 | 3 | git_oid_tostr(actual_oid, sizeof(actual_oid), actual); | |
1551 | - | |||
1552 | 2 | 4 | git_error_set(GIT_ERROR_ODB, "object hash mismatch - expected %s but got %s", | |
1553 | - | expected_oid, actual_oid); | ||
1554 | - | |||
1555 | 2 | 5 | return GIT_EMISMATCH; | |
1556 | - | } | ||
1557 | - | |||
1558 | 201703 | 2 | int git_odb__error_notfound( | |
1559 | - | const char *message, const git_oid *oid, size_t oid_len) | ||
1560 | - | { | ||
1561 | 201703 | 2 | if (oid != NULL) { | |
1562 | - | char oid_str[GIT_OID_HEXSZ + 1]; | ||
1563 | 201703 | 3 | git_oid_tostr(oid_str, oid_len+1, oid); | |
1564 | 205876 | 4,5 | git_error_set(GIT_ERROR_ODB, "object not found - %s (%.*s)", | |
1565 | - | message, (int) oid_len, oid_str); | ||
1566 | - | } else | ||
1567 | ##### | 6 | git_error_set(GIT_ERROR_ODB, "object not found - %s", message); | |
1568 | - | |||
1569 | 195546 | 7 | return GIT_ENOTFOUND; | |
1570 | - | } | ||
1571 | - | |||
1572 | 9 | 2 | static int error_null_oid(int error, const char *message) | |
1573 | - | { | ||
1574 | 9 | 2 | git_error_set(GIT_ERROR_ODB, "odb: %s: null OID cannot exist", message); | |
1575 | 9 | 3 | return error; | |
1576 | - | } | ||
1577 | - | |||
1578 | 31 | 2 | int git_odb__error_ambiguous(const char *message) | |
1579 | - | { | ||
1580 | 31 | 2 | git_error_set(GIT_ERROR_ODB, "ambiguous SHA1 prefix - %s", message); | |
1581 | 31 | 3 | return GIT_EAMBIGUOUS; | |
1582 | - | } | ||
1583 | - | |||
1584 | 1 | 2 | int git_odb_init_backend(git_odb_backend *backend, unsigned int version) | |
1585 | - | { | ||
1586 | 1 | 2-4 | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | |
1587 | - | backend, version, git_odb_backend, GIT_ODB_BACKEND_INIT); | ||
1588 | 1 | 5 | return 0; | |
1589 | - | } |