File Coverage

deps/libgit2/src/odb.c
Criterion Covered Total %
statement 408 765 53.3
branch 217 538 40.3
condition n/a
subroutine n/a
pod n/a
total 625 1303 47.9


line stmt bran cond sub pod time code
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
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 1925           static git_cache *odb_cache(git_odb *odb)
46             {
47 1925 50         if (odb->rc.owner != NULL) {
48 1925           git_repository *owner = odb->rc.owner;
49 1925           return &owner->objects;
50             }
51              
52 0           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 1032           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 1032 100         if (!git_oid_cmp(id, &empty_tree))
65 1           return GIT_OBJECT_TREE;
66              
67 1031           return GIT_OBJECT_INVALID;
68             }
69              
70 636           static int odb_read_hardcoded(bool *found, git_rawobj *raw, const git_oid *id)
71             {
72             git_object_t type;
73              
74 636           *found = false;
75              
76 636 100         if ((type = odb_hardcoded_type(id)) == GIT_OBJECT_INVALID)
77 635           return 0;
78              
79 1           raw->type = type;
80 1           raw->len = 0;
81 1           raw->data = git__calloc(1, sizeof(uint8_t));
82 1 50         GIT_ERROR_CHECK_ALLOC(raw->data);
83              
84 1           *found = true;
85 1           return 0;
86             }
87              
88 1350           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 1350           const char *type_str = git_object_type2string(obj_type);
96 1350 50         int hdr_max = (hdr_size > INT_MAX-2) ? (INT_MAX-2) : (int)hdr_size;
97             int len;
98              
99 1350           len = p_snprintf(hdr, hdr_max, "%s %"PRId64, type_str, (int64_t)obj_len);
100              
101 1350 50         if (len < 0 || len >= hdr_max) {
    50          
102 0           git_error_set(GIT_ERROR_OS, "object header creation failed");
103 0           return -1;
104             }
105              
106 1350           *written = (size_t)(len + 1);
107 1350           return 0;
108             }
109              
110 970           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 970 50         assert(id && obj);
    50          
118              
119 970 50         if (!git_object_typeisloose(obj->type)) {
120 0           git_error_set(GIT_ERROR_INVALID, "invalid object type");
121 0           return -1;
122             }
123              
124 970 50         if (!obj->data && obj->len != 0) {
    0          
125 0           git_error_set(GIT_ERROR_INVALID, "invalid object");
126 0           return -1;
127             }
128              
129 970 50         if ((error = git_odb__format_object_header(&hdrlen,
130             header, sizeof(header), obj->len, obj->type)) < 0)
131 0           return error;
132              
133 970           vec[0].data = header;
134 970           vec[0].len = hdrlen;
135 970           vec[1].data = obj->data;
136 970           vec[1].len = obj->len;
137              
138 970           return git_hash_vec(id, vec, 2);
139             }
140              
141              
142 764           static git_odb_object *odb_object__alloc(const git_oid *oid, git_rawobj *source)
143             {
144 764           git_odb_object *object = git__calloc(1, sizeof(git_odb_object));
145              
146 764 50         if (object != NULL) {
147 764           git_oid_cpy(&object->cached.oid, oid);
148 764           object->cached.type = source->type;
149 764           object->cached.size = source->len;
150 764           object->buffer = source->data;
151             }
152              
153 764           return object;
154             }
155              
156 762           void git_odb_object__free(void *object)
157             {
158 762 50         if (object != NULL) {
159 762           git__free(((git_odb_object *)object)->buffer);
160 762           git__free(object);
161             }
162 762           }
163              
164 1           const git_oid *git_odb_object_id(git_odb_object *object)
165             {
166 1           return &object->cached.oid;
167             }
168              
169 626           const void *git_odb_object_data(git_odb_object *object)
170             {
171 626           return object->buffer;
172             }
173              
174 634           size_t git_odb_object_size(git_odb_object *object)
175             {
176 634           return object->cached.size;
177             }
178              
179 51           git_object_t git_odb_object_type(git_odb_object *object)
180             {
181 51           return object->cached.type;
182             }
183              
184 101           int git_odb_object_dup(git_odb_object **dest, git_odb_object *source)
185             {
186 101           git_cached_obj_incref(source);
187 101           *dest = source;
188 101           return 0;
189             }
190              
191 1052           void git_odb_object_free(git_odb_object *object)
192             {
193 1052 100         if (object == NULL)
194 3           return;
195              
196 1049           git_cached_obj_decref(object);
197             }
198              
199 97           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 97           ssize_t read_len = 0;
205 97           int error = 0;
206              
207 97 50         if (!git_object_typeisloose(type)) {
208 0           git_error_set(GIT_ERROR_INVALID, "invalid object type for hash");
209 0           return -1;
210             }
211              
212 97 50         if ((error = git_hash_ctx_init(&ctx)) < 0)
213 0           return error;
214              
215 97 50         if ((error = git_odb__format_object_header(&hdr_len, hdr,
216             sizeof(hdr), size, type)) < 0)
217 0           goto done;
218              
219 97 50         if ((error = git_hash_update(&ctx, hdr, hdr_len)) < 0)
220 0           goto done;
221              
222 183 100         while (size > 0 && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) {
    50          
223 86 50         if ((error = git_hash_update(&ctx, buffer, read_len)) < 0)
224 0           goto done;
225              
226 86           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 97 50         if (read_len < 0 || size > 0) {
    50          
233 0           git_error_set(GIT_ERROR_OS, "error reading file for hashing");
234 0           error = -1;
235              
236 0           goto done;
237             }
238              
239 97           error = git_hash_final(out, &ctx);
240              
241             done:
242 97           git_hash_ctx_cleanup(&ctx);
243 97           return error;
244             }
245              
246 124           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 124           git_buf raw = GIT_BUF_INIT;
251              
252 124 100         if (!fl)
253 97           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 27 50         if (!(error = git_futils_readbuffer_fd(&raw, fd, size))) {
260 27           git_buf post = GIT_BUF_INIT;
261              
262 27           error = git_filter_list_apply_to_data(&post, fl, &raw);
263              
264 27           git_buf_dispose(&raw);
265              
266 27 50         if (!error)
267 27           error = git_odb_hash(out, post.ptr, post.size, type);
268              
269 27           git_buf_dispose(&post);
270             }
271              
272 124           return error;
273             }
274              
275 0           int git_odb__hashlink(git_oid *out, const char *path)
276             {
277             struct stat st;
278             int size;
279             int result;
280              
281 0 0         if (git_path_lstat(path, &st) < 0)
282 0           return -1;
283              
284 0 0         if (!git__is_int(st.st_size) || (int)st.st_size < 0) {
    0          
285 0           git_error_set(GIT_ERROR_FILESYSTEM, "file size overflow for 32-bit systems");
286 0           return -1;
287             }
288              
289 0           size = (int)st.st_size;
290              
291 0 0         if (S_ISLNK(st.st_mode)) {
292             char *link_data;
293             int read_len;
294             size_t alloc_size;
295              
296 0 0         GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, size, 1);
    0          
297 0           link_data = git__malloc(alloc_size);
298 0 0         GIT_ERROR_CHECK_ALLOC(link_data);
299              
300 0           read_len = p_readlink(path, link_data, size);
301 0           link_data[size] = '\0';
302 0 0         if (read_len != size) {
303 0           git_error_set(GIT_ERROR_OS, "failed to read symlink data for '%s'", path);
304 0           git__free(link_data);
305 0           return -1;
306             }
307              
308 0           result = git_odb_hash(out, link_data, size, GIT_OBJECT_BLOB);
309 0           git__free(link_data);
310             } else {
311 0           int fd = git_futils_open_ro(path);
312 0 0         if (fd < 0)
313 0           return -1;
314 0           result = git_odb__hashfd(out, fd, size, GIT_OBJECT_BLOB);
315 0           p_close(fd);
316             }
317              
318 0           return result;
319             }
320              
321 0           int git_odb_hashfile(git_oid *out, const char *path, git_object_t type)
322             {
323             uint64_t size;
324 0           int fd, error = 0;
325              
326 0 0         if ((fd = git_futils_open_ro(path)) < 0)
327 0           return fd;
328              
329 0 0         if ((error = git_futils_filesize(&size, fd)) < 0)
330 0           goto done;
331              
332 0 0         if (!git__is_sizet(size)) {
333 0           git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems");
334 0           error = -1;
335 0           goto done;
336             }
337              
338 0           error = git_odb__hashfd(out, fd, (size_t)size, type);
339              
340             done:
341 0           p_close(fd);
342 0           return error;
343             }
344              
345 968           int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type)
346             {
347             git_rawobj raw;
348              
349 968 50         assert(id);
350              
351 968           raw.data = (void *)data;
352 968           raw.len = len;
353 968           raw.type = type;
354              
355 968           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 0           static int fake_wstream__fwrite(git_odb_stream *_stream, const git_oid *oid)
370             {
371 0           fake_wstream *stream = (fake_wstream *)_stream;
372 0           return _stream->backend->write(_stream->backend, oid, stream->buffer, stream->size, stream->type);
373             }
374              
375 0           static int fake_wstream__write(git_odb_stream *_stream, const char *data, size_t len)
376             {
377 0           fake_wstream *stream = (fake_wstream *)_stream;
378              
379 0 0         assert(stream->written + len <= stream->size);
380              
381 0           memcpy(stream->buffer + stream->written, data, len);
382 0           stream->written += len;
383 0           return 0;
384             }
385              
386 0           static void fake_wstream__free(git_odb_stream *_stream)
387             {
388 0           fake_wstream *stream = (fake_wstream *)_stream;
389              
390 0           git__free(stream->buffer);
391 0           git__free(stream);
392 0           }
393              
394 0           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 0 0         GIT_ERROR_CHECK_BLOBSIZE(size);
400 0           blobsize = (size_t)size;
401              
402 0           stream = git__calloc(1, sizeof(fake_wstream));
403 0 0         GIT_ERROR_CHECK_ALLOC(stream);
404              
405 0           stream->size = blobsize;
406 0           stream->type = type;
407 0           stream->buffer = git__malloc(blobsize);
408 0 0         if (stream->buffer == NULL) {
409 0           git__free(stream);
410 0           return -1;
411             }
412              
413 0           stream->stream.backend = backend;
414 0           stream->stream.read = NULL; /* read only */
415 0           stream->stream.write = &fake_wstream__write;
416 0           stream->stream.finalize_write = &fake_wstream__fwrite;
417 0           stream->stream.free = &fake_wstream__free;
418 0           stream->stream.mode = GIT_STREAM_WRONLY;
419              
420 0           *stream_p = (git_odb_stream *)stream;
421 0           return 0;
422             }
423              
424             /***********************************************************
425             *
426             * OBJECT DATABASE PUBLIC API
427             *
428             * Public calls for the ODB functionality
429             *
430             ***********************************************************/
431              
432 79           static int backend_sort_cmp(const void *a, const void *b)
433             {
434 79           const backend_internal *backend_a = (const backend_internal *)(a);
435 79           const backend_internal *backend_b = (const backend_internal *)(b);
436              
437 79 100         if (backend_b->priority == backend_a->priority) {
438 1 50         if (backend_a->is_alternate)
439 0           return -1;
440 1 50         if (backend_b->is_alternate)
441 1           return 1;
442 0           return 0;
443             }
444 78           return (backend_b->priority - backend_a->priority);
445             }
446              
447 36           int git_odb_new(git_odb **out)
448             {
449 36           git_odb *db = git__calloc(1, sizeof(*db));
450 36 50         GIT_ERROR_CHECK_ALLOC(db);
451              
452 36 50         if (git_cache_init(&db->own_cache) < 0) {
453 0           git__free(db);
454 0           return -1;
455             }
456 36 50         if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
457 0           git_cache_dispose(&db->own_cache);
458 0           git__free(db);
459 0           return -1;
460             }
461              
462 36           *out = db;
463 36           GIT_REFCOUNT_INC(db);
464 36           return 0;
465             }
466              
467 74           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 74 50         assert(odb && backend);
    50          
474              
475 74 50         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 74 50         assert(!backend->odb || backend->odb == odb);
    0          
479              
480 74           internal = git__malloc(sizeof(backend_internal));
481 74 50         GIT_ERROR_CHECK_ALLOC(internal);
482              
483 74           internal->backend = backend;
484 74           internal->priority = priority;
485 74           internal->is_alternate = is_alternate;
486 74           internal->disk_inode = disk_inode;
487              
488 74 50         if (git_vector_insert(&odb->backends, internal) < 0) {
489 0           git__free(internal);
490 0           return -1;
491             }
492              
493 74           git_vector_sort(&odb->backends);
494 74           internal->backend->odb = odb;
495 74           return 0;
496             }
497              
498 3           int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority)
499             {
500 3           return add_backend_internal(odb, backend, priority, false, 0);
501             }
502              
503 1           int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority)
504             {
505 1           return add_backend_internal(odb, backend, priority, true, 0);
506             }
507              
508 7           size_t git_odb_num_backends(git_odb *odb)
509             {
510 7 50         assert(odb);
511 7           return odb->backends.length;
512             }
513              
514 0           static int git_odb__error_unsupported_in_backend(const char *action)
515             {
516 0           git_error_set(GIT_ERROR_ODB,
517             "cannot %s - unsupported in the loaded odb backends", action);
518 0           return -1;
519             }
520              
521              
522 0           int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos)
523             {
524             backend_internal *internal;
525              
526 0 0         assert(out && odb);
    0          
527 0           internal = git_vector_get(&odb->backends, pos);
528              
529 0 0         if (internal && internal->backend) {
    0          
530 0           *out = internal->backend;
531 0           return 0;
532             }
533              
534 0           git_error_set(GIT_ERROR_ODB, "no ODB backend loaded at index %" PRIuZ, pos);
535 0           return GIT_ENOTFOUND;
536             }
537              
538 35           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 35 50         if (p_stat(objects_dir, &st) < 0) {
556 0 0         if (as_alternates)
557             /* this should warn */
558 0           return 0;
559              
560 0           git_error_set(GIT_ERROR_ODB, "failed to load object database in '%s'", objects_dir);
561 0           return -1;
562             }
563              
564 35           inode = st.st_ino;
565              
566 35 50         for (i = 0; i < db->backends.length; ++i) {
567 0           backend_internal *backend = git_vector_get(&db->backends, i);
568 0 0         if (backend->disk_inode == inode)
569 0           return 0;
570             }
571             #endif
572              
573             /* add the loose object backend */
574 70           if (git_odb_backend_loose(&loose, objects_dir, -1, db->do_fsync, 0, 0) < 0 ||
575 35           add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, inode) < 0)
576 0           return -1;
577              
578             /* add the packed file backend */
579 70           if (git_odb_backend_pack(&packed, objects_dir) < 0 ||
580 35           add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates, inode) < 0)
581 0           return -1;
582              
583 35           return load_alternates(db, objects_dir, alternate_depth);
584             }
585              
586 35           static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth)
587             {
588 35           git_buf alternates_path = GIT_BUF_INIT;
589 35           git_buf alternates_buf = GIT_BUF_INIT;
590             char *buffer;
591             const char *alternate;
592 35           int result = 0;
593              
594             /* Git reports an error, we just ignore anything deeper */
595 35 50         if (alternate_depth > GIT_ALTERNATES_MAX_DEPTH)
596 0           return 0;
597              
598 35 50         if (git_buf_joinpath(&alternates_path, objects_dir, GIT_ALTERNATES_FILE) < 0)
599 0           return -1;
600              
601 35 50         if (git_path_exists(alternates_path.ptr) == false) {
602 35           git_buf_dispose(&alternates_path);
603 35           return 0;
604             }
605              
606 0 0         if (git_futils_readbuffer(&alternates_buf, alternates_path.ptr) < 0) {
607 0           git_buf_dispose(&alternates_path);
608 0           return -1;
609             }
610              
611 0           buffer = (char *)alternates_buf.ptr;
612              
613             /* add each alternate as a new backend; one alternate per line */
614 0 0         while ((alternate = git__strtok(&buffer, "\r\n")) != NULL) {
615 0 0         if (*alternate == '\0' || *alternate == '#')
    0          
616 0           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 0 0         if (*alternate == '.' && !alternate_depth) {
    0          
624 0 0         if ((result = git_buf_joinpath(&alternates_path, objects_dir, alternate)) < 0)
625 0           break;
626 0           alternate = git_buf_cstr(&alternates_path);
627             }
628              
629 0 0         if ((result = git_odb__add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0)
630 0           break;
631             }
632              
633 0           git_buf_dispose(&alternates_path);
634 0           git_buf_dispose(&alternates_buf);
635              
636 35           return result;
637             }
638              
639 0           int git_odb_add_disk_alternate(git_odb *odb, const char *path)
640             {
641 0           return git_odb__add_default_backends(odb, path, true, 0);
642             }
643              
644 2           int git_odb_open(git_odb **out, const char *objects_dir)
645             {
646             git_odb *db;
647              
648 2 50         assert(out && objects_dir);
    50          
649              
650 2           *out = NULL;
651              
652 2 50         if (git_odb_new(&db) < 0)
653 0           return -1;
654              
655 2 50         if (git_odb__add_default_backends(db, objects_dir, 0, 0) < 0) {
656 0           git_odb_free(db);
657 0           return -1;
658             }
659              
660 2           *out = db;
661 2           return 0;
662             }
663              
664 33           int git_odb__set_caps(git_odb *odb, int caps)
665             {
666 33 50         if (caps == GIT_ODB_CAP_FROM_OWNER) {
667 33           git_repository *repo = odb->rc.owner;
668             int val;
669              
670 33 50         if (!repo) {
671 0           git_error_set(GIT_ERROR_ODB, "cannot access repository to set odb caps");
672 0           return -1;
673             }
674              
675 33 50         if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_FSYNCOBJECTFILES))
676 33           odb->do_fsync = !!val;
677             }
678              
679 33           return 0;
680             }
681              
682 36           static void odb_free(git_odb *db)
683             {
684             size_t i;
685              
686 110 100         for (i = 0; i < db->backends.length; ++i) {
687 74           backend_internal *internal = git_vector_get(&db->backends, i);
688 74           git_odb_backend *backend = internal->backend;
689              
690 74           backend->free(backend);
691              
692 74           git__free(internal);
693             }
694              
695 36           git_vector_free(&db->backends);
696 36           git_cache_dispose(&db->own_cache);
697              
698 36           git__memzero(db, sizeof(*db));
699 36           git__free(db);
700 36           }
701              
702 211           void git_odb_free(git_odb *db)
703             {
704 211 100         if (db == NULL)
705 10           return;
706              
707 201 100         GIT_REFCOUNT_DEC(db, odb_free);
    50          
708             }
709              
710 4           static int odb_exists_1(
711             git_odb *db,
712             const git_oid *id,
713             bool only_refreshed)
714             {
715             size_t i;
716 4           bool found = false;
717              
718 12 100         for (i = 0; i < db->backends.length && !found; ++i) {
    50          
719 8           backend_internal *internal = git_vector_get(&db->backends, i);
720 8           git_odb_backend *b = internal->backend;
721              
722 8 50         if (only_refreshed && !b->refresh)
    0          
723 0           continue;
724              
725 8 50         if (b->exists != NULL)
726 8           found = (bool)b->exists(b, id);
727             }
728              
729 4           return (int)found;
730             }
731              
732 451           static int odb_freshen_1(
733             git_odb *db,
734             const git_oid *id,
735             bool only_refreshed)
736             {
737             size_t i;
738 451           bool found = false;
739              
740 1363 100         for (i = 0; i < db->backends.length && !found; ++i) {
    100          
741 912           backend_internal *internal = git_vector_get(&db->backends, i);
742 912           git_odb_backend *b = internal->backend;
743              
744 912 100         if (only_refreshed && !b->refresh)
    100          
745 169           continue;
746              
747 743 100         if (b->freshen != NULL)
748 735           found = !b->freshen(b, id);
749 8 50         else if (b->exists != NULL)
750 8           found = b->exists(b, id);
751             }
752              
753 451           return (int)found;
754             }
755              
756 288           int git_odb__freshen(git_odb *db, const git_oid *id)
757             {
758 288 50         assert(db && id);
    50          
759              
760 288 100         if (odb_freshen_1(db, id, false))
761 125           return 1;
762              
763 163 50         if (!git_odb_refresh(db))
764 163           return odb_freshen_1(db, id, true);
765              
766             /* Failed to refresh, hence not found */
767 0           return 0;
768             }
769              
770 4           int git_odb_exists(git_odb *db, const git_oid *id)
771             {
772             git_odb_object *object;
773              
774 4 50         assert(db && id);
    50          
775              
776 4 50         if (git_oid_is_zero(id))
777 0           return 0;
778              
779 4 50         if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
780 0           git_odb_object_free(object);
781 0           return 1;
782             }
783              
784 4 50         if (odb_exists_1(db, id, false))
785 4           return 1;
786              
787 0 0         if (!git_odb_refresh(db))
788 0           return odb_exists_1(db, id, true);
789              
790             /* Failed to refresh, hence not found */
791 0           return 0;
792             }
793              
794 0           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 0           int error = GIT_ENOTFOUND, num_found = 0;
799 0           git_oid last_found = {{0}}, found;
800              
801 0 0         for (i = 0; i < db->backends.length; ++i) {
802 0           backend_internal *internal = git_vector_get(&db->backends, i);
803 0           git_odb_backend *b = internal->backend;
804              
805 0 0         if (only_refreshed && !b->refresh)
    0          
806 0           continue;
807              
808 0 0         if (!b->exists_prefix)
809 0           continue;
810              
811 0           error = b->exists_prefix(&found, b, key, len);
812 0 0         if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
    0          
813 0           continue;
814 0 0         if (error)
815 0           return error;
816              
817             /* make sure found item doesn't introduce ambiguity */
818 0 0         if (num_found) {
819 0 0         if (git_oid__cmp(&last_found, &found))
820 0           return git_odb__error_ambiguous("multiple matches for prefix");
821             } else {
822 0           git_oid_cpy(&last_found, &found);
823 0           num_found++;
824             }
825             }
826              
827 0 0         if (!num_found)
828 0           return GIT_ENOTFOUND;
829              
830 0 0         if (out)
831 0           git_oid_cpy(out, &last_found);
832              
833 0           return 0;
834             }
835              
836 0           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 0           git_oid key = {{0}};
841              
842 0 0         assert(db && short_id);
    0          
843              
844 0 0         if (len < GIT_OID_MINPREFIXLEN)
845 0           return git_odb__error_ambiguous("prefix length too short");
846              
847 0 0         if (len >= GIT_OID_HEXSZ) {
848 0 0         if (git_odb_exists(db, short_id)) {
849 0 0         if (out)
850 0           git_oid_cpy(out, short_id);
851 0           return 0;
852             } else {
853 0           return git_odb__error_notfound(
854             "no match for id prefix", short_id, len);
855             }
856             }
857              
858 0           git_oid__cpy_prefix(&key, short_id, len);
859              
860 0           error = odb_exists_prefix_1(out, db, &key, len, false);
861              
862 0 0         if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
    0          
863 0           error = odb_exists_prefix_1(out, db, &key, len, true);
864              
865 0 0         if (error == GIT_ENOTFOUND)
866 0           return git_odb__error_notfound("no match for id prefix", &key, len);
867              
868 0           return error;
869             }
870              
871 0           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 0 0         assert(db && ids);
    0          
879              
880 0 0         for (i = 0; i < count; i++) {
881 0           git_odb_expand_id *query = &ids[i];
882 0           int error = GIT_EAMBIGUOUS;
883              
884 0 0         if (!query->type)
885 0           query->type = GIT_OBJECT_ANY;
886              
887             /* if we have a short OID, expand it first */
888 0 0         if (query->length >= GIT_OID_MINPREFIXLEN && query->length < GIT_OID_HEXSZ) {
    0          
889             git_oid actual_id;
890              
891 0           error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false);
892 0 0         if (!error) {
893 0           git_oid_cpy(&query->id, &actual_id);
894 0           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 0 0         if (query->length >= GIT_OID_HEXSZ) {
903             git_object_t actual_type;
904              
905 0           error = odb_otype_fast(&actual_type, db, &query->id);
906 0 0         if (!error) {
907 0 0         if (query->type != GIT_OBJECT_ANY && query->type != actual_type)
    0          
908 0           error = GIT_ENOTFOUND;
909             else
910 0           query->type = actual_type;
911             }
912             }
913              
914 0           switch (error) {
915             /* no errors, so we've successfully expanded the OID */
916             case 0:
917 0           continue;
918              
919             /* the object is missing or ambiguous */
920             case GIT_ENOTFOUND:
921             case GIT_EAMBIGUOUS:
922 0           memset(&query->id, 0, sizeof(git_oid));
923 0           query->length = 0;
924 0           query->type = 0;
925 0           break;
926              
927             /* something went very wrong with the ODB; bail hard */
928             default:
929 0           return error;
930             }
931             }
932              
933 0           git_error_clear();
934 0           return 0;
935             }
936              
937 382           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 382           error = git_odb__read_header_or_object(&object, len_p, type_p, db, id);
943              
944 382 100         if (object)
945 3           git_odb_object_free(object);
946              
947 382           return error;
948             }
949              
950 396           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 396           bool passthrough = false;
957             int error;
958              
959 396 50         if (!only_refreshed && (ht = odb_hardcoded_type(id)) != GIT_OBJECT_INVALID) {
    50          
960 0           *type_p = ht;
961 0           *len_p = 0;
962 0           return 0;
963             }
964              
965 787 50         for (i = 0; i < db->backends.length; ++i) {
966 787           backend_internal *internal = git_vector_get(&db->backends, i);
967 787           git_odb_backend *b = internal->backend;
968              
969 787 50         if (only_refreshed && !b->refresh)
    0          
970 0           continue;
971              
972 787 50         if (!b->read_header) {
973 0           passthrough = true;
974 0           continue;
975             }
976              
977 787           error = b->read_header(len_p, type_p, b, id);
978              
979 787           switch (error) {
980             case GIT_PASSTHROUGH:
981 0           passthrough = true;
982 0           break;
983             case GIT_ENOTFOUND:
984 391           break;
985             default:
986 396           return error;
987             }
988             }
989              
990 0 0         return passthrough ? GIT_PASSTHROUGH : GIT_ENOTFOUND;
991             }
992              
993 399           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 399           int error = GIT_ENOTFOUND;
998             git_odb_object *object;
999              
1000 399 50         assert(db && id && out && len_p && type_p);
    50          
    50          
    50          
    50          
1001              
1002 399           *out = NULL;
1003              
1004 399 50         if (git_oid_is_zero(id))
1005 0           return error_null_oid(GIT_ENOTFOUND, "cannot read object");
1006              
1007 399 100         if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
1008 3           *len_p = object->cached.size;
1009 3           *type_p = object->cached.type;
1010 3           *out = object;
1011 3           return 0;
1012             }
1013              
1014 396           error = odb_read_header_1(len_p, type_p, db, id, false);
1015              
1016 396 50         if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
    0          
1017 0           error = odb_read_header_1(len_p, type_p, db, id, true);
1018              
1019 396 50         if (error == GIT_ENOTFOUND)
1020 0           return git_odb__error_notfound("cannot read header for", id, GIT_OID_HEXSZ);
1021              
1022             /* we found the header; return early */
1023 396 50         if (!error)
1024 396           return 0;
1025              
1026 0 0         if (error == GIT_PASSTHROUGH) {
1027             /*
1028             * no backend has header-reading functionality
1029             * so try using `git_odb_read` instead
1030             */
1031 0           error = git_odb_read(&object, db, id);
1032 0 0         if (!error) {
1033 0           *len_p = object->cached.size;
1034 0           *type_p = object->cached.type;
1035 0           *out = object;
1036             }
1037             }
1038              
1039 399           return error;
1040             }
1041              
1042 638           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 638           bool found = false;
1050 638           int error = 0;
1051              
1052 638 100         if (!only_refreshed) {
1053 636 50         if ((error = odb_read_hardcoded(&found, &raw, id)) < 0)
1054 0           return error;
1055             }
1056              
1057 1900 100         for (i = 0; i < db->backends.length && !found; ++i) {
    100          
1058 1262           backend_internal *internal = git_vector_get(&db->backends, i);
1059 1262           git_odb_backend *b = internal->backend;
1060              
1061 1262 100         if (only_refreshed && !b->refresh)
    100          
1062 2           continue;
1063              
1064 1260 50         if (b->read != NULL) {
1065 1260           error = b->read(&raw.data, &raw.len, &raw.type, b, id);
1066 1260 50         if (error == GIT_PASSTHROUGH || error == GIT_ENOTFOUND)
    100          
1067 627           continue;
1068              
1069 633 50         if (error < 0)
1070 0           return error;
1071              
1072 633           found = true;
1073             }
1074             }
1075              
1076 638 100         if (!found)
1077 4           return GIT_ENOTFOUND;
1078              
1079 634 50         if (git_odb__strict_hash_verification) {
1080 634 50         if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0)
1081 0           goto out;
1082              
1083 634 50         if (!git_oid_equal(id, &hashed)) {
1084 0           error = git_odb__error_mismatch(id, &hashed);
1085 0           goto out;
1086             }
1087             }
1088              
1089 634           git_error_clear();
1090 634 50         if ((object = odb_object__alloc(id, &raw)) == NULL) {
1091 0           error = -1;
1092 0           goto out;
1093             }
1094              
1095 634           *out = git_cache_store_raw(odb_cache(db), object);
1096              
1097             out:
1098 634 50         if (error)
1099 0           git__free(raw.data);
1100 638           return error;
1101             }
1102              
1103 636           int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
1104             {
1105             int error;
1106              
1107 636 50         assert(out && db && id);
    50          
    50          
1108              
1109 636 50         if (git_oid_is_zero(id))
1110 0           return error_null_oid(GIT_ENOTFOUND, "cannot read object");
1111              
1112 636           *out = git_cache_get_raw(odb_cache(db), id);
1113 636 50         if (*out != NULL)
1114 0           return 0;
1115              
1116 636           error = odb_read_1(out, db, id, false);
1117              
1118 636 100         if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
    50          
1119 2           error = odb_read_1(out, db, id, true);
1120              
1121 636 100         if (error == GIT_ENOTFOUND)
1122 2           return git_odb__error_notfound("no match for id", id, GIT_OID_HEXSZ);
1123              
1124 634           return error;
1125             }
1126              
1127 0           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 0 0         if (git_oid_is_zero(id))
1134 0           return error_null_oid(GIT_ENOTFOUND, "cannot get object type");
1135              
1136 0 0         if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
1137 0           *type_p = object->cached.type;
1138 0           git_odb_object_free(object);
1139 0           return 0;
1140             }
1141              
1142 0           error = odb_read_header_1(&_unused, type_p, db, id, false);
1143              
1144 0 0         if (error == GIT_PASSTHROUGH) {
1145 0           error = odb_read_1(&object, db, id, false);
1146 0 0         if (!error)
1147 0           *type_p = object->cached.type;
1148 0           git_odb_object_free(object);
1149             }
1150              
1151 0           return error;
1152             }
1153              
1154 146           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 146           int error = 0;
1159 146           git_oid found_full_oid = {{0}};
1160 146           git_rawobj raw = {0};
1161 146           void *data = NULL;
1162 146           bool found = false;
1163             git_odb_object *object;
1164              
1165 438 100         for (i = 0; i < db->backends.length; ++i) {
1166 292           backend_internal *internal = git_vector_get(&db->backends, i);
1167 292           git_odb_backend *b = internal->backend;
1168              
1169 292 100         if (only_refreshed && !b->refresh)
    100          
1170 8           continue;
1171              
1172 284 50         if (b->read_prefix != NULL) {
1173             git_oid full_oid;
1174 284           error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, key, len);
1175              
1176 284 100         if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) {
    50          
1177 154           error = 0;
1178 154           continue;
1179             }
1180              
1181 130 50         if (error)
1182 0           goto out;
1183              
1184 130           git__free(data);
1185 130           data = raw.data;
1186              
1187 130 50         if (found && git_oid__cmp(&full_oid, &found_full_oid)) {
    0          
1188 0           git_buf buf = GIT_BUF_INIT;
1189              
1190 0           git_buf_printf(&buf, "multiple matches for prefix: %s",
1191             git_oid_tostr_s(&full_oid));
1192 0           git_buf_printf(&buf, " %s",
1193             git_oid_tostr_s(&found_full_oid));
1194              
1195 0           error = git_odb__error_ambiguous(buf.ptr);
1196 0           git_buf_dispose(&buf);
1197 0           goto out;
1198             }
1199              
1200 130           found_full_oid = full_oid;
1201 130           found = true;
1202             }
1203             }
1204              
1205 146 100         if (!found)
1206 16           return GIT_ENOTFOUND;
1207              
1208 130 50         if (git_odb__strict_hash_verification) {
1209             git_oid hash;
1210              
1211 130 50         if ((error = git_odb_hash(&hash, raw.data, raw.len, raw.type)) < 0)
1212 0           goto out;
1213              
1214 130 50         if (!git_oid_equal(&found_full_oid, &hash)) {
1215 130           error = git_odb__error_mismatch(&found_full_oid, &hash);
1216 0           goto out;
1217             }
1218             }
1219              
1220 130 50         if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) {
1221 0           error = -1;
1222 0           goto out;
1223             }
1224              
1225 130           *out = git_cache_store_raw(odb_cache(db), object);
1226              
1227             out:
1228 130 50         if (error)
1229 0           git__free(raw.data);
1230              
1231 146           return error;
1232             }
1233              
1234 138           int git_odb_read_prefix(
1235             git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len)
1236             {
1237 138           git_oid key = {{0}};
1238             int error;
1239              
1240 138 50         assert(out && db);
    50          
1241              
1242 138 50         if (len < GIT_OID_MINPREFIXLEN)
1243 0           return git_odb__error_ambiguous("prefix length too short");
1244              
1245 138 50         if (len > GIT_OID_HEXSZ)
1246 0           len = GIT_OID_HEXSZ;
1247              
1248 138 100         if (len == GIT_OID_HEXSZ) {
1249 122           *out = git_cache_get_raw(odb_cache(db), short_id);
1250 122 50         if (*out != NULL)
1251 0           return 0;
1252             }
1253              
1254 138           git_oid__cpy_prefix(&key, short_id, len);
1255              
1256 138           error = read_prefix_1(out, db, &key, len, false);
1257              
1258 138 100         if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
    50          
1259 8           error = read_prefix_1(out, db, &key, len, true);
1260              
1261 138 100         if (error == GIT_ENOTFOUND)
1262 8           return git_odb__error_notfound("no match for prefix", &key, len);
1263              
1264 138           return error;
1265             }
1266              
1267 1           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 3 100         git_vector_foreach(&db->backends, i, internal) {
1273 2           git_odb_backend *b = internal->backend;
1274 2           int error = b->foreach(b, cb, payload);
1275 2 50         if (error != 0)
1276 0           return error;
1277             }
1278              
1279 1           return 0;
1280             }
1281              
1282 171           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 171           int error = GIT_ERROR;
1287             git_odb_stream *stream;
1288              
1289 171 50         assert(oid && db);
    50          
1290              
1291 171           git_odb_hash(oid, data, len, type);
1292              
1293 171 50         if (git_oid_is_zero(oid))
1294 0           return error_null_oid(GIT_EINVALID, "cannot write object");
1295              
1296 171 100         if (git_odb__freshen(db, oid))
1297 51           return 0;
1298              
1299 354 100         for (i = 0; i < db->backends.length && error < 0; ++i) {
    100          
1300 234           backend_internal *internal = git_vector_get(&db->backends, i);
1301 234           git_odb_backend *b = internal->backend;
1302              
1303             /* we don't write in alternates! */
1304 234 50         if (internal->is_alternate)
1305 0           continue;
1306              
1307 234 100         if (b->write != NULL)
1308 120           error = b->write(b, oid, data, len, type);
1309             }
1310              
1311 120 50         if (!error || error == GIT_PASSTHROUGH)
    0          
1312 120           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 0 0         if ((error = git_odb_open_wstream(&stream, db, len, type)) != 0)
1319 0           return error;
1320              
1321 0           stream->write(stream, data, len);
1322 0           error = stream->finalize_write(stream, oid);
1323 0           git_odb_stream_free(stream);
1324              
1325 171           return error;
1326             }
1327              
1328 63           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 63 50         if ((error = git_odb__format_object_header(&hdrlen,
1335             header, sizeof(header), size, type)) < 0)
1336 0           return error;
1337              
1338 63           return git_hash_update(ctx, header, hdrlen);
1339             }
1340              
1341 63           int git_odb_open_wstream(
1342             git_odb_stream **stream, git_odb *db, git_object_size_t size, git_object_t type)
1343             {
1344 63           size_t i, writes = 0;
1345 63           int error = GIT_ERROR;
1346 63           git_hash_ctx *ctx = NULL;
1347              
1348 63 50         assert(stream && db);
    50          
1349              
1350 189 100         for (i = 0; i < db->backends.length && error < 0; ++i) {
    50          
1351 126           backend_internal *internal = git_vector_get(&db->backends, i);
1352 126           git_odb_backend *b = internal->backend;
1353              
1354             /* we don't write in alternates! */
1355 126 50         if (internal->is_alternate)
1356 0           continue;
1357              
1358 126 100         if (b->writestream != NULL) {
1359 63           ++writes;
1360 63           error = b->writestream(stream, b, size, type);
1361 63 50         } else if (b->write != NULL) {
1362 0           ++writes;
1363 0           error = init_fake_wstream(stream, b, size, type);
1364             }
1365             }
1366              
1367 63 50         if (error < 0) {
1368 0 0         if (error == GIT_PASSTHROUGH)
1369 0           error = 0;
1370 0 0         else if (!writes)
1371 0           error = git_odb__error_unsupported_in_backend("write object");
1372              
1373 0           goto done;
1374             }
1375              
1376 63           ctx = git__malloc(sizeof(git_hash_ctx));
1377 63 50         GIT_ERROR_CHECK_ALLOC(ctx);
1378              
1379 63 50         if ((error = git_hash_ctx_init(ctx)) < 0 ||
    50          
1380             (error = hash_header(ctx, size, type)) < 0)
1381             goto done;
1382              
1383 63           (*stream)->hash_ctx = ctx;
1384 63           (*stream)->declared_size = size;
1385 63           (*stream)->received_bytes = 0;
1386              
1387             done:
1388 63 50         if (error)
1389 0           git__free(ctx);
1390 63           return error;
1391             }
1392              
1393 0           static int git_odb_stream__invalid_length(
1394             const git_odb_stream *stream,
1395             const char *action)
1396             {
1397 0           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 0           return -1;
1404             }
1405              
1406 62           int git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len)
1407             {
1408 62           git_hash_update(stream->hash_ctx, buffer, len);
1409              
1410 62           stream->received_bytes += len;
1411              
1412 62 50         if (stream->received_bytes > stream->declared_size)
1413 0           return git_odb_stream__invalid_length(stream,
1414             "stream_write()");
1415              
1416 62           return stream->write(stream, buffer, len);
1417             }
1418              
1419 63           int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream)
1420             {
1421 63 50         if (stream->received_bytes != stream->declared_size)
1422 0           return git_odb_stream__invalid_length(stream,
1423             "stream_finalize_write()");
1424              
1425 63           git_hash_final(out, stream->hash_ctx);
1426              
1427 63 100         if (git_odb__freshen(stream->backend->odb, out))
1428 20           return 0;
1429              
1430 43           return stream->finalize_write(stream, out);
1431             }
1432              
1433 0           int git_odb_stream_read(git_odb_stream *stream, char *buffer, size_t len)
1434             {
1435 0           return stream->read(stream, buffer, len);
1436             }
1437              
1438 63           void git_odb_stream_free(git_odb_stream *stream)
1439             {
1440 63 50         if (stream == NULL)
1441 0           return;
1442              
1443 63           git_hash_ctx_cleanup(stream->hash_ctx);
1444 63           git__free(stream->hash_ctx);
1445 63           stream->free(stream);
1446             }
1447              
1448 0           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 0           size_t i, reads = 0;
1456 0           int error = GIT_ERROR;
1457              
1458 0 0         assert(stream && db);
    0          
1459              
1460 0 0         for (i = 0; i < db->backends.length && error < 0; ++i) {
    0          
1461 0           backend_internal *internal = git_vector_get(&db->backends, i);
1462 0           git_odb_backend *b = internal->backend;
1463              
1464 0 0         if (b->readstream != NULL) {
1465 0           ++reads;
1466 0           error = b->readstream(stream, len, type, b, oid);
1467             }
1468             }
1469              
1470 0 0         if (error == GIT_PASSTHROUGH)
1471 0           error = 0;
1472 0 0         if (error < 0 && !reads)
    0          
1473 0           error = git_odb__error_unsupported_in_backend("read object streamed");
1474              
1475 0           return error;
1476             }
1477              
1478 0           int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_indexer_progress_cb progress_cb, void *progress_payload)
1479             {
1480 0           size_t i, writes = 0;
1481 0           int error = GIT_ERROR;
1482              
1483 0 0         assert(out && db);
    0          
1484              
1485 0 0         for (i = 0; i < db->backends.length && error < 0; ++i) {
    0          
1486 0           backend_internal *internal = git_vector_get(&db->backends, i);
1487 0           git_odb_backend *b = internal->backend;
1488              
1489             /* we don't write in alternates! */
1490 0 0         if (internal->is_alternate)
1491 0           continue;
1492              
1493 0 0         if (b->writepack != NULL) {
1494 0           ++writes;
1495 0           error = b->writepack(out, b, db, progress_cb, progress_payload);
1496             }
1497             }
1498              
1499 0 0         if (error == GIT_PASSTHROUGH)
1500 0           error = 0;
1501 0 0         if (error < 0 && !writes)
    0          
1502 0           error = git_odb__error_unsupported_in_backend("write pack");
1503              
1504 0           return error;
1505             }
1506              
1507 0           void *git_odb_backend_data_alloc(git_odb_backend *backend, size_t len)
1508             {
1509             GIT_UNUSED(backend);
1510 0           return git__malloc(len);
1511             }
1512              
1513 0           void *git_odb_backend_malloc(git_odb_backend *backend, size_t len)
1514             {
1515 0           return git_odb_backend_data_alloc(backend, len);
1516             }
1517              
1518 0           void git_odb_backend_data_free(git_odb_backend *backend, void *data)
1519             {
1520             GIT_UNUSED(backend);
1521 0           git__free(data);
1522 0           }
1523              
1524 175           int git_odb_refresh(struct git_odb *db)
1525             {
1526             size_t i;
1527 175 50         assert(db);
1528              
1529 530 100         for (i = 0; i < db->backends.length; ++i) {
1530 355           backend_internal *internal = git_vector_get(&db->backends, i);
1531 355           git_odb_backend *b = internal->backend;
1532              
1533 355 100         if (b->refresh != NULL) {
1534 175           int error = b->refresh(b);
1535 175 50         if (error < 0)
1536 0           return error;
1537             }
1538             }
1539              
1540 175           return 0;
1541             }
1542              
1543 0           int git_odb__error_mismatch(const git_oid *expected, const git_oid *actual)
1544             {
1545             char expected_oid[GIT_OID_HEXSZ + 1], actual_oid[GIT_OID_HEXSZ + 1];
1546              
1547 0           git_oid_tostr(expected_oid, sizeof(expected_oid), expected);
1548 0           git_oid_tostr(actual_oid, sizeof(actual_oid), actual);
1549              
1550 0           git_error_set(GIT_ERROR_ODB, "object hash mismatch - expected %s but got %s",
1551             expected_oid, actual_oid);
1552              
1553 0           return GIT_EMISMATCH;
1554             }
1555              
1556 1622           int git_odb__error_notfound(
1557             const char *message, const git_oid *oid, size_t oid_len)
1558             {
1559 1622 50         if (oid != NULL) {
1560             char oid_str[GIT_OID_HEXSZ + 1];
1561 1622           git_oid_tostr(oid_str, oid_len+1, oid);
1562 1622           git_error_set(GIT_ERROR_ODB, "object not found - %s (%.*s)",
1563             message, (int) oid_len, oid_str);
1564             } else
1565 0           git_error_set(GIT_ERROR_ODB, "object not found - %s", message);
1566              
1567 1622           return GIT_ENOTFOUND;
1568             }
1569              
1570 0           static int error_null_oid(int error, const char *message)
1571             {
1572 0           git_error_set(GIT_ERROR_ODB, "odb: %s: null OID cannot exist", message);
1573 0           return error;
1574             }
1575              
1576 0           int git_odb__error_ambiguous(const char *message)
1577             {
1578 0           git_error_set(GIT_ERROR_ODB, "ambiguous SHA1 prefix - %s", message);
1579 0           return GIT_EAMBIGUOUS;
1580             }
1581              
1582 0           int git_odb_init_backend(git_odb_backend *backend, unsigned int version)
1583             {
1584 0 0         GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1585             backend, version, git_odb_backend, GIT_ODB_BACKEND_INIT);
1586 0           return 0;
1587             }