2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
11 #include "git2/object.h"
12 #include "git2/sys/odb_backend.h"
17 #include "repository.h"
20 #include "git2/odb_backend.h"
22 #include "git2/oidarray.h"
24 #define GIT_ALTERNATES_FILE "info/alternates"
26 #define GIT_ALTERNATES_MAX_DEPTH 5
29 * We work under the assumption that most objects for long-running
30 * operations will be packed
32 int git_odb__loose_priority
= GIT_ODB_DEFAULT_LOOSE_PRIORITY
;
33 int git_odb__packed_priority
= GIT_ODB_DEFAULT_PACKED_PRIORITY
;
35 bool git_odb__strict_hash_verification
= true;
39 git_odb_backend
*backend
;
45 static git_cache
*odb_cache(git_odb
*odb
)
47 git_repository
*owner
= GIT_REFCOUNT_OWNER(odb
);
49 return &owner
->objects
;
52 return &odb
->own_cache
;
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
);
59 static git_object_t
odb_hardcoded_type(const git_oid
*id
)
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 }};
64 if (!git_oid_cmp(id
, &empty_tree
))
65 return GIT_OBJECT_TREE
;
67 return GIT_OBJECT_INVALID
;
70 static int odb_read_hardcoded(bool *found
, git_rawobj
*raw
, const git_oid
*id
)
76 if ((type
= odb_hardcoded_type(id
)) == GIT_OBJECT_INVALID
)
81 raw
->data
= git__calloc(1, sizeof(uint8_t));
82 GIT_ERROR_CHECK_ALLOC(raw
->data
);
88 int git_odb__format_object_header(
92 git_object_size_t obj_len
,
93 git_object_t obj_type
)
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
;
99 len
= p_snprintf(hdr
, hdr_max
, "%s %"PRId64
, type_str
, (int64_t)obj_len
);
101 if (len
< 0 || len
>= hdr_max
) {
102 git_error_set(GIT_ERROR_OS
, "object header creation failed");
106 *written
= (size_t)(len
+ 1);
110 int git_odb__hashobj(git_oid
*id
, git_rawobj
*obj
)
120 if (!git_object_typeisloose(obj
->type
)) {
121 git_error_set(GIT_ERROR_INVALID
, "invalid object type");
125 if (!obj
->data
&& obj
->len
!= 0) {
126 git_error_set(GIT_ERROR_INVALID
, "invalid object");
130 if ((error
= git_odb__format_object_header(&hdrlen
,
131 header
, sizeof(header
), obj
->len
, obj
->type
)) < 0)
134 vec
[0].data
= header
;
136 vec
[1].data
= obj
->data
;
137 vec
[1].len
= obj
->len
;
139 return git_hash_vec(id
, vec
, 2);
143 static git_odb_object
*odb_object__alloc(const git_oid
*oid
, git_rawobj
*source
)
145 git_odb_object
*object
= git__calloc(1, sizeof(git_odb_object
));
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
;
157 void git_odb_object__free(void *object
)
159 if (object
!= NULL
) {
160 git__free(((git_odb_object
*)object
)->buffer
);
165 const git_oid
*git_odb_object_id(git_odb_object
*object
)
167 return &object
->cached
.oid
;
170 const void *git_odb_object_data(git_odb_object
*object
)
172 return object
->buffer
;
175 size_t git_odb_object_size(git_odb_object
*object
)
177 return object
->cached
.size
;
180 git_object_t
git_odb_object_type(git_odb_object
*object
)
182 return object
->cached
.type
;
185 int git_odb_object_dup(git_odb_object
**dest
, git_odb_object
*source
)
187 git_cached_obj_incref(source
);
192 void git_odb_object_free(git_odb_object
*object
)
197 git_cached_obj_decref(object
);
200 int git_odb__hashfd(git_oid
*out
, git_file fd
, size_t size
, git_object_t type
)
203 char hdr
[64], buffer
[FILEIO_BUFSIZE
];
205 ssize_t read_len
= 0;
208 if (!git_object_typeisloose(type
)) {
209 git_error_set(GIT_ERROR_INVALID
, "invalid object type for hash");
213 if ((error
= git_hash_ctx_init(&ctx
)) < 0)
216 if ((error
= git_odb__format_object_header(&hdr_len
, hdr
,
217 sizeof(hdr
), size
, type
)) < 0)
220 if ((error
= git_hash_update(&ctx
, hdr
, hdr_len
)) < 0)
223 while (size
> 0 && (read_len
= p_read(fd
, buffer
, sizeof(buffer
))) > 0) {
224 if ((error
= git_hash_update(&ctx
, buffer
, read_len
)) < 0)
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");
240 error
= git_hash_final(out
, &ctx
);
243 git_hash_ctx_cleanup(&ctx
);
247 int git_odb__hashfd_filtered(
248 git_oid
*out
, git_file fd
, size_t size
, git_object_t type
, git_filter_list
*fl
)
251 git_buf raw
= GIT_BUF_INIT
;
254 return git_odb__hashfd(out
, fd
, size
, type
);
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
260 if (!(error
= git_futils_readbuffer_fd(&raw
, fd
, size
))) {
261 git_buf post
= GIT_BUF_INIT
;
263 error
= git_filter_list__convert_buf(&post
, fl
, &raw
);
266 error
= git_odb_hash(out
, post
.ptr
, post
.size
, type
);
268 git_buf_dispose(&post
);
274 int git_odb__hashlink(git_oid
*out
, const char *path
)
280 if (git_path_lstat(path
, &st
) < 0)
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");
288 size
= (int)st
.st_size
;
290 if (S_ISLNK(st
.st_mode
)) {
295 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size
, size
, 1);
296 link_data
= git__malloc(alloc_size
);
297 GIT_ERROR_CHECK_ALLOC(link_data
);
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
);
305 GIT_ASSERT(read_len
<= size
);
306 link_data
[read_len
] = '\0';
308 result
= git_odb_hash(out
, link_data
, read_len
, GIT_OBJECT_BLOB
);
309 git__free(link_data
);
311 int fd
= git_futils_open_ro(path
);
314 result
= git_odb__hashfd(out
, fd
, size
, GIT_OBJECT_BLOB
);
321 int git_odb_hashfile(git_oid
*out
, const char *path
, git_object_t type
)
326 if ((fd
= git_futils_open_ro(path
)) < 0)
329 if ((error
= git_futils_filesize(&size
, fd
)) < 0)
332 if (!git__is_sizet(size
)) {
333 git_error_set(GIT_ERROR_OS
, "file size overflow for 32-bit systems");
338 error
= git_odb__hashfd(out
, fd
, (size_t)size
, type
);
345 int git_odb_hash(git_oid
*id
, const void *data
, size_t len
, git_object_t type
)
351 raw
.data
= (void *)data
;
355 return git_odb__hashobj(id
, &raw
);
363 git_odb_stream stream
;
365 size_t size
, written
;
369 static int fake_wstream__fwrite(git_odb_stream
*_stream
, const git_oid
*oid
)
371 fake_wstream
*stream
= (fake_wstream
*)_stream
;
372 return _stream
->backend
->write(_stream
->backend
, oid
, stream
->buffer
, stream
->size
, stream
->type
);
375 static int fake_wstream__write(git_odb_stream
*_stream
, const char *data
, size_t len
)
377 fake_wstream
*stream
= (fake_wstream
*)_stream
;
379 GIT_ASSERT(stream
->written
+ len
<= stream
->size
);
381 memcpy(stream
->buffer
+ stream
->written
, data
, len
);
382 stream
->written
+= len
;
386 static void fake_wstream__free(git_odb_stream
*_stream
)
388 fake_wstream
*stream
= (fake_wstream
*)_stream
;
390 git__free(stream
->buffer
);
394 static int init_fake_wstream(git_odb_stream
**stream_p
, git_odb_backend
*backend
, git_object_size_t size
, git_object_t type
)
396 fake_wstream
*stream
;
399 GIT_ERROR_CHECK_BLOBSIZE(size
);
400 blobsize
= (size_t)size
;
402 stream
= git__calloc(1, sizeof(fake_wstream
));
403 GIT_ERROR_CHECK_ALLOC(stream
);
405 stream
->size
= blobsize
;
407 stream
->buffer
= git__malloc(blobsize
);
408 if (stream
->buffer
== NULL
) {
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
;
420 *stream_p
= (git_odb_stream
*)stream
;
424 /***********************************************************
426 * OBJECT DATABASE PUBLIC API
428 * Public calls for the ODB functionality
430 ***********************************************************/
432 static int backend_sort_cmp(const void *a
, const void *b
)
434 const backend_internal
*backend_a
= (const backend_internal
*)(a
);
435 const backend_internal
*backend_b
= (const backend_internal
*)(b
);
437 if (backend_b
->priority
== backend_a
->priority
) {
438 if (backend_a
->is_alternate
)
440 if (backend_b
->is_alternate
)
444 return (backend_b
->priority
- backend_a
->priority
);
447 int git_odb_new(git_odb
**out
)
449 git_odb
*db
= git__calloc(1, sizeof(*db
));
450 GIT_ERROR_CHECK_ALLOC(db
);
452 if (git_mutex_init(&db
->lock
) < 0) {
456 if (git_cache_init(&db
->own_cache
) < 0) {
457 git_mutex_free(&db
->lock
);
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
);
469 GIT_REFCOUNT_INC(db
);
473 static int add_backend_internal(
474 git_odb
*odb
, git_odb_backend
*backend
,
475 int priority
, bool is_alternate
, ino_t disk_inode
)
477 backend_internal
*internal
;
480 GIT_ASSERT_ARG(backend
);
482 GIT_ERROR_CHECK_VERSION(backend
, GIT_ODB_BACKEND_VERSION
, "git_odb_backend");
484 /* Check if the backend is already owned by another ODB */
485 GIT_ASSERT(!backend
->odb
|| backend
->odb
== odb
);
487 internal
= git__malloc(sizeof(backend_internal
));
488 GIT_ERROR_CHECK_ALLOC(internal
);
490 internal
->backend
= backend
;
491 internal
->priority
= priority
;
492 internal
->is_alternate
= is_alternate
;
493 internal
->disk_inode
= disk_inode
;
495 if (git_mutex_lock(&odb
->lock
) < 0) {
496 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
499 if (git_vector_insert(&odb
->backends
, internal
) < 0) {
500 git_mutex_unlock(&odb
->lock
);
504 git_vector_sort(&odb
->backends
);
505 internal
->backend
->odb
= odb
;
506 git_mutex_unlock(&odb
->lock
);
510 int git_odb_add_backend(git_odb
*odb
, git_odb_backend
*backend
, int priority
)
512 return add_backend_internal(odb
, backend
, priority
, false, 0);
515 int git_odb_add_alternate(git_odb
*odb
, git_odb_backend
*backend
, int priority
)
517 return add_backend_internal(odb
, backend
, priority
, true, 0);
520 size_t git_odb_num_backends(git_odb
*odb
)
527 if (git_mutex_lock(&odb
->lock
) < 0) {
528 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
531 length
= odb
->backends
.length
;
533 git_mutex_unlock(&odb
->lock
);
537 static int git_odb__error_unsupported_in_backend(const char *action
)
539 git_error_set(GIT_ERROR_ODB
,
540 "cannot %s - unsupported in the loaded odb backends", action
);
545 int git_odb_get_backend(git_odb_backend
**out
, git_odb
*odb
, size_t pos
)
547 backend_internal
*internal
;
554 if ((error
= git_mutex_lock(&odb
->lock
)) < 0) {
555 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
558 internal
= git_vector_get(&odb
->backends
, pos
);
560 if (!internal
|| !internal
->backend
) {
561 git_mutex_unlock(&odb
->lock
);
563 git_error_set(GIT_ERROR_ODB
, "no ODB backend loaded at index %" PRIuZ
, pos
);
564 return GIT_ENOTFOUND
;
566 *out
= internal
->backend
;
567 git_mutex_unlock(&odb
->lock
);
572 int git_odb__add_default_backends(
573 git_odb
*db
, const char *objects_dir
,
574 bool as_alternates
, int alternate_depth
)
579 git_odb_backend
*loose
, *packed
;
581 /* TODO: inodes are not really relevant on Win32, so we need to find
582 * a cross-platform workaround for this */
589 if (p_stat(objects_dir
, &st
) < 0) {
591 /* this should warn */
594 git_error_set(GIT_ERROR_ODB
, "failed to load object database in '%s'", objects_dir
);
600 if (git_mutex_lock(&db
->lock
) < 0) {
601 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
);
611 git_mutex_unlock(&db
->lock
);
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)
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)
624 if (git_mutex_lock(&db
->lock
) < 0) {
625 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
628 if (!db
->cgraph
&& git_commit_graph_new(&db
->cgraph
, objects_dir
, false) < 0) {
629 git_mutex_unlock(&db
->lock
);
632 git_mutex_unlock(&db
->lock
);
634 return load_alternates(db
, objects_dir
, alternate_depth
);
637 static int load_alternates(git_odb
*odb
, const char *objects_dir
, int alternate_depth
)
639 git_buf alternates_path
= GIT_BUF_INIT
;
640 git_buf alternates_buf
= GIT_BUF_INIT
;
642 const char *alternate
;
645 /* Git reports an error, we just ignore anything deeper */
646 if (alternate_depth
> GIT_ALTERNATES_MAX_DEPTH
)
649 if (git_buf_joinpath(&alternates_path
, objects_dir
, GIT_ALTERNATES_FILE
) < 0)
652 if (git_path_exists(alternates_path
.ptr
) == false) {
653 git_buf_dispose(&alternates_path
);
657 if (git_futils_readbuffer(&alternates_buf
, alternates_path
.ptr
) < 0) {
658 git_buf_dispose(&alternates_path
);
662 buffer
= (char *)alternates_buf
.ptr
;
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
== '#')
670 * Relative path: build based on the current `objects`
671 * folder. However, relative paths are only allowed in
672 * the current repository.
674 if (*alternate
== '.' && !alternate_depth
) {
675 if ((result
= git_buf_joinpath(&alternates_path
, objects_dir
, alternate
)) < 0)
677 alternate
= git_buf_cstr(&alternates_path
);
680 if ((result
= git_odb__add_default_backends(odb
, alternate
, true, alternate_depth
+ 1)) < 0)
684 git_buf_dispose(&alternates_path
);
685 git_buf_dispose(&alternates_buf
);
690 int git_odb_add_disk_alternate(git_odb
*odb
, const char *path
)
692 return git_odb__add_default_backends(odb
, path
, true, 0);
695 int git_odb_set_commit_graph(git_odb
*odb
, git_commit_graph
*cgraph
)
701 if ((error
= git_mutex_lock(&odb
->lock
)) < 0) {
702 git_error_set(GIT_ERROR_ODB
, "failed to acquire the db lock");
705 git_commit_graph_free(odb
->cgraph
);
706 odb
->cgraph
= cgraph
;
707 git_mutex_unlock(&odb
->lock
);
712 int git_odb_open(git_odb
**out
, const char *objects_dir
)
717 GIT_ASSERT_ARG(objects_dir
);
721 if (git_odb_new(&db
) < 0)
724 if (git_odb__add_default_backends(db
, objects_dir
, 0, 0) < 0) {
733 int git_odb__set_caps(git_odb
*odb
, int caps
)
735 if (caps
== GIT_ODB_CAP_FROM_OWNER
) {
736 git_repository
*repo
= GIT_REFCOUNT_OWNER(odb
);
740 git_error_set(GIT_ERROR_ODB
, "cannot access repository to set odb caps");
744 if (!git_repository__configmap_lookup(&val
, repo
, GIT_CONFIGMAP_FSYNCOBJECTFILES
))
745 odb
->do_fsync
= !!val
;
751 static void odb_free(git_odb
*db
)
756 if (git_mutex_lock(&db
->lock
) < 0) {
757 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
764 backend
->free(backend
);
769 git_mutex_unlock(&db
->lock
);
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
);
776 git__memzero(db
, sizeof(*db
));
780 void git_odb_free(git_odb
*db
)
785 GIT_REFCOUNT_DEC(db
, odb_free
);
788 static int odb_exists_1(
797 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
798 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
805 if (only_refreshed
&& !b
->refresh
)
808 if (b
->exists
!= NULL
)
809 found
= (bool)b
->exists(b
, id
);
811 git_mutex_unlock(&db
->lock
);
816 int git_odb__get_commit_graph_file(git_commit_graph_file
**out
, git_odb
*db
)
819 git_commit_graph_file
*result
= NULL
;
821 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
822 git_error_set(GIT_ERROR_ODB
, "failed to acquire the db lock");
826 error
= GIT_ENOTFOUND
;
829 error
= git_commit_graph_get_file(&result
, db
->cgraph
);
835 git_mutex_unlock(&db
->lock
);
839 static int odb_freshen_1(
848 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
849 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
856 if (only_refreshed
&& !b
->refresh
)
859 if (b
->freshen
!= NULL
)
860 found
= !b
->freshen(b
, id
);
861 else if (b
->exists
!= NULL
)
862 found
= b
->exists(b
, id
);
864 git_mutex_unlock(&db
->lock
);
869 int git_odb__freshen(git_odb
*db
, const git_oid
*id
)
874 if (odb_freshen_1(db
, id
, false))
877 if (!git_odb_refresh(db
))
878 return odb_freshen_1(db
, id
, true);
880 /* Failed to refresh, hence not found */
884 int git_odb_exists(git_odb
*db
, const git_oid
*id
)
886 git_odb_object
*object
;
891 if (git_oid_is_zero(id
))
894 if ((object
= git_cache_get_raw(odb_cache(db
), id
)) != NULL
) {
895 git_odb_object_free(object
);
899 if (odb_exists_1(db
, id
, false))
902 if (!git_odb_refresh(db
))
903 return odb_exists_1(db
, id
, true);
905 /* Failed to refresh, hence not found */
909 static int odb_exists_prefix_1(git_oid
*out
, git_odb
*db
,
910 const git_oid
*key
, size_t len
, bool only_refreshed
)
913 int error
= GIT_ENOTFOUND
, num_found
= 0;
914 git_oid last_found
= {{0}}, found
;
916 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
917 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
925 if (only_refreshed
&& !b
->refresh
)
928 if (!b
->exists_prefix
)
931 error
= b
->exists_prefix(&found
, b
, key
, len
);
932 if (error
== GIT_ENOTFOUND
|| error
== GIT_PASSTHROUGH
)
935 git_mutex_unlock(&db
->lock
);
939 /* make sure found item doesn't introduce ambiguity */
941 if (git_oid__cmp(&last_found
, &found
)) {
942 git_mutex_unlock(&db
->lock
);
943 return git_odb__error_ambiguous("multiple matches for prefix");
946 git_oid_cpy(&last_found
, &found
);
950 git_mutex_unlock(&db
->lock
);
953 return GIT_ENOTFOUND
;
956 git_oid_cpy(out
, &last_found
);
961 int git_odb_exists_prefix(
962 git_oid
*out
, git_odb
*db
, const git_oid
*short_id
, size_t len
)
968 GIT_ASSERT_ARG(short_id
);
970 if (len
< GIT_OID_MINPREFIXLEN
)
971 return git_odb__error_ambiguous("prefix length too short");
973 if (len
>= GIT_OID_HEXSZ
) {
974 if (git_odb_exists(db
, short_id
)) {
976 git_oid_cpy(out
, short_id
);
979 return git_odb__error_notfound(
980 "no match for id prefix", short_id
, len
);
984 git_oid__cpy_prefix(&key
, short_id
, len
);
986 error
= odb_exists_prefix_1(out
, db
, &key
, len
, false);
988 if (error
== GIT_ENOTFOUND
&& !git_odb_refresh(db
))
989 error
= odb_exists_prefix_1(out
, db
, &key
, len
, true);
991 if (error
== GIT_ENOTFOUND
)
992 return git_odb__error_notfound("no match for id prefix", &key
, len
);
997 int git_odb_expand_ids(
999 git_odb_expand_id
*ids
,
1005 GIT_ASSERT_ARG(ids
);
1007 for (i
= 0; i
< count
; i
++) {
1008 git_odb_expand_id
*query
= &ids
[i
];
1009 int error
= GIT_EAMBIGUOUS
;
1012 query
->type
= GIT_OBJECT_ANY
;
1014 /* if we have a short OID, expand it first */
1015 if (query
->length
>= GIT_OID_MINPREFIXLEN
&& query
->length
< GIT_OID_HEXSZ
) {
1018 error
= odb_exists_prefix_1(&actual_id
, db
, &query
->id
, query
->length
, false);
1020 git_oid_cpy(&query
->id
, &actual_id
);
1021 query
->length
= GIT_OID_HEXSZ
;
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.
1029 if (query
->length
>= GIT_OID_HEXSZ
) {
1030 git_object_t actual_type
;
1032 error
= odb_otype_fast(&actual_type
, db
, &query
->id
);
1034 if (query
->type
!= GIT_OBJECT_ANY
&& query
->type
!= actual_type
)
1035 error
= GIT_ENOTFOUND
;
1037 query
->type
= actual_type
;
1042 /* no errors, so we've successfully expanded the OID */
1046 /* the object is missing or ambiguous */
1048 case GIT_EAMBIGUOUS
:
1049 memset(&query
->id
, 0, sizeof(git_oid
));
1054 /* something went very wrong with the ODB; bail hard */
1064 int git_odb_read_header(size_t *len_p
, git_object_t
*type_p
, git_odb
*db
, const git_oid
*id
)
1067 git_odb_object
*object
;
1069 error
= git_odb__read_header_or_object(&object
, len_p
, type_p
, db
, id
);
1072 git_odb_object_free(object
);
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
)
1083 bool passthrough
= false;
1086 if (!only_refreshed
&& (ht
= odb_hardcoded_type(id
)) != GIT_OBJECT_INVALID
) {
1092 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
1093 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
1100 if (only_refreshed
&& !b
->refresh
)
1103 if (!b
->read_header
) {
1108 error
= b
->read_header(len_p
, type_p
, b
, id
);
1111 case GIT_PASSTHROUGH
:
1117 git_mutex_unlock(&db
->lock
);
1121 git_mutex_unlock(&db
->lock
);
1123 return passthrough
? GIT_PASSTHROUGH
: GIT_ENOTFOUND
;
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
)
1130 int error
= GIT_ENOTFOUND
;
1131 git_odb_object
*object
;
1135 GIT_ASSERT_ARG(out
);
1136 GIT_ASSERT_ARG(len_p
);
1137 GIT_ASSERT_ARG(type_p
);
1141 if (git_oid_is_zero(id
))
1142 return error_null_oid(GIT_ENOTFOUND
, "cannot read object");
1144 if ((object
= git_cache_get_raw(odb_cache(db
), id
)) != NULL
) {
1145 *len_p
= object
->cached
.size
;
1146 *type_p
= object
->cached
.type
;
1151 error
= odb_read_header_1(len_p
, type_p
, db
, id
, false);
1153 if (error
== GIT_ENOTFOUND
&& !git_odb_refresh(db
))
1154 error
= odb_read_header_1(len_p
, type_p
, db
, id
, true);
1156 if (error
== GIT_ENOTFOUND
)
1157 return git_odb__error_notfound("cannot read header for", id
, GIT_OID_HEXSZ
);
1159 /* we found the header; return early */
1163 if (error
== GIT_PASSTHROUGH
) {
1165 * no backend has header-reading functionality
1166 * so try using `git_odb_read` instead
1168 error
= git_odb_read(&object
, db
, id
);
1170 *len_p
= object
->cached
.size
;
1171 *type_p
= object
->cached
.type
;
1179 static int odb_read_1(git_odb_object
**out
, git_odb
*db
, const git_oid
*id
,
1180 bool only_refreshed
)
1184 git_odb_object
*object
;
1189 if (!only_refreshed
) {
1190 if ((error
= odb_read_hardcoded(&found
, &raw
, id
)) < 0)
1194 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
1195 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
1202 if (only_refreshed
&& !b
->refresh
)
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
)
1211 git_mutex_unlock(&db
->lock
);
1218 git_mutex_unlock(&db
->lock
);
1221 return GIT_ENOTFOUND
;
1223 if (git_odb__strict_hash_verification
) {
1224 if ((error
= git_odb_hash(&hashed
, raw
.data
, raw
.len
, raw
.type
)) < 0)
1227 if (!git_oid_equal(id
, &hashed
)) {
1228 error
= git_odb__error_mismatch(id
, &hashed
);
1234 if ((object
= odb_object__alloc(id
, &raw
)) == NULL
) {
1239 *out
= git_cache_store_raw(odb_cache(db
), object
);
1243 git__free(raw
.data
);
1247 int git_odb_read(git_odb_object
**out
, git_odb
*db
, const git_oid
*id
)
1251 GIT_ASSERT_ARG(out
);
1255 if (git_oid_is_zero(id
))
1256 return error_null_oid(GIT_ENOTFOUND
, "cannot read object");
1258 *out
= git_cache_get_raw(odb_cache(db
), id
);
1262 error
= odb_read_1(out
, db
, id
, false);
1264 if (error
== GIT_ENOTFOUND
&& !git_odb_refresh(db
))
1265 error
= odb_read_1(out
, db
, id
, true);
1267 if (error
== GIT_ENOTFOUND
)
1268 return git_odb__error_notfound("no match for id", id
, GIT_OID_HEXSZ
);
1273 static int odb_otype_fast(git_object_t
*type_p
, git_odb
*db
, const git_oid
*id
)
1275 git_odb_object
*object
;
1279 if (git_oid_is_zero(id
))
1280 return error_null_oid(GIT_ENOTFOUND
, "cannot get object type");
1282 if ((object
= git_cache_get_raw(odb_cache(db
), id
)) != NULL
) {
1283 *type_p
= object
->cached
.type
;
1284 git_odb_object_free(object
);
1288 error
= odb_read_header_1(&_unused
, type_p
, db
, id
, false);
1290 if (error
== GIT_PASSTHROUGH
) {
1291 error
= odb_read_1(&object
, db
, id
, false);
1293 *type_p
= object
->cached
.type
;
1294 git_odb_object_free(object
);
1300 static int read_prefix_1(git_odb_object
**out
, git_odb
*db
,
1301 const git_oid
*key
, size_t len
, bool only_refreshed
)
1305 git_oid found_full_oid
= {{0}};
1306 git_rawobj raw
= {0};
1309 git_odb_object
*object
;
1311 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
1312 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
1319 if (only_refreshed
&& !b
->refresh
)
1322 if (b
->read_prefix
!= NULL
) {
1324 error
= b
->read_prefix(&full_oid
, &raw
.data
, &raw
.len
, &raw
.type
, b
, key
, len
);
1326 if (error
== GIT_ENOTFOUND
|| error
== GIT_PASSTHROUGH
) {
1332 git_mutex_unlock(&db
->lock
);
1339 if (found
&& git_oid__cmp(&full_oid
, &found_full_oid
)) {
1340 git_buf buf
= GIT_BUF_INIT
;
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
));
1347 error
= git_odb__error_ambiguous(buf
.ptr
);
1348 git_buf_dispose(&buf
);
1349 git_mutex_unlock(&db
->lock
);
1353 found_full_oid
= full_oid
;
1357 git_mutex_unlock(&db
->lock
);
1360 return GIT_ENOTFOUND
;
1362 if (git_odb__strict_hash_verification
) {
1365 if ((error
= git_odb_hash(&hash
, raw
.data
, raw
.len
, raw
.type
)) < 0)
1368 if (!git_oid_equal(&found_full_oid
, &hash
)) {
1369 error
= git_odb__error_mismatch(&found_full_oid
, &hash
);
1374 if ((object
= odb_object__alloc(&found_full_oid
, &raw
)) == NULL
) {
1379 *out
= git_cache_store_raw(odb_cache(db
), object
);
1383 git__free(raw
.data
);
1388 int git_odb_read_prefix(
1389 git_odb_object
**out
, git_odb
*db
, const git_oid
*short_id
, size_t len
)
1391 git_oid key
= {{0}};
1394 GIT_ASSERT_ARG(out
);
1397 if (len
< GIT_OID_MINPREFIXLEN
)
1398 return git_odb__error_ambiguous("prefix length too short");
1400 if (len
> GIT_OID_HEXSZ
)
1401 len
= GIT_OID_HEXSZ
;
1403 if (len
== GIT_OID_HEXSZ
) {
1404 *out
= git_cache_get_raw(odb_cache(db
), short_id
);
1409 git_oid__cpy_prefix(&key
, short_id
, len
);
1411 error
= read_prefix_1(out
, db
, &key
, len
, false);
1413 if (error
== GIT_ENOTFOUND
&& !git_odb_refresh(db
))
1414 error
= read_prefix_1(out
, db
, &key
, len
, true);
1416 if (error
== GIT_ENOTFOUND
)
1417 return git_odb__error_notfound("no match for prefix", &key
, len
);
1422 int git_odb_foreach(git_odb
*db
, git_odb_foreach_cb cb
, void *payload
)
1425 git_vector backends
= GIT_VECTOR_INIT
;
1426 backend_internal
*internal
;
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");
1434 error
= git_vector_dup(&backends
, &db
->backends
, NULL
);
1435 git_mutex_unlock(&db
->lock
);
1440 git_vector_foreach(&backends
, i
, internal
) {
1441 git_odb_backend
*b
= internal
->backend
;
1442 error
= b
->foreach(b
, cb
, payload
);
1448 git_vector_free(&backends
);
1454 git_oid
*oid
, git_odb
*db
, const void *data
, size_t len
, git_object_t type
)
1458 git_odb_stream
*stream
;
1460 GIT_ASSERT_ARG(oid
);
1463 if ((error
= git_odb_hash(oid
, data
, len
, type
)) < 0)
1466 if (git_oid_is_zero(oid
))
1467 return error_null_oid(GIT_EINVALID
, "cannot write object");
1469 if (git_odb__freshen(db
, oid
))
1472 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
1473 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
1480 /* we don't write in alternates! */
1481 if (internal
->is_alternate
)
1484 if (b
->write
!= NULL
)
1485 error
= b
->write(b
, oid
, data
, len
, type
);
1487 git_mutex_unlock(&db
->lock
);
1489 if (!error
|| error
== GIT_PASSTHROUGH
)
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
1496 if ((error
= git_odb_open_wstream(&stream
, db
, len
, type
)) != 0)
1499 stream
->write(stream
, data
, len
);
1500 error
= stream
->finalize_write(stream
, oid
);
1501 git_odb_stream_free(stream
);
1506 static int hash_header(git_hash_ctx
*ctx
, git_object_size_t size
, git_object_t type
)
1512 if ((error
= git_odb__format_object_header(&hdrlen
,
1513 header
, sizeof(header
), size
, type
)) < 0)
1516 return git_hash_update(ctx
, header
, hdrlen
);
1519 int git_odb_open_wstream(
1520 git_odb_stream
**stream
, git_odb
*db
, git_object_size_t size
, git_object_t type
)
1522 size_t i
, writes
= 0;
1523 int error
= GIT_ERROR
;
1524 git_hash_ctx
*ctx
= NULL
;
1526 GIT_ASSERT_ARG(stream
);
1529 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
1530 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
1538 /* we don't write in alternates! */
1539 if (internal
->is_alternate
)
1542 if (b
->writestream
!= NULL
) {
1544 error
= b
->writestream(stream
, b
, size
, type
);
1545 } else if (b
->write
!= NULL
) {
1547 error
= init_fake_wstream(stream
, b
, size
, type
);
1550 git_mutex_unlock(&db
->lock
);
1553 if (error
== GIT_PASSTHROUGH
)
1556 error
= git_odb__error_unsupported_in_backend("write object");
1561 ctx
= git__malloc(sizeof(git_hash_ctx
));
1562 GIT_ERROR_CHECK_ALLOC(ctx
);
1564 if ((error
= git_hash_ctx_init(ctx
)) < 0 ||
1565 (error
= hash_header(ctx
, size
, type
)) < 0)
1568 (*stream
)->hash_ctx
= ctx
;
1569 (*stream
)->declared_size
= size
;
1570 (*stream
)->received_bytes
= 0;
1578 static int git_odb_stream__invalid_length(
1579 const git_odb_stream
*stream
,
1582 git_error_set(GIT_ERROR_ODB
,
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
);
1591 int git_odb_stream_write(git_odb_stream
*stream
, const char *buffer
, size_t len
)
1593 git_hash_update(stream
->hash_ctx
, buffer
, len
);
1595 stream
->received_bytes
+= len
;
1597 if (stream
->received_bytes
> stream
->declared_size
)
1598 return git_odb_stream__invalid_length(stream
,
1601 return stream
->write(stream
, buffer
, len
);
1604 int git_odb_stream_finalize_write(git_oid
*out
, git_odb_stream
*stream
)
1606 if (stream
->received_bytes
!= stream
->declared_size
)
1607 return git_odb_stream__invalid_length(stream
,
1608 "stream_finalize_write()");
1610 git_hash_final(out
, stream
->hash_ctx
);
1612 if (git_odb__freshen(stream
->backend
->odb
, out
))
1615 return stream
->finalize_write(stream
, out
);
1618 int git_odb_stream_read(git_odb_stream
*stream
, char *buffer
, size_t len
)
1620 return stream
->read(stream
, buffer
, len
);
1623 void git_odb_stream_free(git_odb_stream
*stream
)
1628 git_hash_ctx_cleanup(stream
->hash_ctx
);
1629 git__free(stream
->hash_ctx
);
1630 stream
->free(stream
);
1633 int git_odb_open_rstream(
1634 git_odb_stream
**stream
,
1640 size_t i
, reads
= 0;
1641 int error
= GIT_ERROR
;
1643 GIT_ASSERT_ARG(stream
);
1646 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
1647 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
1655 if (b
->readstream
!= NULL
) {
1657 error
= b
->readstream(stream
, len
, type
, b
, oid
);
1660 git_mutex_unlock(&db
->lock
);
1662 if (error
== GIT_PASSTHROUGH
)
1664 if (error
< 0 && !reads
)
1665 error
= git_odb__error_unsupported_in_backend("read object streamed");
1670 int git_odb_write_pack(struct git_odb_writepack
**out
, git_odb
*db
, git_indexer_progress_cb progress_cb
, void *progress_payload
)
1672 size_t i
, writes
= 0;
1673 int error
= GIT_ERROR
;
1675 GIT_ASSERT_ARG(out
);
1678 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
1679 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
1687 /* we don't write in alternates! */
1688 if (internal
->is_alternate
)
1691 if (b
->writepack
!= NULL
) {
1693 error
= b
->writepack(out
, b
, db
, progress_cb
, progress_payload
);
1696 git_mutex_unlock(&db
->lock
);
1698 if (error
== GIT_PASSTHROUGH
)
1700 if (error
< 0 && !writes
)
1701 error
= git_odb__error_unsupported_in_backend("write pack");
1706 int git_odb_write_multi_pack_index(git_odb
*db
)
1708 size_t i
, writes
= 0;
1709 int error
= GIT_ERROR
;
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
;
1717 /* we don't write in alternates! */
1718 if (internal
->is_alternate
)
1721 if (b
->writemidx
!= NULL
) {
1723 error
= b
->writemidx(b
);
1727 if (error
== GIT_PASSTHROUGH
)
1729 if (error
< 0 && !writes
)
1730 error
= git_odb__error_unsupported_in_backend("write multi-pack-index");
1735 void *git_odb_backend_data_alloc(git_odb_backend
*backend
, size_t len
)
1737 GIT_UNUSED(backend
);
1738 return git__malloc(len
);
1741 #ifndef GIT_DEPRECATE_HARD
1742 void *git_odb_backend_malloc(git_odb_backend
*backend
, size_t len
)
1744 return git_odb_backend_data_alloc(backend
, len
);
1748 void git_odb_backend_data_free(git_odb_backend
*backend
, void *data
)
1750 GIT_UNUSED(backend
);
1754 int git_odb_refresh(struct git_odb
*db
)
1761 if ((error
= git_mutex_lock(&db
->lock
)) < 0) {
1762 git_error_set(GIT_ERROR_ODB
, "failed to acquire the odb lock");
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
;
1769 if (b
->refresh
!= NULL
) {
1770 int error
= b
->refresh(b
);
1772 git_mutex_unlock(&db
->lock
);
1778 git_commit_graph_refresh(db
->cgraph
);
1779 git_mutex_unlock(&db
->lock
);
1784 int git_odb__error_mismatch(const git_oid
*expected
, const git_oid
*actual
)
1786 char expected_oid
[GIT_OID_HEXSZ
+ 1], actual_oid
[GIT_OID_HEXSZ
+ 1];
1788 git_oid_tostr(expected_oid
, sizeof(expected_oid
), expected
);
1789 git_oid_tostr(actual_oid
, sizeof(actual_oid
), actual
);
1791 git_error_set(GIT_ERROR_ODB
, "object hash mismatch - expected %s but got %s",
1792 expected_oid
, actual_oid
);
1794 return GIT_EMISMATCH
;
1797 int git_odb__error_notfound(
1798 const char *message
, const git_oid
*oid
, size_t oid_len
)
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
);
1806 git_error_set(GIT_ERROR_ODB
, "object not found - %s", message
);
1808 return GIT_ENOTFOUND
;
1811 static int error_null_oid(int error
, const char *message
)
1813 git_error_set(GIT_ERROR_ODB
, "odb: %s: null OID cannot exist", message
);
1817 int git_odb__error_ambiguous(const char *message
)
1819 git_error_set(GIT_ERROR_ODB
, "ambiguous SHA1 prefix - %s", message
);
1820 return GIT_EAMBIGUOUS
;
1823 int git_odb_init_backend(git_odb_backend
*backend
, unsigned int version
)
1825 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1826 backend
, version
, git_odb_backend
, GIT_ODB_BACKEND_INIT
);