File Coverage

deps/libgit2/src/libgit2/odb.c
Criterion Covered Total %
statement 479 941 50.9
branch 243 622 39.0
condition n/a
subroutine n/a
pod n/a
total 722 1563 46.1


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