File Coverage

deps/libgit2/src/odb.c
Criterion Covered Total %
statement 407 765 53.2
branch 218 540 40.3
condition n/a
subroutine n/a
pod n/a
total 625 1305 47.8


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 1950           static git_cache *odb_cache(git_odb *odb)
46             {
47 1950 50         if (odb->rc.owner != NULL) {
48 1950           git_repository *owner = odb->rc.owner;
49 1950           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 1045           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 1045 100         if (!git_oid_cmp(id, &empty_tree))
65 1           return GIT_OBJECT_TREE;
66              
67 1044           return GIT_OBJECT_INVALID;
68             }
69              
70 649           static int odb_read_hardcoded(bool *found, git_rawobj *raw, const git_oid *id)
71             {
72             git_object_t type;
73              
74 649           *found = false;
75              
76 649 100         if ((type = odb_hardcoded_type(id)) == GIT_OBJECT_INVALID)
77 648           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 1403           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 1403           const char *type_str = git_object_type2string(obj_type);
96 1403 50         int hdr_max = (hdr_size > INT_MAX-2) ? (INT_MAX-2) : (int)hdr_size;
97             int len;
98              
99 1403           len = p_snprintf(hdr, hdr_max, "%s %"PRId64, type_str, (int64_t)obj_len);
100              
101 1403 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 1403           *written = (size_t)(len + 1);
107 1403           return 0;
108             }
109              
110 994           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 994 50         assert(id && obj);
    50          
118              
119 994 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 994 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 994 50         if ((error = git_odb__format_object_header(&hdrlen,
130             header, sizeof(header), obj->len, obj->type)) < 0)
131 0           return error;
132              
133 994           vec[0].data = header;
134 994           vec[0].len = hdrlen;
135 994           vec[1].data = obj->data;
136 994           vec[1].len = obj->len;
137              
138 994           return git_hash_vec(id, vec, 2);
139             }
140              
141              
142 776           static git_odb_object *odb_object__alloc(const git_oid *oid, git_rawobj *source)
143             {
144 776           git_odb_object *object = git__calloc(1, sizeof(git_odb_object));
145              
146 776 50         if (object != NULL) {
147 776           git_oid_cpy(&object->cached.oid, oid);
148 776           object->cached.type = source->type;
149 776           object->cached.size = source->len;
150 776           object->buffer = source->data;
151             }
152              
153 776           return object;
154             }
155              
156 774           void git_odb_object__free(void *object)
157             {
158 774 50         if (object != NULL) {
159 774           git__free(((git_odb_object *)object)->buffer);
160 774           git__free(object);
161             }
162 774           }
163              
164 1           const git_oid *git_odb_object_id(git_odb_object *object)
165             {
166 1           return &object->cached.oid;
167             }
168              
169 638           const void *git_odb_object_data(git_odb_object *object)
170             {
171 638           return object->buffer;
172             }
173              
174 646           size_t git_odb_object_size(git_odb_object *object)
175             {
176 646           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 1076           void git_odb_object_free(git_odb_object *object)
192             {
193 1076 100         if (object == NULL)
194 3           return;
195              
196 1073           git_cached_obj_decref(object);
197             }
198              
199 126           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 126           ssize_t read_len = 0;
205 126           int error = 0;
206              
207 126 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 126 50         if ((error = git_hash_ctx_init(&ctx)) < 0)
213 0           return error;
214              
215 126 50         if ((error = git_odb__format_object_header(&hdr_len, hdr,
216             sizeof(hdr), size, type)) < 0)
217 0           goto done;
218              
219 126 50         if ((error = git_hash_update(&ctx, hdr, hdr_len)) < 0)
220 0           goto done;
221              
222 235 100         while (size > 0 && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) {
    50          
223 109 50         if ((error = git_hash_update(&ctx, buffer, read_len)) < 0)
224 0           goto done;
225              
226 109           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 126 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 126           error = git_hash_final(out, &ctx);
240              
241             done:
242 126           git_hash_ctx_cleanup(&ctx);
243 126           return error;
244             }
245              
246 165           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 165           git_buf raw = GIT_BUF_INIT;
251              
252 165 100         if (!fl)
253 126           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 39 50         if (!(error = git_futils_readbuffer_fd(&raw, fd, size))) {
260 39           git_buf post = GIT_BUF_INIT;
261              
262 39           error = git_filter_list_apply_to_data(&post, fl, &raw);
263              
264 39           git_buf_dispose(&raw);
265              
266 39 50         if (!error)
267 39           error = git_odb_hash(out, post.ptr, post.size, type);
268              
269 39           git_buf_dispose(&post);
270             }
271              
272 165           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 992           int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type)
346             {
347             git_rawobj raw;
348              
349 992 50         assert(id);
350              
351 992           raw.data = (void *)data;
352 992           raw.len = len;
353 992           raw.type = type;
354              
355 992           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 212           void git_odb_free(git_odb *db)
703             {
704 212 100         if (db == NULL)
705 10           return;
706              
707 202 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 652           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 652           bool found = false;
1050 652           int error = 0;
1051              
1052 652 100         if (!only_refreshed) {
1053 649 50         if ((error = odb_read_hardcoded(&found, &raw, id)) < 0)
1054 0           return error;
1055             }
1056              
1057 1942 100         for (i = 0; i < db->backends.length && !found; ++i) {
    100          
1058 1290           backend_internal *internal = git_vector_get(&db->backends, i);
1059 1290           git_odb_backend *b = internal->backend;
1060              
1061 1290 100         if (only_refreshed && !b->refresh)
    100          
1062 3           continue;
1063              
1064 1287 50         if (b->read != NULL) {
1065 1287           error = b->read(&raw.data, &raw.len, &raw.type, b, id);
1066 1287 50         if (error == GIT_PASSTHROUGH || error == GIT_ENOTFOUND)
    100          
1067 642           continue;
1068              
1069 645 50         if (error < 0)
1070 0           return error;
1071              
1072 645           found = true;
1073             }
1074             }
1075              
1076 652 100         if (!found)
1077 6           return GIT_ENOTFOUND;
1078              
1079 646 50         if (git_odb__strict_hash_verification) {
1080 646 50         if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0)
1081 0           goto out;
1082              
1083 646 50         if (!git_oid_equal(id, &hashed)) {
1084 0           error = git_odb__error_mismatch(id, &hashed);
1085 0           goto out;
1086             }
1087             }
1088              
1089 646           git_error_clear();
1090 646 50         if ((object = odb_object__alloc(id, &raw)) == NULL) {
1091 0           error = -1;
1092 0           goto out;
1093             }
1094              
1095 646           *out = git_cache_store_raw(odb_cache(db), object);
1096              
1097             out:
1098 646 50         if (error)
1099 0           git__free(raw.data);
1100 652           return error;
1101             }
1102              
1103 649           int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
1104             {
1105             int error;
1106              
1107 649 50         assert(out && db && id);
    50          
    50          
1108              
1109 649 50         if (git_oid_is_zero(id))
1110 0           return error_null_oid(GIT_ENOTFOUND, "cannot read object");
1111              
1112 649           *out = git_cache_get_raw(odb_cache(db), id);
1113 649 50         if (*out != NULL)
1114 0           return 0;
1115              
1116 649           error = odb_read_1(out, db, id, false);
1117              
1118 649 100         if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
    50          
1119 3           error = odb_read_1(out, db, id, true);
1120              
1121 649 100         if (error == GIT_ENOTFOUND)
1122 3           return git_odb__error_notfound("no match for id", id, GIT_OID_HEXSZ);
1123              
1124 646           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             int error;
1287             git_odb_stream *stream;
1288              
1289 171 50         assert(oid && db);
    50          
1290              
1291 171 50         if ((error = git_odb_hash(oid, data, len, type)) < 0)
1292 0           return error;
1293              
1294 171 50         if (git_oid_is_zero(oid))
1295 0           return error_null_oid(GIT_EINVALID, "cannot write object");
1296              
1297 171 100         if (git_odb__freshen(db, oid))
1298 51           return 0;
1299              
1300 354 100         for (i = 0, error = GIT_ERROR; i < db->backends.length && error < 0; ++i) {
    100          
1301 234           backend_internal *internal = git_vector_get(&db->backends, i);
1302 234           git_odb_backend *b = internal->backend;
1303              
1304             /* we don't write in alternates! */
1305 234 50         if (internal->is_alternate)
1306 0           continue;
1307              
1308 234 100         if (b->write != NULL)
1309 120           error = b->write(b, oid, data, len, type);
1310             }
1311              
1312 120 50         if (!error || error == GIT_PASSTHROUGH)
    0          
1313 120           return 0;
1314              
1315             /* if no backends were able to write the object directly, we try a
1316             * streaming write to the backends; just write the whole object into the
1317             * stream in one push
1318             */
1319 0 0         if ((error = git_odb_open_wstream(&stream, db, len, type)) != 0)
1320 0           return error;
1321              
1322 0           stream->write(stream, data, len);
1323 0           error = stream->finalize_write(stream, oid);
1324 0           git_odb_stream_free(stream);
1325              
1326 171           return error;
1327             }
1328              
1329 63           static int hash_header(git_hash_ctx *ctx, git_object_size_t size, git_object_t type)
1330             {
1331             char header[64];
1332             size_t hdrlen;
1333             int error;
1334              
1335 63 50         if ((error = git_odb__format_object_header(&hdrlen,
1336             header, sizeof(header), size, type)) < 0)
1337 0           return error;
1338              
1339 63           return git_hash_update(ctx, header, hdrlen);
1340             }
1341              
1342 63           int git_odb_open_wstream(
1343             git_odb_stream **stream, git_odb *db, git_object_size_t size, git_object_t type)
1344             {
1345 63           size_t i, writes = 0;
1346 63           int error = GIT_ERROR;
1347 63           git_hash_ctx *ctx = NULL;
1348              
1349 63 50         assert(stream && db);
    50          
1350              
1351 189 100         for (i = 0; i < db->backends.length && error < 0; ++i) {
    50          
1352 126           backend_internal *internal = git_vector_get(&db->backends, i);
1353 126           git_odb_backend *b = internal->backend;
1354              
1355             /* we don't write in alternates! */
1356 126 50         if (internal->is_alternate)
1357 0           continue;
1358              
1359 126 100         if (b->writestream != NULL) {
1360 63           ++writes;
1361 63           error = b->writestream(stream, b, size, type);
1362 63 50         } else if (b->write != NULL) {
1363 0           ++writes;
1364 0           error = init_fake_wstream(stream, b, size, type);
1365             }
1366             }
1367              
1368 63 50         if (error < 0) {
1369 0 0         if (error == GIT_PASSTHROUGH)
1370 0           error = 0;
1371 0 0         else if (!writes)
1372 0           error = git_odb__error_unsupported_in_backend("write object");
1373              
1374 0           goto done;
1375             }
1376              
1377 63           ctx = git__malloc(sizeof(git_hash_ctx));
1378 63 50         GIT_ERROR_CHECK_ALLOC(ctx);
1379              
1380 63 50         if ((error = git_hash_ctx_init(ctx)) < 0 ||
    50          
1381             (error = hash_header(ctx, size, type)) < 0)
1382             goto done;
1383              
1384 63           (*stream)->hash_ctx = ctx;
1385 63           (*stream)->declared_size = size;
1386 63           (*stream)->received_bytes = 0;
1387              
1388             done:
1389 63 50         if (error)
1390 0           git__free(ctx);
1391 63           return error;
1392             }
1393              
1394 0           static int git_odb_stream__invalid_length(
1395             const git_odb_stream *stream,
1396             const char *action)
1397             {
1398 0           git_error_set(GIT_ERROR_ODB,
1399             "cannot %s - "
1400             "Invalid length. %"PRId64" was expected. The "
1401             "total size of the received chunks amounts to %"PRId64".",
1402             action, stream->declared_size, stream->received_bytes);
1403              
1404 0           return -1;
1405             }
1406              
1407 62           int git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len)
1408             {
1409 62           git_hash_update(stream->hash_ctx, buffer, len);
1410              
1411 62           stream->received_bytes += len;
1412              
1413 62 50         if (stream->received_bytes > stream->declared_size)
1414 0           return git_odb_stream__invalid_length(stream,
1415             "stream_write()");
1416              
1417 62           return stream->write(stream, buffer, len);
1418             }
1419              
1420 63           int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream)
1421             {
1422 63 50         if (stream->received_bytes != stream->declared_size)
1423 0           return git_odb_stream__invalid_length(stream,
1424             "stream_finalize_write()");
1425              
1426 63           git_hash_final(out, stream->hash_ctx);
1427              
1428 63 100         if (git_odb__freshen(stream->backend->odb, out))
1429 20           return 0;
1430              
1431 43           return stream->finalize_write(stream, out);
1432             }
1433              
1434 0           int git_odb_stream_read(git_odb_stream *stream, char *buffer, size_t len)
1435             {
1436 0           return stream->read(stream, buffer, len);
1437             }
1438              
1439 63           void git_odb_stream_free(git_odb_stream *stream)
1440             {
1441 63 50         if (stream == NULL)
1442 0           return;
1443              
1444 63           git_hash_ctx_cleanup(stream->hash_ctx);
1445 63           git__free(stream->hash_ctx);
1446 63           stream->free(stream);
1447             }
1448              
1449 0           int git_odb_open_rstream(
1450             git_odb_stream **stream,
1451             size_t *len,
1452             git_object_t *type,
1453             git_odb *db,
1454             const git_oid *oid)
1455             {
1456 0           size_t i, reads = 0;
1457 0           int error = GIT_ERROR;
1458              
1459 0 0         assert(stream && db);
    0          
1460              
1461 0 0         for (i = 0; i < db->backends.length && error < 0; ++i) {
    0          
1462 0           backend_internal *internal = git_vector_get(&db->backends, i);
1463 0           git_odb_backend *b = internal->backend;
1464              
1465 0 0         if (b->readstream != NULL) {
1466 0           ++reads;
1467 0           error = b->readstream(stream, len, type, b, oid);
1468             }
1469             }
1470              
1471 0 0         if (error == GIT_PASSTHROUGH)
1472 0           error = 0;
1473 0 0         if (error < 0 && !reads)
    0          
1474 0           error = git_odb__error_unsupported_in_backend("read object streamed");
1475              
1476 0           return error;
1477             }
1478              
1479 0           int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_indexer_progress_cb progress_cb, void *progress_payload)
1480             {
1481 0           size_t i, writes = 0;
1482 0           int error = GIT_ERROR;
1483              
1484 0 0         assert(out && db);
    0          
1485              
1486 0 0         for (i = 0; i < db->backends.length && error < 0; ++i) {
    0          
1487 0           backend_internal *internal = git_vector_get(&db->backends, i);
1488 0           git_odb_backend *b = internal->backend;
1489              
1490             /* we don't write in alternates! */
1491 0 0         if (internal->is_alternate)
1492 0           continue;
1493              
1494 0 0         if (b->writepack != NULL) {
1495 0           ++writes;
1496 0           error = b->writepack(out, b, db, progress_cb, progress_payload);
1497             }
1498             }
1499              
1500 0 0         if (error == GIT_PASSTHROUGH)
1501 0           error = 0;
1502 0 0         if (error < 0 && !writes)
    0          
1503 0           error = git_odb__error_unsupported_in_backend("write pack");
1504              
1505 0           return error;
1506             }
1507              
1508 0           void *git_odb_backend_data_alloc(git_odb_backend *backend, size_t len)
1509             {
1510             GIT_UNUSED(backend);
1511 0           return git__malloc(len);
1512             }
1513              
1514             #ifndef GIT_DEPRECATE_HARD
1515 0           void *git_odb_backend_malloc(git_odb_backend *backend, size_t len)
1516             {
1517 0           return git_odb_backend_data_alloc(backend, len);
1518             }
1519             #endif
1520              
1521 0           void git_odb_backend_data_free(git_odb_backend *backend, void *data)
1522             {
1523             GIT_UNUSED(backend);
1524 0           git__free(data);
1525 0           }
1526              
1527 176           int git_odb_refresh(struct git_odb *db)
1528             {
1529             size_t i;
1530 176 50         assert(db);
1531              
1532 533 100         for (i = 0; i < db->backends.length; ++i) {
1533 357           backend_internal *internal = git_vector_get(&db->backends, i);
1534 357           git_odb_backend *b = internal->backend;
1535              
1536 357 100         if (b->refresh != NULL) {
1537 176           int error = b->refresh(b);
1538 176 50         if (error < 0)
1539 0           return error;
1540             }
1541             }
1542              
1543 176           return 0;
1544             }
1545              
1546 0           int git_odb__error_mismatch(const git_oid *expected, const git_oid *actual)
1547             {
1548             char expected_oid[GIT_OID_HEXSZ + 1], actual_oid[GIT_OID_HEXSZ + 1];
1549              
1550 0           git_oid_tostr(expected_oid, sizeof(expected_oid), expected);
1551 0           git_oid_tostr(actual_oid, sizeof(actual_oid), actual);
1552              
1553 0           git_error_set(GIT_ERROR_ODB, "object hash mismatch - expected %s but got %s",
1554             expected_oid, actual_oid);
1555              
1556 0           return GIT_EMISMATCH;
1557             }
1558              
1559 1638           int git_odb__error_notfound(
1560             const char *message, const git_oid *oid, size_t oid_len)
1561             {
1562 1638 50         if (oid != NULL) {
1563             char oid_str[GIT_OID_HEXSZ + 1];
1564 1638           git_oid_tostr(oid_str, oid_len+1, oid);
1565 1638           git_error_set(GIT_ERROR_ODB, "object not found - %s (%.*s)",
1566             message, (int) oid_len, oid_str);
1567             } else
1568 0           git_error_set(GIT_ERROR_ODB, "object not found - %s", message);
1569              
1570 1638           return GIT_ENOTFOUND;
1571             }
1572              
1573 0           static int error_null_oid(int error, const char *message)
1574             {
1575 0           git_error_set(GIT_ERROR_ODB, "odb: %s: null OID cannot exist", message);
1576 0           return error;
1577             }
1578              
1579 0           int git_odb__error_ambiguous(const char *message)
1580             {
1581 0           git_error_set(GIT_ERROR_ODB, "ambiguous SHA1 prefix - %s", message);
1582 0           return GIT_EAMBIGUOUS;
1583             }
1584              
1585 0           int git_odb_init_backend(git_odb_backend *backend, unsigned int version)
1586             {
1587 0 0         GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1588             backend, version, git_odb_backend, GIT_ODB_BACKEND_INIT);
1589 0           return 0;
1590             }