2 * Copyright (C) 2009-2012 the libgit2 contributors
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"
14 #include "delta-apply.h"
17 #include "git2/odb_backend.h"
20 #define GIT_ALTERNATES_FILE "info/alternates"
22 /* TODO: is this correct? */
23 #define GIT_LOOSE_PRIORITY 2
24 #define GIT_PACKED_PRIORITY 1
26 #define GIT_ALTERNATES_MAX_DEPTH 5
30 git_odb_backend
*backend
;
35 static int load_alternates(git_odb
*odb
, const char *objects_dir
, int alternate_depth
);
37 int git_odb__format_object_header(char *hdr
, size_t n
, size_t obj_len
, git_otype obj_type
)
39 const char *type_str
= git_object_type2string(obj_type
);
40 int len
= p_snprintf(hdr
, n
, "%s %"PRIuZ
, type_str
, obj_len
);
41 assert(len
> 0 && len
<= (int)n
);
45 int git_odb__hashobj(git_oid
*id
, git_rawobj
*obj
)
53 if (!git_object_typeisloose(obj
->type
))
55 if (!obj
->data
&& obj
->len
!= 0)
58 hdrlen
= git_odb__format_object_header(header
, sizeof(header
), obj
->len
, obj
->type
);
62 vec
[1].data
= obj
->data
;
63 vec
[1].len
= obj
->len
;
65 git_hash_vec(id
, vec
, 2);
71 static git_odb_object
*new_odb_object(const git_oid
*oid
, git_rawobj
*source
)
73 git_odb_object
*object
= git__malloc(sizeof(git_odb_object
));
74 memset(object
, 0x0, sizeof(git_odb_object
));
76 git_oid_cpy(&object
->cached
.oid
, oid
);
77 memcpy(&object
->raw
, source
, sizeof(git_rawobj
));
82 static void free_odb_object(void *o
)
84 git_odb_object
*object
= (git_odb_object
*)o
;
87 git__free(object
->raw
.data
);
92 const git_oid
*git_odb_object_id(git_odb_object
*object
)
94 return &object
->cached
.oid
;
97 const void *git_odb_object_data(git_odb_object
*object
)
99 return object
->raw
.data
;
102 size_t git_odb_object_size(git_odb_object
*object
)
104 return object
->raw
.len
;
107 git_otype
git_odb_object_type(git_odb_object
*object
)
109 return object
->raw
.type
;
112 void git_odb_object_free(git_odb_object
*object
)
117 git_cached_obj_decref((git_cached_obj
*)object
, &free_odb_object
);
120 int git_odb__hashfd(git_oid
*out
, git_file fd
, size_t size
, git_otype type
)
123 char hdr
[64], buffer
[2048];
125 ssize_t read_len
= 0;
128 if (!git_object_typeisloose(type
)) {
129 giterr_set(GITERR_INVALID
, "Invalid object type for hash");
133 if ((error
= git_hash_ctx_init(&ctx
)) < 0)
136 hdr_len
= git_odb__format_object_header(hdr
, sizeof(hdr
), size
, type
);
138 if ((error
= git_hash_update(&ctx
, hdr
, hdr_len
)) < 0)
141 while (size
> 0 && (read_len
= p_read(fd
, buffer
, sizeof(buffer
))) > 0) {
142 if ((error
= git_hash_update(&ctx
, buffer
, read_len
)) < 0)
148 /* If p_read returned an error code, the read obviously failed.
149 * If size is not zero, the file was truncated after we originally
150 * stat'd it, so we consider this a read failure too */
151 if (read_len
< 0 || size
> 0) {
152 giterr_set(GITERR_OS
, "Error reading file for hashing");
159 error
= git_hash_final(out
, &ctx
);
162 git_hash_ctx_cleanup(&ctx
);
166 int git_odb__hashfd_filtered(
167 git_oid
*out
, git_file fd
, size_t size
, git_otype type
, git_vector
*filters
)
170 git_buf raw
= GIT_BUF_INIT
;
171 git_buf filtered
= GIT_BUF_INIT
;
173 if (!filters
|| !filters
->length
)
174 return git_odb__hashfd(out
, fd
, size
, type
);
176 /* size of data is used in header, so we have to read the whole file
177 * into memory to apply filters before beginning to calculate the hash
180 if (!(error
= git_futils_readbuffer_fd(&raw
, fd
, size
)))
181 error
= git_filters_apply(&filtered
, &raw
, filters
);
186 error
= git_odb_hash(out
, filtered
.ptr
, filtered
.size
, type
);
188 git_buf_free(&filtered
);
193 int git_odb__hashlink(git_oid
*out
, const char *path
)
199 if (git_path_lstat(path
, &st
) < 0)
204 if (!git__is_sizet(size
)) {
205 giterr_set(GITERR_OS
, "File size overflow for 32-bit systems");
209 if (S_ISLNK(st
.st_mode
)) {
213 link_data
= git__malloc((size_t)(size
+ 1));
214 GITERR_CHECK_ALLOC(link_data
);
216 read_len
= p_readlink(path
, link_data
, (size_t)size
);
217 link_data
[size
] = '\0';
218 if (read_len
!= (ssize_t
)size
) {
219 giterr_set(GITERR_OS
, "Failed to read symlink data for '%s'", path
);
223 result
= git_odb_hash(out
, link_data
, (size_t)size
, GIT_OBJ_BLOB
);
224 git__free(link_data
);
226 int fd
= git_futils_open_ro(path
);
229 result
= git_odb__hashfd(out
, fd
, (size_t)size
, GIT_OBJ_BLOB
);
236 int git_odb_hashfile(git_oid
*out
, const char *path
, git_otype type
)
239 int result
, fd
= git_futils_open_ro(path
);
243 if ((size
= git_futils_filesize(fd
)) < 0 || !git__is_sizet(size
)) {
244 giterr_set(GITERR_OS
, "File size overflow for 32-bit systems");
249 result
= git_odb__hashfd(out
, fd
, (size_t)size
, type
);
254 int git_odb_hash(git_oid
*id
, const void *data
, size_t len
, git_otype type
)
260 raw
.data
= (void *)data
;
264 return git_odb__hashobj(id
, &raw
);
272 git_odb_stream stream
;
274 size_t size
, written
;
278 static int fake_wstream__fwrite(git_oid
*oid
, git_odb_stream
*_stream
)
280 fake_wstream
*stream
= (fake_wstream
*)_stream
;
281 return _stream
->backend
->write(oid
, _stream
->backend
, stream
->buffer
, stream
->size
, stream
->type
);
284 static int fake_wstream__write(git_odb_stream
*_stream
, const char *data
, size_t len
)
286 fake_wstream
*stream
= (fake_wstream
*)_stream
;
288 if (stream
->written
+ len
> stream
->size
)
291 memcpy(stream
->buffer
+ stream
->written
, data
, len
);
292 stream
->written
+= len
;
296 static void fake_wstream__free(git_odb_stream
*_stream
)
298 fake_wstream
*stream
= (fake_wstream
*)_stream
;
300 git__free(stream
->buffer
);
304 static int init_fake_wstream(git_odb_stream
**stream_p
, git_odb_backend
*backend
, size_t size
, git_otype type
)
306 fake_wstream
*stream
;
308 stream
= git__calloc(1, sizeof(fake_wstream
));
309 GITERR_CHECK_ALLOC(stream
);
313 stream
->buffer
= git__malloc(size
);
314 if (stream
->buffer
== NULL
) {
319 stream
->stream
.backend
= backend
;
320 stream
->stream
.read
= NULL
; /* read only */
321 stream
->stream
.write
= &fake_wstream__write
;
322 stream
->stream
.finalize_write
= &fake_wstream__fwrite
;
323 stream
->stream
.free
= &fake_wstream__free
;
324 stream
->stream
.mode
= GIT_STREAM_WRONLY
;
326 *stream_p
= (git_odb_stream
*)stream
;
330 /***********************************************************
332 * OBJECT DATABASE PUBLIC API
334 * Public calls for the ODB functionality
336 ***********************************************************/
338 static int backend_sort_cmp(const void *a
, const void *b
)
340 const backend_internal
*backend_a
= (const backend_internal
*)(a
);
341 const backend_internal
*backend_b
= (const backend_internal
*)(b
);
343 if (backend_a
->is_alternate
== backend_b
->is_alternate
)
344 return (backend_b
->priority
- backend_a
->priority
);
346 return backend_a
->is_alternate
? 1 : -1;
349 int git_odb_new(git_odb
**out
)
351 git_odb
*db
= git__calloc(1, sizeof(*db
));
352 GITERR_CHECK_ALLOC(db
);
354 if (git_cache_init(&db
->cache
, GIT_DEFAULT_CACHE_SIZE
, &free_odb_object
) < 0 ||
355 git_vector_init(&db
->backends
, 4, backend_sort_cmp
) < 0)
362 GIT_REFCOUNT_INC(db
);
366 static int add_backend_internal(git_odb
*odb
, git_odb_backend
*backend
, int priority
, int is_alternate
)
368 backend_internal
*internal
;
370 assert(odb
&& backend
);
372 GITERR_CHECK_VERSION(backend
, GIT_ODB_BACKEND_VERSION
, "git_odb_backend");
374 /* Check if the backend is already owned by another ODB */
375 assert(!backend
->odb
|| backend
->odb
== odb
);
377 internal
= git__malloc(sizeof(backend_internal
));
378 GITERR_CHECK_ALLOC(internal
);
380 internal
->backend
= backend
;
381 internal
->priority
= priority
;
382 internal
->is_alternate
= is_alternate
;
384 if (git_vector_insert(&odb
->backends
, internal
) < 0) {
389 git_vector_sort(&odb
->backends
);
390 internal
->backend
->odb
= odb
;
394 int git_odb_add_backend(git_odb
*odb
, git_odb_backend
*backend
, int priority
)
396 return add_backend_internal(odb
, backend
, priority
, 0);
399 int git_odb_add_alternate(git_odb
*odb
, git_odb_backend
*backend
, int priority
)
401 return add_backend_internal(odb
, backend
, priority
, 1);
404 static int add_default_backends(git_odb
*db
, const char *objects_dir
, int as_alternates
, int alternate_depth
)
406 git_odb_backend
*loose
, *packed
;
408 /* add the loose object backend */
409 if (git_odb_backend_loose(&loose
, objects_dir
, -1, 0) < 0 ||
410 add_backend_internal(db
, loose
, GIT_LOOSE_PRIORITY
, as_alternates
) < 0)
413 /* add the packed file backend */
414 if (git_odb_backend_pack(&packed
, objects_dir
) < 0 ||
415 add_backend_internal(db
, packed
, GIT_PACKED_PRIORITY
, as_alternates
) < 0)
418 return load_alternates(db
, objects_dir
, alternate_depth
);
421 static int load_alternates(git_odb
*odb
, const char *objects_dir
, int alternate_depth
)
423 git_buf alternates_path
= GIT_BUF_INIT
;
424 git_buf alternates_buf
= GIT_BUF_INIT
;
426 const char *alternate
;
429 /* Git reports an error, we just ignore anything deeper */
430 if (alternate_depth
> GIT_ALTERNATES_MAX_DEPTH
) {
434 if (git_buf_joinpath(&alternates_path
, objects_dir
, GIT_ALTERNATES_FILE
) < 0)
437 if (git_path_exists(alternates_path
.ptr
) == false) {
438 git_buf_free(&alternates_path
);
442 if (git_futils_readbuffer(&alternates_buf
, alternates_path
.ptr
) < 0) {
443 git_buf_free(&alternates_path
);
447 buffer
= (char *)alternates_buf
.ptr
;
449 /* add each alternate as a new backend; one alternate per line */
450 while ((alternate
= git__strtok(&buffer
, "\r\n")) != NULL
) {
451 if (*alternate
== '\0' || *alternate
== '#')
455 * Relative path: build based on the current `objects`
456 * folder. However, relative paths are only allowed in
457 * the current repository.
459 if (*alternate
== '.' && !alternate_depth
) {
460 if ((result
= git_buf_joinpath(&alternates_path
, objects_dir
, alternate
)) < 0)
462 alternate
= git_buf_cstr(&alternates_path
);
465 if ((result
= add_default_backends(odb
, alternate
, 1, alternate_depth
+ 1)) < 0)
469 git_buf_free(&alternates_path
);
470 git_buf_free(&alternates_buf
);
475 int git_odb_add_disk_alternate(git_odb
*odb
, const char *path
)
477 return add_default_backends(odb
, path
, 1, 0);
480 int git_odb_open(git_odb
**out
, const char *objects_dir
)
484 assert(out
&& objects_dir
);
488 if (git_odb_new(&db
) < 0)
491 if (add_default_backends(db
, objects_dir
, 0, 0) < 0) {
500 static void odb_free(git_odb
*db
)
504 for (i
= 0; i
< db
->backends
.length
; ++i
) {
505 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
506 git_odb_backend
*backend
= internal
->backend
;
508 if (backend
->free
) backend
->free(backend
);
509 else git__free(backend
);
514 git_vector_free(&db
->backends
);
515 git_cache_free(&db
->cache
);
519 void git_odb_free(git_odb
*db
)
524 GIT_REFCOUNT_DEC(db
, odb_free
);
527 int git_odb_exists(git_odb
*db
, const git_oid
*id
)
529 git_odb_object
*object
;
535 if ((object
= git_cache_get(&db
->cache
, id
)) != NULL
) {
536 git_odb_object_free(object
);
540 for (i
= 0; i
< db
->backends
.length
&& !found
; ++i
) {
541 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
542 git_odb_backend
*b
= internal
->backend
;
544 if (b
->exists
!= NULL
)
545 found
= b
->exists(b
, id
);
551 int git_odb_read_header(size_t *len_p
, git_otype
*type_p
, git_odb
*db
, const git_oid
*id
)
554 git_odb_object
*object
;
556 error
= git_odb__read_header_or_object(&object
, len_p
, type_p
, db
, id
);
559 git_odb_object_free(object
);
564 int git_odb__read_header_or_object(
565 git_odb_object
**out
, size_t *len_p
, git_otype
*type_p
,
566 git_odb
*db
, const git_oid
*id
)
569 int error
= GIT_ENOTFOUND
;
570 git_odb_object
*object
;
572 assert(db
&& id
&& out
&& len_p
&& type_p
);
574 if ((object
= git_cache_get(&db
->cache
, id
)) != NULL
) {
575 *len_p
= object
->raw
.len
;
576 *type_p
= object
->raw
.type
;
583 for (i
= 0; i
< db
->backends
.length
&& error
< 0; ++i
) {
584 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
585 git_odb_backend
*b
= internal
->backend
;
587 if (b
->read_header
!= NULL
)
588 error
= b
->read_header(len_p
, type_p
, b
, id
);
591 if (!error
|| error
== GIT_PASSTHROUGH
)
595 * no backend could read only the header.
596 * try reading the whole object and freeing the contents
598 if ((error
= git_odb_read(&object
, db
, id
)) < 0)
599 return error
; /* error already set - pass along */
601 *len_p
= object
->raw
.len
;
602 *type_p
= object
->raw
.type
;
608 int git_odb_read(git_odb_object
**out
, git_odb
*db
, const git_oid
*id
)
611 int error
= GIT_ENOTFOUND
;
614 assert(out
&& db
&& id
);
616 *out
= git_cache_get(&db
->cache
, id
);
620 for (i
= 0; i
< db
->backends
.length
&& error
< 0; ++i
) {
621 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
622 git_odb_backend
*b
= internal
->backend
;
625 error
= b
->read(&raw
.data
, &raw
.len
, &raw
.type
, b
, id
);
628 /* TODO: If no backends are configured, this returns GIT_ENOTFOUND but
629 * will never have called giterr_set().
632 if (error
&& error
!= GIT_PASSTHROUGH
)
635 *out
= git_cache_try_store(&db
->cache
, new_odb_object(id
, &raw
));
639 int git_odb_read_prefix(
640 git_odb_object
**out
, git_odb
*db
, const git_oid
*short_id
, size_t len
)
643 int error
= GIT_ENOTFOUND
;
644 git_oid found_full_oid
= {{0}};
651 if (len
< GIT_OID_MINPREFIXLEN
)
652 return git_odb__error_ambiguous("prefix length too short");
654 if (len
> GIT_OID_HEXSZ
)
657 if (len
== GIT_OID_HEXSZ
) {
658 *out
= git_cache_get(&db
->cache
, short_id
);
663 for (i
= 0; i
< db
->backends
.length
; ++i
) {
664 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
665 git_odb_backend
*b
= internal
->backend
;
667 if (b
->read
!= NULL
) {
669 error
= b
->read_prefix(&full_oid
, &raw
.data
, &raw
.len
, &raw
.type
, b
, short_id
, len
);
670 if (error
== GIT_ENOTFOUND
|| error
== GIT_PASSTHROUGH
)
678 if (found
&& git_oid_cmp(&full_oid
, &found_full_oid
))
679 return git_odb__error_ambiguous("multiple matches for prefix");
680 found_full_oid
= full_oid
;
686 return git_odb__error_notfound("no match for prefix", short_id
);
688 *out
= git_cache_try_store(&db
->cache
, new_odb_object(&found_full_oid
, &raw
));
692 int git_odb_foreach(git_odb
*db
, git_odb_foreach_cb cb
, void *payload
)
695 backend_internal
*internal
;
697 git_vector_foreach(&db
->backends
, i
, internal
) {
698 git_odb_backend
*b
= internal
->backend
;
699 int error
= b
->foreach(b
, cb
, payload
);
708 git_oid
*oid
, git_odb
*db
, const void *data
, size_t len
, git_otype type
)
711 int error
= GIT_ERROR
;
712 git_odb_stream
*stream
;
716 git_odb_hash(oid
, data
, len
, type
);
717 if (git_odb_exists(db
, oid
))
720 for (i
= 0; i
< db
->backends
.length
&& error
< 0; ++i
) {
721 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
722 git_odb_backend
*b
= internal
->backend
;
724 /* we don't write in alternates! */
725 if (internal
->is_alternate
)
728 if (b
->write
!= NULL
)
729 error
= b
->write(oid
, b
, data
, len
, type
);
732 if (!error
|| error
== GIT_PASSTHROUGH
)
735 /* if no backends were able to write the object directly, we try a streaming
736 * write to the backends; just write the whole object into the stream in one
739 if ((error
= git_odb_open_wstream(&stream
, db
, len
, type
)) != 0)
742 stream
->write(stream
, data
, len
);
743 error
= stream
->finalize_write(oid
, stream
);
744 stream
->free(stream
);
749 int git_odb_open_wstream(
750 git_odb_stream
**stream
, git_odb
*db
, size_t size
, git_otype type
)
753 int error
= GIT_ERROR
;
755 assert(stream
&& db
);
757 for (i
= 0; i
< db
->backends
.length
&& error
< 0; ++i
) {
758 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
759 git_odb_backend
*b
= internal
->backend
;
761 /* we don't write in alternates! */
762 if (internal
->is_alternate
)
765 if (b
->writestream
!= NULL
)
766 error
= b
->writestream(stream
, b
, size
, type
);
767 else if (b
->write
!= NULL
)
768 error
= init_fake_wstream(stream
, b
, size
, type
);
771 if (error
== GIT_PASSTHROUGH
)
777 int git_odb_open_rstream(git_odb_stream
**stream
, git_odb
*db
, const git_oid
*oid
)
780 int error
= GIT_ERROR
;
782 assert(stream
&& db
);
784 for (i
= 0; i
< db
->backends
.length
&& error
< 0; ++i
) {
785 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
786 git_odb_backend
*b
= internal
->backend
;
788 if (b
->readstream
!= NULL
)
789 error
= b
->readstream(stream
, b
, oid
);
792 if (error
== GIT_PASSTHROUGH
)
798 int git_odb_write_pack(struct git_odb_writepack
**out
, git_odb
*db
, git_transfer_progress_callback progress_cb
, void *progress_payload
)
801 int error
= GIT_ERROR
;
805 for (i
= 0; i
< db
->backends
.length
&& error
< 0; ++i
) {
806 backend_internal
*internal
= git_vector_get(&db
->backends
, i
);
807 git_odb_backend
*b
= internal
->backend
;
809 /* we don't write in alternates! */
810 if (internal
->is_alternate
)
813 if (b
->writepack
!= NULL
)
814 error
= b
->writepack(out
, b
, progress_cb
, progress_payload
);
817 if (error
== GIT_PASSTHROUGH
)
823 void * git_odb_backend_malloc(git_odb_backend
*backend
, size_t len
)
826 return git__malloc(len
);
829 int git_odb__error_notfound(const char *message
, const git_oid
*oid
)
832 char oid_str
[GIT_OID_HEXSZ
+ 1];
833 git_oid_tostr(oid_str
, sizeof(oid_str
), oid
);
834 giterr_set(GITERR_ODB
, "Object not found - %s (%s)", message
, oid_str
);
836 giterr_set(GITERR_ODB
, "Object not found - %s", message
);
838 return GIT_ENOTFOUND
;
841 int git_odb__error_ambiguous(const char *message
)
843 giterr_set(GITERR_ODB
, "Ambiguous SHA1 prefix - %s", message
);
844 return GIT_EAMBIGUOUS
;