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.
10 #include "git2/object.h"
11 #include "git2/sys/odb_backend.h"
15 #include "delta-apply.h"
17 #include "repository.h"
19 #include "git2/odb_backend.h"
21 #include "git2/oidarray.h"
23 #define GIT_ALTERNATES_FILE "info/alternates"
26 * We work under the assumption that most objects for long-running
27 * operations will be packed
29 #define GIT_LOOSE_PRIORITY 1
30 #define GIT_PACKED_PRIORITY 2
32 #define GIT_ALTERNATES_MAX_DEPTH 5
36 git_odb_backend
*backend
;
42 static git_cache
*odb_cache(git_odb
*odb
)
44 if (odb
->rc
.owner
!= NULL
) {
45 git_repository
*owner
= odb
->rc
.owner
;
46 return &owner
->objects
;
49 return &odb
->own_cache
;
52 static int load_alternates(git_odb
*odb
, const char *objects_dir
, int alternate_depth
);
54 int git_odb__format_object_header(char *hdr
, size_t n
, git_off_t obj_len
, git_otype obj_type
)
56 const char *type_str
= git_object_type2string(obj_type
);
57 int len
= p_snprintf(hdr
, n
, "%s %lld", type_str
, (long long)obj_len
);
58 assert(len
> 0 && len
<= (int)n
);
62 int git_odb__hashobj(git_oid
*id
, git_rawobj
*obj
)
70 if (!git_object_typeisloose(obj
->type
))
73 if (!obj
->data
&& obj
->len
!= 0)
76 hdrlen
= git_odb__format_object_header(header
, sizeof(header
), obj
->len
, obj
->type
);
80 vec
[1].data
= obj
->data
;
81 vec
[1].len
= obj
->len
;
83 git_hash_vec(id
, vec
, 2);
89 static git_odb_object
*odb_object__alloc(const git_oid
*oid
, git_rawobj
*source
)
91 git_odb_object
*object
= git__calloc(1, sizeof(git_odb_object
));
94 git_oid_cpy(&object
->cached
.oid
, oid
);
95 object
->cached
.type
= source
->type
;
96 object
->cached
.size
= source
->len
;
97 object
->buffer
= source
->data
;
103 void git_odb_object__free(void *object
)
105 if (object
!= NULL
) {
106 git__free(((git_odb_object
*)object
)->buffer
);
111 const git_oid
*git_odb_object_id(git_odb_object
*object
)
113 return &object
->cached
.oid
;
116 const void *git_odb_object_data(git_odb_object
*object
)
118 return object
->buffer
;
121 size_t git_odb_object_size(git_odb_object
*object
)
123 return object
->cached
.size
;
126 git_otype
git_odb_object_type(git_odb_object
*object
)
128 return object
->cached
.type
;
131 int git_odb_object_dup(git_odb_object
**dest
, git_odb_object
*source
)
133 git_cached_obj_incref(source
);
138 void git_odb_object_free(git_odb_object
*object
)
143 git_cached_obj_decref(object
);
146 int git_odb__hashfd(git_oid
*out
, git_file fd
, size_t size
, git_otype type
)
149 char hdr
[64], buffer
[FILEIO_BUFSIZE
];
151 ssize_t read_len
= 0;
154 if (!git_object_typeisloose(type
)) {
155 giterr_set(GITERR_INVALID
, "Invalid object type for hash");
159 if ((error
= git_hash_ctx_init(&ctx
)) < 0)
162 hdr_len
= git_odb__format_object_header(hdr
, sizeof(hdr
), size
, type
);
164 if ((error
= git_hash_update(&ctx
, hdr
, hdr_len
)) < 0)
167 while (size
> 0 && (read_len
= p_read(fd
, buffer
, sizeof(buffer
))) > 0) {
168 if ((error
= git_hash_update(&ctx
, buffer
, read_len
)) < 0)
174 /* If p_read returned an error code, the read obviously failed.
175 * If size is not zero, the file was truncated after we originally
176 * stat'd it, so we consider this a read failure too */
177 if (read_len
< 0 || size
> 0) {
178 giterr_set(GITERR_OS
, "Error reading file for hashing");
184 error
= git_hash_final(out
, &ctx
);
187 git_hash_ctx_cleanup(&ctx
);
191 int git_odb__hashfd_filtered(
192 git_oid
*out
, git_file fd
, size_t size
, git_otype type
, git_filter_list
*fl
)
195 git_buf raw
= GIT_BUF_INIT
;
198 return git_odb__hashfd(out
, fd
, size
, type
);
200 /* size of data is used in header, so we have to read the whole file
201 * into memory to apply filters before beginning to calculate the hash
204 if (!(error
= git_futils_readbuffer_fd(&raw
, fd
, size
))) {
205 git_buf post
= GIT_BUF_INIT
;
207 error
= git_filter_list_apply_to_data(&post
, fl
, &raw
);
212 error
= git_odb_hash(out
, post
.ptr
, post
.size
, type
);
220 int git_odb__hashlink(git_oid
*out
, const char *path
)
226 if (git_path_lstat(path
, &st
) < 0)
229 if (!git__is_int(st
.st_size
) || (int)st
.st_size
< 0) {
230 giterr_set(GITERR_FILESYSTEM
, "File size overflow for 32-bit systems");
234 size
= (int)st
.st_size
;
236 if (S_ISLNK(st
.st_mode
)) {
241 GITERR_CHECK_ALLOC_ADD(&alloc_size
, size
, 1);
242 link_data
= git__malloc(alloc_size
);
243 GITERR_CHECK_ALLOC(link_data
);
245 read_len
= p_readlink(path
, link_data
, size
);
246 link_data
[size
] = '\0';
247 if (read_len
!= size
) {
248 giterr_set(GITERR_OS
, "Failed to read symlink data for '%s'", path
);
249 git__free(link_data
);
253 result
= git_odb_hash(out
, link_data
, size
, GIT_OBJ_BLOB
);
254 git__free(link_data
);
256 int fd
= git_futils_open_ro(path
);
259 result
= git_odb__hashfd(out
, fd
, size
, GIT_OBJ_BLOB
);
266 int git_odb_hashfile(git_oid
*out
, const char *path
, git_otype type
)
269 int result
, fd
= git_futils_open_ro(path
);
273 if ((size
= git_futils_filesize(fd
)) < 0 || !git__is_sizet(size
)) {
274 giterr_set(GITERR_OS
, "File size overflow for 32-bit systems");
279 result
= git_odb__hashfd(out
, fd
, (size_t)size
, type
);
284 int git_odb_hash(git_oid
*id
, const void *data
, size_t len
, git_otype type
)
290 raw
.data
= (void *)data
;
294 return git_odb__hashobj(id
, &raw
);
302 git_odb_stream stream
;
304 size_t size
, written
;
308 static int fake_wstream__fwrite(git_odb_stream
*_stream
, const git_oid
*oid
)
310 fake_wstream
*stream
= (fake_wstream
*)_stream
;
311 return _stream
->backend
->write(_stream
->backend
, oid
, stream
->buffer
, stream
->size
, stream
->type
);
314 static int fake_wstream__write(git_odb_stream
*_stream
, const char *data
, size_t len
)
316 fake_wstream
*stream
= (fake_wstream
*)_stream
;
318 if (stream
->written
+ len
> stream
->size
)
321 memcpy(stream
->buffer
+ stream
->written
, data
, len
);
322 stream
->written
+= len
;
326 static void fake_wstream__free(git_odb_stream
*_stream
)
328 fake_wstream
*stream
= (fake_wstream
*)_stream
;
330 git__free(stream
->buffer
);
334 static int init_fake_wstream(git_odb_stream
**stream_p
, git_odb_backend
*backend
, git_off_t size
, git_otype type
)
336 fake_wstream
*stream
;
338 if (!git__is_ssizet(size
)) {
339 giterr_set(GITERR_ODB
, "object size too large to keep in memory");
343 stream
= git__calloc(1, sizeof(fake_wstream
));
344 GITERR_CHECK_ALLOC(stream
);
348 stream
->buffer
= git__malloc(size
);
349 if (stream
->buffer
== NULL
) {
354 stream
->stream
.backend
= backend
;
355 stream
->stream
.read
= NULL
; /* read only */
356 stream
->stream
.write
= &fake_wstream__write
;
357 stream
->stream
.finalize_write
= &fake_wstream__fwrite
;
358 stream
->stream
.free
= &fake_wstream__free
;
359 stream
->stream
.mode
= GIT_STREAM_WRONLY
;
361 *stream_p
= (git_odb_stream
*)stream
;
365 /***********************************************************
367 * OBJECT DATABASE PUBLIC API
369 * Public calls for the ODB functionality
371 ***********************************************************/
373 static int backend_sort_cmp(const void *a
, const void *b
)
375 const backend_internal
*backend_a
= (const backend_internal
*)(a
);
376 const backend_internal
*backend_b
= (const backend_internal
*)(b
);
378 if (backend_b
->priority
== backend_a
->priority
) {
379 if (backend_a
->is_alternate
)
381 if (backend_b
->is_alternate
)
385 return (backend_b
->priority
- backend_a
->priority
);
388 int git_odb_new(git_odb
**out
)
390 git_odb
*db
= git__calloc(1, sizeof(*db
));
391 GITERR_CHECK_ALLOC(db
);
393 if (git_cache_init(&db
->own_cache
) < 0 ||
394 git_vector_init(&db
->backends
, 4, backend_sort_cmp
) < 0) {
400 GIT_REFCOUNT_INC(db
);
404 static int add_backend_internal(
405 git_odb
*odb
, git_odb_backend
*backend
,
406 int priority
, bool is_alternate
, ino_t disk_inode
)
408 backend_internal
*internal
;
410 assert(odb
&& backend
);
412 GITERR_CHECK_VERSION(backend
, GIT_ODB_BACKEND_VERSION
, "git_odb_backend");
414 /* Check if the backend is already owned by another ODB */
415 assert(!backend
->odb
|| backend
->odb
== odb
);
417 internal
= git__malloc(sizeof(backend_internal
));
418 GITERR_CHECK_ALLOC(internal
);
420 internal
->backend
= backend
;
421 internal
->priority
= priority
;
422 internal
->is_alternate
= is_alternate
;
423 internal
->disk_inode
= disk_inode
;
425 if (git_vector_insert(&odb
->backends
, internal
) < 0) {
430 git_vector_sort(&odb
->backends
);
431 internal
->backend
->odb
= odb
;
435 int git_odb_add_backend(git_odb
*odb
, git_odb_backend
*backend
, int priority
)
437 return add_backend_internal(odb
, backend
, priority
, false, 0);
440 int git_odb_add_alternate(git_odb
*odb
, git_odb_backend
*backend
, int priority
)
442 return add_backend_internal(odb
, backend
, priority
, true, 0);
445 size_t git_odb_num_backends(git_odb
*odb
)
448 return odb
->backends
.length
;
451 static int git_odb__error_unsupported_in_backend(const char *action
)
453 giterr_set(GITERR_ODB
,
454 "Cannot %s - unsupported in the loaded odb backends", action
);
459 int git_odb_get_backend(git_odb_backend
**out
, git_odb
*odb
, size_t pos
)
461 backend_internal
*internal
;
464 internal
= git_vector_get(&odb
->backends
, pos
);
466 if (internal
&& internal
->backend
) {
467 *out
= internal
->backend
;
471 giterr_set(GITERR_ODB
, "No ODB backend loaded at index %" PRIuZ
, pos
);
472 return GIT_ENOTFOUND
;
475 static int add_default_backends(
476 git_odb
*db
, const char *objects_dir
,
477 bool as_alternates
, int alternate_depth
)
482 git_odb_backend
*loose
, *packed
;
484 /* TODO: inodes are not really relevant on Win32, so we need to find
485 * a cross-platform workaround for this */
492 if (p_stat(objects_dir
, &st
) < 0) {
496 giterr_set(GITERR_ODB
, "Failed to load object database in '%s'", objects_dir
);
502 for (i
= 0; i
< db
->backends
.length
; ++i
) {
503 backend_internal
*backend
= git_vector_get(&db
->backends
, i
);
504 if (backend
->disk_inode
== inode
)
509 /* add the loose object backend */
510 if (git_odb_backend_loose(&loose
, objects_dir
, -1, 0, 0, 0) < 0 ||
511 add_backend_internal(db
, loose
, GIT_LOOSE_PRIORITY
, as_alternates
, inode
) < 0)
514 /* add the packed file backend */
515 if (git_odb_backend_pack(&packed
, objects_dir
) < 0 ||
516 add_backend_internal(db
, packed
, GIT_PACKED_PRIORITY
, as_alternates
, inode
) < 0)
519 return load_alternates(db
, objects_dir
, alternate_depth
);
522 static int load_alternates(git_odb
*odb
, const char *objects_dir
, int alternate_depth
)
524 git_buf alternates_path
= GIT_BUF_INIT
;
525 git_buf alternates_buf
= GIT_BUF_INIT
;
527 const char *alternate
;
530 /* Git reports an error, we just ignore anything deeper */
531 if (alternate_depth
> GIT_ALTERNATES_MAX_DEPTH
)
534 if (git_buf_joinpath(&alternates_path
, objects_dir
, GIT_ALTERNATES_FILE
) < 0)
537 if (git_path_exists(alternates_path
.ptr
) == false) {
538 git_buf_free(&alternates_path
);
542 if (git_futils_readbuffer(&alternates_buf
, alternates_path
.ptr
) < 0) {
543 git_buf_free(&alternates_path
);
547 buffer
= (char *)alternates_buf
.ptr
;
549 /* add each alternate as a new backend; one alternate per line */
550 while ((alternate
= git__strtok(&buffer
, "\r\n")) != NULL
) {
551 if (*alternate
== '\0' || *alternate
== '#')
555 * Relative path: build based on the current `objects`
556 * folder. However, relative paths are only allowed in
557 * the current repository.
559 if (*alternate
== '.' && !alternate_depth
) {
560 if ((result
= git_buf_joinpath(&alternates_path
, objects_dir
, alternate
)) < 0)
562 alternate
= git_buf_cstr(&alternates_path
);
565 if ((result
= add_default_backends(odb
, alternate
, true, alternate_depth
+ 1)) < 0)
569 git_buf_free(&alternates_path
);
570 git_buf_free(&alternates_buf
);
575 int git_odb_add_disk_alternate(git_odb
*odb
, const char *path
)
577 return add_default_backends(odb
, path
, true, 0);
580 int git_odb_open(git_odb
**out
, const char *objects_dir
)
584 assert(out
&& objects_dir
);
588 if (git_odb_new(&db
) < 0)
591 if (add_default_backends(db
, objects_dir
, 0, 0) < 0) {
600 static void odb_free(git_odb
*db
)
604 for (i
= 0; i
< db
->backends
.length
; ++i
) {
605 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
606 git_odb_backend
*backend
= internal
->backend
;
608 backend
->free(backend
);
613 git_vector_free(&db
->backends
);
614 git_cache_free(&db
->own_cache
);
616 git__memzero(db
, sizeof(*db
));
620 void git_odb_free(git_odb
*db
)
625 GIT_REFCOUNT_DEC(db
, odb_free
);
628 static int odb_exists_1(git_odb
*db
, const git_oid
*id
, bool only_refreshed
)
633 for (i
= 0; i
< db
->backends
.length
&& !found
; ++i
) {
634 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
635 git_odb_backend
*b
= internal
->backend
;
637 if (only_refreshed
&& !b
->refresh
)
640 if (b
->exists
!= NULL
)
641 found
= (bool)b
->exists(b
, id
);
647 int git_odb_exists(git_odb
*db
, const git_oid
*id
)
649 git_odb_object
*object
;
653 if ((object
= git_cache_get_raw(odb_cache(db
), id
)) != NULL
) {
654 git_odb_object_free(object
);
658 if (odb_exists_1(db
, id
, false))
661 if (!git_odb_refresh(db
))
662 return odb_exists_1(db
, id
, true);
664 /* Failed to refresh, hence not found */
668 static int odb_exists_prefix_1(git_oid
*out
, git_odb
*db
,
669 const git_oid
*key
, size_t len
, bool only_refreshed
)
672 int error
= GIT_ENOTFOUND
, num_found
= 0;
673 git_oid last_found
= {{0}}, found
;
675 for (i
= 0; i
< db
->backends
.length
; ++i
) {
676 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
677 git_odb_backend
*b
= internal
->backend
;
679 if (only_refreshed
&& !b
->refresh
)
682 if (!b
->exists_prefix
)
685 error
= b
->exists_prefix(&found
, b
, key
, len
);
686 if (error
== GIT_ENOTFOUND
|| error
== GIT_PASSTHROUGH
)
691 /* make sure found item doesn't introduce ambiguity */
693 if (git_oid__cmp(&last_found
, &found
))
694 return git_odb__error_ambiguous("multiple matches for prefix");
696 git_oid_cpy(&last_found
, &found
);
702 return GIT_ENOTFOUND
;
705 git_oid_cpy(out
, &last_found
);
710 int git_odb_exists_prefix(
711 git_oid
*out
, git_odb
*db
, const git_oid
*short_id
, size_t len
)
716 assert(db
&& short_id
);
718 if (len
< GIT_OID_MINPREFIXLEN
)
719 return git_odb__error_ambiguous("prefix length too short");
721 if (len
>= GIT_OID_HEXSZ
) {
722 if (git_odb_exists(db
, short_id
)) {
724 git_oid_cpy(out
, short_id
);
727 return git_odb__error_notfound(
728 "no match for id prefix", short_id
, len
);
732 git_oid__cpy_prefix(&key
, short_id
, len
);
734 error
= odb_exists_prefix_1(out
, db
, &key
, len
, false);
736 if (error
== GIT_ENOTFOUND
&& !git_odb_refresh(db
))
737 error
= odb_exists_prefix_1(out
, db
, &key
, len
, true);
739 if (error
== GIT_ENOTFOUND
)
740 return git_odb__error_notfound("no match for id prefix", &key
, len
);
745 int git_odb_expand_ids(
755 assert(db
&& ids
&& id_lengths
);
757 for (i
= 0; i
< cnt
; i
++) {
758 git_oid
*actual_id
= NULL
, tmp
;
759 git_otype actual_type
= 0;
761 /* if we were given a full object ID, simply look it up */
762 if (id_lengths
[i
] >= GIT_OID_HEXSZ
) {
763 error
= git_odb_read_header(&len
, &actual_type
, db
, &ids
[i
]);
766 /* otherwise, resolve the short id to full, then (optionally)
769 else if (id_lengths
[i
] >= GIT_OID_MINPREFIXLEN
) {
770 error
= odb_exists_prefix_1(&tmp
,
771 db
, &ids
[i
], id_lengths
[i
], false);
777 error
= git_odb_read_header(&len
, &actual_type
, db
, &tmp
);
779 actual_type
= GIT_OBJ_ANY
;
783 if (error
< 0 && error
!= GIT_ENOTFOUND
&& error
!= GIT_EAMBIGUOUS
)
788 if (types
&& types
[i
] != GIT_OBJ_ANY
&& types
[i
] != actual_type
)
792 memset(&ids
[i
], 0, sizeof(git_oid
));
799 git_oid_cpy(&ids
[i
], actual_id
);
801 id_lengths
[i
] = GIT_OID_HEXSZ
;
804 types
[i
] = actual_type
;
814 int git_odb_read_header(size_t *len_p
, git_otype
*type_p
, git_odb
*db
, const git_oid
*id
)
817 git_odb_object
*object
;
819 error
= git_odb__read_header_or_object(&object
, len_p
, type_p
, db
, id
);
822 git_odb_object_free(object
);
827 int git_odb__read_header_or_object(
828 git_odb_object
**out
, size_t *len_p
, git_otype
*type_p
,
829 git_odb
*db
, const git_oid
*id
)
832 int error
= GIT_ENOTFOUND
;
833 git_odb_object
*object
;
835 assert(db
&& id
&& out
&& len_p
&& type_p
);
837 if ((object
= git_cache_get_raw(odb_cache(db
), id
)) != NULL
) {
838 *len_p
= object
->cached
.size
;
839 *type_p
= object
->cached
.type
;
846 for (i
= 0; i
< db
->backends
.length
&& error
< 0; ++i
) {
847 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
848 git_odb_backend
*b
= internal
->backend
;
850 if (b
->read_header
!= NULL
)
851 error
= b
->read_header(len_p
, type_p
, b
, id
);
854 if (!error
|| error
== GIT_PASSTHROUGH
)
858 * no backend could read only the header.
859 * try reading the whole object and freeing the contents
861 if ((error
= git_odb_read(&object
, db
, id
)) < 0)
862 return error
; /* error already set - pass along */
864 *len_p
= object
->cached
.size
;
865 *type_p
= object
->cached
.type
;
871 static git_oid empty_blob
= {{ 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, 0xd6, 0x43, 0x4b, 0x8b,
872 0x29, 0xae, 0x77, 0x5a, 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91 }};
873 static git_oid empty_tree
= {{ 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
874 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04 }};
876 static int hardcoded_objects(git_rawobj
*raw
, const git_oid
*id
)
878 if (!git_oid_cmp(id
, &empty_blob
)) {
879 raw
->type
= GIT_OBJ_BLOB
;
881 raw
->data
= git__calloc(1, sizeof(uint8_t));
883 } else if (!git_oid_cmp(id
, &empty_tree
)) {
884 raw
->type
= GIT_OBJ_TREE
;
886 raw
->data
= git__calloc(1, sizeof(uint8_t));
889 return GIT_ENOTFOUND
;
893 static int odb_read_1(git_odb_object
**out
, git_odb
*db
, const git_oid
*id
,
898 git_odb_object
*object
;
901 if (!hardcoded_objects(&raw
, id
))
904 for (i
= 0; i
< db
->backends
.length
&& !found
; ++i
) {
905 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
906 git_odb_backend
*b
= internal
->backend
;
908 if (only_refreshed
&& !b
->refresh
)
911 if (b
->read
!= NULL
) {
912 int error
= b
->read(&raw
.data
, &raw
.len
, &raw
.type
, b
, id
);
913 if (error
== GIT_PASSTHROUGH
|| error
== GIT_ENOTFOUND
)
924 return GIT_ENOTFOUND
;
927 if ((object
= odb_object__alloc(id
, &raw
)) == NULL
)
930 *out
= git_cache_store_raw(odb_cache(db
), object
);
934 int git_odb_read(git_odb_object
**out
, git_odb
*db
, const git_oid
*id
)
938 assert(out
&& db
&& id
);
940 *out
= git_cache_get_raw(odb_cache(db
), id
);
944 error
= odb_read_1(out
, db
, id
, false);
946 if (error
== GIT_ENOTFOUND
&& !git_odb_refresh(db
))
947 error
= odb_read_1(out
, db
, id
, true);
949 if (error
== GIT_ENOTFOUND
)
950 return git_odb__error_notfound("no match for id", id
, GIT_OID_HEXSZ
);
955 static int read_prefix_1(git_odb_object
**out
, git_odb
*db
,
956 const git_oid
*key
, size_t len
, bool only_refreshed
)
959 int error
= GIT_ENOTFOUND
;
960 git_oid found_full_oid
= {{0}};
964 git_odb_object
*object
;
966 for (i
= 0; i
< db
->backends
.length
; ++i
) {
967 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
968 git_odb_backend
*b
= internal
->backend
;
970 if (only_refreshed
&& !b
->refresh
)
973 if (b
->read_prefix
!= NULL
) {
975 error
= b
->read_prefix(&full_oid
, &raw
.data
, &raw
.len
, &raw
.type
, b
, key
, len
);
976 if (error
== GIT_ENOTFOUND
|| error
== GIT_PASSTHROUGH
)
985 if (found
&& git_oid__cmp(&full_oid
, &found_full_oid
)) {
987 return git_odb__error_ambiguous("multiple matches for prefix");
990 found_full_oid
= full_oid
;
996 return GIT_ENOTFOUND
;
998 if ((object
= odb_object__alloc(&found_full_oid
, &raw
)) == NULL
)
1001 *out
= git_cache_store_raw(odb_cache(db
), object
);
1005 int git_odb_read_prefix(
1006 git_odb_object
**out
, git_odb
*db
, const git_oid
*short_id
, size_t len
)
1008 git_oid key
= {{0}};
1013 if (len
< GIT_OID_MINPREFIXLEN
)
1014 return git_odb__error_ambiguous("prefix length too short");
1016 if (len
> GIT_OID_HEXSZ
)
1017 len
= GIT_OID_HEXSZ
;
1019 if (len
== GIT_OID_HEXSZ
) {
1020 *out
= git_cache_get_raw(odb_cache(db
), short_id
);
1025 git_oid__cpy_prefix(&key
, short_id
, len
);
1027 error
= read_prefix_1(out
, db
, &key
, len
, false);
1029 if (error
== GIT_ENOTFOUND
&& !git_odb_refresh(db
))
1030 error
= read_prefix_1(out
, db
, &key
, len
, true);
1032 if (error
== GIT_ENOTFOUND
)
1033 return git_odb__error_notfound("no match for prefix", &key
, len
);
1038 int git_odb_foreach(git_odb
*db
, git_odb_foreach_cb cb
, void *payload
)
1041 backend_internal
*internal
;
1043 git_vector_foreach(&db
->backends
, i
, internal
) {
1044 git_odb_backend
*b
= internal
->backend
;
1045 int error
= b
->foreach(b
, cb
, payload
);
1054 git_oid
*oid
, git_odb
*db
, const void *data
, size_t len
, git_otype type
)
1057 int error
= GIT_ERROR
;
1058 git_odb_stream
*stream
;
1062 git_odb_hash(oid
, data
, len
, type
);
1063 if (git_odb_exists(db
, oid
))
1066 for (i
= 0; i
< db
->backends
.length
&& error
< 0; ++i
) {
1067 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
1068 git_odb_backend
*b
= internal
->backend
;
1070 /* we don't write in alternates! */
1071 if (internal
->is_alternate
)
1074 if (b
->write
!= NULL
)
1075 error
= b
->write(b
, oid
, data
, len
, type
);
1078 if (!error
|| error
== GIT_PASSTHROUGH
)
1081 /* if no backends were able to write the object directly, we try a
1082 * streaming write to the backends; just write the whole object into the
1083 * stream in one push
1085 if ((error
= git_odb_open_wstream(&stream
, db
, len
, type
)) != 0)
1088 stream
->write(stream
, data
, len
);
1089 error
= stream
->finalize_write(stream
, oid
);
1090 git_odb_stream_free(stream
);
1095 static void hash_header(git_hash_ctx
*ctx
, git_off_t size
, git_otype type
)
1100 hdrlen
= git_odb__format_object_header(header
, sizeof(header
), size
, type
);
1101 git_hash_update(ctx
, header
, hdrlen
);
1104 int git_odb_open_wstream(
1105 git_odb_stream
**stream
, git_odb
*db
, git_off_t size
, git_otype type
)
1107 size_t i
, writes
= 0;
1108 int error
= GIT_ERROR
;
1109 git_hash_ctx
*ctx
= NULL
;
1111 assert(stream
&& db
);
1113 for (i
= 0; i
< db
->backends
.length
&& error
< 0; ++i
) {
1114 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
1115 git_odb_backend
*b
= internal
->backend
;
1117 /* we don't write in alternates! */
1118 if (internal
->is_alternate
)
1121 if (b
->writestream
!= NULL
) {
1123 error
= b
->writestream(stream
, b
, size
, type
);
1124 } else if (b
->write
!= NULL
) {
1126 error
= init_fake_wstream(stream
, b
, size
, type
);
1131 if (error
== GIT_PASSTHROUGH
)
1134 error
= git_odb__error_unsupported_in_backend("write object");
1139 ctx
= git__malloc(sizeof(git_hash_ctx
));
1140 GITERR_CHECK_ALLOC(ctx
);
1142 if ((error
= git_hash_ctx_init(ctx
)) < 0)
1145 hash_header(ctx
, size
, type
);
1146 (*stream
)->hash_ctx
= ctx
;
1148 (*stream
)->declared_size
= size
;
1149 (*stream
)->received_bytes
= 0;
1155 static int git_odb_stream__invalid_length(
1156 const git_odb_stream
*stream
,
1159 giterr_set(GITERR_ODB
,
1161 "Invalid length. %"PRIuZ
" was expected. The "
1162 "total size of the received chunks amounts to %"PRIuZ
".",
1163 action
, stream
->declared_size
, stream
->received_bytes
);
1168 int git_odb_stream_write(git_odb_stream
*stream
, const char *buffer
, size_t len
)
1170 git_hash_update(stream
->hash_ctx
, buffer
, len
);
1172 stream
->received_bytes
+= len
;
1174 if (stream
->received_bytes
> stream
->declared_size
)
1175 return git_odb_stream__invalid_length(stream
,
1178 return stream
->write(stream
, buffer
, len
);
1181 int git_odb_stream_finalize_write(git_oid
*out
, git_odb_stream
*stream
)
1183 if (stream
->received_bytes
!= stream
->declared_size
)
1184 return git_odb_stream__invalid_length(stream
,
1185 "stream_finalize_write()");
1187 git_hash_final(out
, stream
->hash_ctx
);
1189 if (git_odb_exists(stream
->backend
->odb
, out
))
1192 return stream
->finalize_write(stream
, out
);
1195 int git_odb_stream_read(git_odb_stream
*stream
, char *buffer
, size_t len
)
1197 return stream
->read(stream
, buffer
, len
);
1200 void git_odb_stream_free(git_odb_stream
*stream
)
1205 git_hash_ctx_cleanup(stream
->hash_ctx
);
1206 git__free(stream
->hash_ctx
);
1207 stream
->free(stream
);
1210 int git_odb_open_rstream(git_odb_stream
**stream
, git_odb
*db
, const git_oid
*oid
)
1212 size_t i
, reads
= 0;
1213 int error
= GIT_ERROR
;
1215 assert(stream
&& db
);
1217 for (i
= 0; i
< db
->backends
.length
&& error
< 0; ++i
) {
1218 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
1219 git_odb_backend
*b
= internal
->backend
;
1221 if (b
->readstream
!= NULL
) {
1223 error
= b
->readstream(stream
, b
, oid
);
1227 if (error
== GIT_PASSTHROUGH
)
1229 if (error
< 0 && !reads
)
1230 error
= git_odb__error_unsupported_in_backend("read object streamed");
1235 int git_odb_write_pack(struct git_odb_writepack
**out
, git_odb
*db
, git_transfer_progress_cb progress_cb
, void *progress_payload
)
1237 size_t i
, writes
= 0;
1238 int error
= GIT_ERROR
;
1242 for (i
= 0; i
< db
->backends
.length
&& error
< 0; ++i
) {
1243 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
1244 git_odb_backend
*b
= internal
->backend
;
1246 /* we don't write in alternates! */
1247 if (internal
->is_alternate
)
1250 if (b
->writepack
!= NULL
) {
1252 error
= b
->writepack(out
, b
, db
, progress_cb
, progress_payload
);
1256 if (error
== GIT_PASSTHROUGH
)
1258 if (error
< 0 && !writes
)
1259 error
= git_odb__error_unsupported_in_backend("write pack");
1264 void *git_odb_backend_malloc(git_odb_backend
*backend
, size_t len
)
1266 GIT_UNUSED(backend
);
1267 return git__malloc(len
);
1270 int git_odb_refresh(struct git_odb
*db
)
1275 for (i
= 0; i
< db
->backends
.length
; ++i
) {
1276 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
1277 git_odb_backend
*b
= internal
->backend
;
1279 if (b
->refresh
!= NULL
) {
1280 int error
= b
->refresh(b
);
1289 int git_odb__error_notfound(
1290 const char *message
, const git_oid
*oid
, size_t oid_len
)
1293 char oid_str
[GIT_OID_HEXSZ
+ 1];
1294 git_oid_tostr(oid_str
, oid_len
, oid
);
1295 giterr_set(GITERR_ODB
, "Object not found - %s (%.*s)",
1296 message
, oid_len
, oid_str
);
1298 giterr_set(GITERR_ODB
, "Object not found - %s", message
);
1300 return GIT_ENOTFOUND
;
1303 int git_odb__error_ambiguous(const char *message
)
1305 giterr_set(GITERR_ODB
, "Ambiguous SHA1 prefix - %s", message
);
1306 return GIT_EAMBIGUOUS
;
1309 int git_odb_init_backend(git_odb_backend
*backend
, unsigned int version
)
1311 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1312 backend
, version
, git_odb_backend
, GIT_ODB_BACKEND_INIT
);