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