]> git.proxmox.com Git - libgit2.git/blame - src/odb.c
Add BD on ca-certificates
[libgit2.git] / src / odb.c
CommitLineData
c15648cb 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
c15648cb 3 *
bb742ede
VM
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.
c15648cb
SP
6 */
7
eae0bfdc
PP
8#include "odb.h"
9
0c3bae62 10#include <zlib.h>
44908fe7 11#include "git2/object.h"
83cc70d9 12#include "git2/sys/odb_backend.h"
3d3552e8 13#include "fileops.h"
c960d6a3 14#include "hash.h"
6a2d2f8a 15#include "delta.h"
60b9d3fc 16#include "filter.h"
5df18424 17#include "repository.h"
ac3d33df 18#include "blob.h"
c15648cb 19
44908fe7 20#include "git2/odb_backend.h"
c07d9c95 21#include "git2/oid.h"
6c04269c 22#include "git2/oidarray.h"
7b6e8067 23
5a800efc
VM
24#define GIT_ALTERNATES_FILE "info/alternates"
25
b0d7f329
CMN
26/*
27 * We work under the assumption that most objects for long-running
28 * operations will be packed
29 */
30#define GIT_LOOSE_PRIORITY 1
31#define GIT_PACKED_PRIORITY 2
d4b5a4e2 32
85e7efa1
CMN
33#define GIT_ALTERNATES_MAX_DEPTH 5
34
35079f50
PS
35bool git_odb__strict_hash_verification = true;
36
d4b5a4e2
VM
37typedef struct
38{
39 git_odb_backend *backend;
40 int priority;
a29c6b5f
VM
41 bool is_alternate;
42 ino_t disk_inode;
d4b5a4e2
VM
43} backend_internal;
44
5df18424
VM
45static git_cache *odb_cache(git_odb *odb)
46{
47 if (odb->rc.owner != NULL) {
48 git_repository *owner = odb->rc.owner;
49 return &owner->objects;
50 }
51
52 return &odb->own_cache;
53}
f5e28202 54
ac3d33df 55static int odb_otype_fast(git_object_t *type_p, git_odb *db, const git_oid *id);
85e7efa1 56static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth);
eae0bfdc 57static int error_null_oid(int error, const char *message);
85e7efa1 58
ac3d33df 59static git_object_t odb_hardcoded_type(const git_oid *id)
4416aa77 60{
4416aa77
VM
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
4416aa77 64 if (!git_oid_cmp(id, &empty_tree))
ac3d33df 65 return GIT_OBJECT_TREE;
4416aa77 66
ac3d33df 67 return GIT_OBJECT_INVALID;
4416aa77
VM
68}
69
eae0bfdc 70static int odb_read_hardcoded(bool *found, git_rawobj *raw, const git_oid *id)
4416aa77 71{
ac3d33df 72 git_object_t type;
eae0bfdc
PP
73
74 *found = false;
75
ac3d33df 76 if ((type = odb_hardcoded_type(id)) == GIT_OBJECT_INVALID)
eae0bfdc 77 return 0;
4416aa77
VM
78
79 raw->type = type;
80 raw->len = 0;
81 raw->data = git__calloc(1, sizeof(uint8_t));
ac3d33df 82 GIT_ERROR_CHECK_ALLOC(raw->data);
eae0bfdc
PP
83
84 *found = true;
4416aa77
VM
85 return 0;
86}
87
eae0bfdc
PP
88int git_odb__format_object_header(
89 size_t *written,
90 char *hdr,
91 size_t hdr_size,
92 git_off_t obj_len,
ac3d33df 93 git_object_t obj_type)
c960d6a3 94{
c52736fa 95 const char *type_str = git_object_type2string(obj_type);
eae0bfdc
PP
96 int hdr_max = (hdr_size > INT_MAX-2) ? (INT_MAX-2) : (int)hdr_size;
97 int len;
98
ac3d33df 99 len = p_snprintf(hdr, hdr_max, "%s %"PRId64, type_str, (int64_t)obj_len);
eae0bfdc
PP
100
101 if (len < 0 || len >= hdr_max) {
ac3d33df 102 git_error_set(GIT_ERROR_OS, "object header creation failed");
eae0bfdc
PP
103 return -1;
104 }
105
106 *written = (size_t)(len + 1);
107 return 0;
c960d6a3
RJ
108}
109
18e5b854 110int git_odb__hashobj(git_oid *id, git_rawobj *obj)
c960d6a3
RJ
111{
112 git_buf_vec vec[2];
c85e08b1 113 char header[64];
eae0bfdc
PP
114 size_t hdrlen;
115 int error;
c960d6a3 116
c85e08b1 117 assert(id && obj);
c960d6a3 118
eae0bfdc 119 if (!git_object_typeisloose(obj->type)) {
ac3d33df 120 git_error_set(GIT_ERROR_INVALID, "invalid object type");
ae9e29fd 121 return -1;
eae0bfdc 122 }
8842c75f 123
eae0bfdc 124 if (!obj->data && obj->len != 0) {
ac3d33df 125 git_error_set(GIT_ERROR_INVALID, "invalid object");
ae9e29fd 126 return -1;
eae0bfdc 127 }
c960d6a3 128
eae0bfdc
PP
129 if ((error = git_odb__format_object_header(&hdrlen,
130 header, sizeof(header), obj->len, obj->type)) < 0)
131 return error;
c960d6a3 132
c85e08b1 133 vec[0].data = header;
87d9869f 134 vec[0].len = hdrlen;
c960d6a3 135 vec[1].data = obj->data;
87d9869f 136 vec[1].len = obj->len;
c960d6a3 137
eae0bfdc 138 return git_hash_vec(id, vec, 2);
c960d6a3
RJ
139}
140
d12299fe 141
78606263 142static git_odb_object *odb_object__alloc(const git_oid *oid, git_rawobj *source)
e17a3f56 143{
78606263 144 git_odb_object *object = git__calloc(1, sizeof(git_odb_object));
e17a3f56 145
78606263
RB
146 if (object != NULL) {
147 git_oid_cpy(&object->cached.oid, oid);
148 object->cached.type = source->type;
149 object->cached.size = source->len;
150 object->buffer = source->data;
151 }
e17a3f56 152
72a3fe42 153 return object;
3d3552e8
RJ
154}
155
78606263 156void git_odb_object__free(void *object)
3d3552e8 157{
72a3fe42 158 if (object != NULL) {
78606263 159 git__free(((git_odb_object *)object)->buffer);
3286c408 160 git__free(object);
72a3fe42
VM
161 }
162}
3d3552e8 163
1881f078
VM
164const git_oid *git_odb_object_id(git_odb_object *object)
165{
166 return &object->cached.oid;
167}
168
169const void *git_odb_object_data(git_odb_object *object)
170{
8842c75f 171 return object->buffer;
1881f078
VM
172}
173
174size_t git_odb_object_size(git_odb_object *object)
175{
8842c75f 176 return object->cached.size;
1881f078
VM
177}
178
ac3d33df 179git_object_t git_odb_object_type(git_odb_object *object)
1881f078 180{
8842c75f 181 return object->cached.type;
1881f078
VM
182}
183
98fec8a9
VM
184int git_odb_object_dup(git_odb_object **dest, git_odb_object *source)
185{
186 git_cached_obj_incref(source);
187 *dest = source;
188 return 0;
189}
190
45e79e37 191void git_odb_object_free(git_odb_object *object)
72a3fe42 192{
edca6c8f
MS
193 if (object == NULL)
194 return;
195
5df18424 196 git_cached_obj_decref(object);
72a3fe42 197}
3d3552e8 198
ac3d33df 199int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_object_t type)
c52736fa 200{
eae0bfdc 201 size_t hdr_len;
7dd22538 202 char hdr[64], buffer[FILEIO_BUFSIZE];
603bee07 203 git_hash_ctx ctx;
addc9be4 204 ssize_t read_len = 0;
d6fb0924 205 int error = 0;
c52736fa 206
a13fb55a 207 if (!git_object_typeisloose(type)) {
ac3d33df 208 git_error_set(GIT_ERROR_INVALID, "invalid object type for hash");
a13fb55a
RB
209 return -1;
210 }
211
603bee07 212 if ((error = git_hash_ctx_init(&ctx)) < 0)
eae0bfdc 213 return error;
c52736fa 214
eae0bfdc
PP
215 if ((error = git_odb__format_object_header(&hdr_len, hdr,
216 sizeof(hdr), size, type)) < 0)
217 goto done;
d6fb0924 218
603bee07 219 if ((error = git_hash_update(&ctx, hdr, hdr_len)) < 0)
d6fb0924 220 goto done;
c52736fa 221
c859184b 222 while (size > 0 && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) {
603bee07 223 if ((error = git_hash_update(&ctx, buffer, read_len)) < 0)
d6fb0924
ET
224 goto done;
225
c52736fa
VM
226 size -= read_len;
227 }
228
c859184b
VM
229 /* If p_read returned an error code, the read obviously failed.
230 * If size is not zero, the file was truncated after we originally
231 * stat'd it, so we consider this a read failure too */
232 if (read_len < 0 || size > 0) {
ac3d33df 233 git_error_set(GIT_ERROR_OS, "error reading file for hashing");
d6fb0924
ET
234 error = -1;
235
236 goto done;
c859184b
VM
237 }
238
603bee07 239 error = git_hash_final(out, &ctx);
c52736fa 240
d6fb0924 241done:
603bee07 242 git_hash_ctx_cleanup(&ctx);
d6fb0924 243 return error;
c52736fa
VM
244}
245
60b9d3fc 246int git_odb__hashfd_filtered(
ac3d33df 247 git_oid *out, git_file fd, size_t size, git_object_t type, git_filter_list *fl)
60b9d3fc
RB
248{
249 int error;
250 git_buf raw = GIT_BUF_INIT;
60b9d3fc 251
85d54812 252 if (!fl)
60b9d3fc
RB
253 return git_odb__hashfd(out, fd, size, type);
254
255 /* size of data is used in header, so we have to read the whole file
256 * into memory to apply filters before beginning to calculate the hash
257 */
258
2a7d224f 259 if (!(error = git_futils_readbuffer_fd(&raw, fd, size))) {
a9f51e43 260 git_buf post = GIT_BUF_INIT;
60b9d3fc 261
a9f51e43 262 error = git_filter_list_apply_to_data(&post, fl, &raw);
60b9d3fc 263
ac3d33df 264 git_buf_dispose(&raw);
60b9d3fc 265
2a7d224f
RB
266 if (!error)
267 error = git_odb_hash(out, post.ptr, post.size, type);
268
ac3d33df 269 git_buf_dispose(&post);
2a7d224f 270 }
60b9d3fc
RB
271
272 return error;
273}
274
f19e3ca2
VM
275int git_odb__hashlink(git_oid *out, const char *path)
276{
277 struct stat st;
f1453c59 278 int size;
ae9e29fd 279 int result;
f19e3ca2 280
deafee7b 281 if (git_path_lstat(path, &st) < 0)
ae9e29fd 282 return -1;
f19e3ca2 283
f1453c59 284 if (!git__is_int(st.st_size) || (int)st.st_size < 0) {
ac3d33df 285 git_error_set(GIT_ERROR_FILESYSTEM, "file size overflow for 32-bit systems");
ae9e29fd
RB
286 return -1;
287 }
f19e3ca2 288
f1453c59 289 size = (int)st.st_size;
15d54fdd 290
f19e3ca2
VM
291 if (S_ISLNK(st.st_mode)) {
292 char *link_data;
f1453c59
ET
293 int read_len;
294 size_t alloc_size;
f19e3ca2 295
ac3d33df 296 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, size, 1);
f1453c59 297 link_data = git__malloc(alloc_size);
ac3d33df 298 GIT_ERROR_CHECK_ALLOC(link_data);
f19e3ca2 299
15d54fdd 300 read_len = p_readlink(path, link_data, size);
e8776d30 301 link_data[size] = '\0';
f1453c59 302 if (read_len != size) {
ac3d33df 303 git_error_set(GIT_ERROR_OS, "failed to read symlink data for '%s'", path);
c6451624 304 git__free(link_data);
ae9e29fd
RB
305 return -1;
306 }
f19e3ca2 307
ac3d33df 308 result = git_odb_hash(out, link_data, size, GIT_OBJECT_BLOB);
2bc8fa02 309 git__free(link_data);
60b9d3fc 310 } else {
ae9e29fd
RB
311 int fd = git_futils_open_ro(path);
312 if (fd < 0)
313 return -1;
ac3d33df 314 result = git_odb__hashfd(out, fd, size, GIT_OBJECT_BLOB);
f19e3ca2
VM
315 p_close(fd);
316 }
317
ae9e29fd 318 return result;
f19e3ca2
VM
319}
320
ac3d33df 321int git_odb_hashfile(git_oid *out, const char *path, git_object_t type)
18e5b854 322{
18e5b854 323 git_off_t size;
ae9e29fd
RB
324 int result, fd = git_futils_open_ro(path);
325 if (fd < 0)
e1de726c 326 return fd;
18e5b854
VM
327
328 if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) {
ac3d33df 329 git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems");
18e5b854 330 p_close(fd);
ae9e29fd 331 return -1;
18e5b854
VM
332 }
333
ae9e29fd 334 result = git_odb__hashfd(out, fd, (size_t)size, type);
18e5b854 335 p_close(fd);
ae9e29fd 336 return result;
18e5b854
VM
337}
338
ac3d33df 339int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type)
72a3fe42 340{
72a3fe42 341 git_rawobj raw;
3d3552e8 342
72a3fe42 343 assert(id);
3d3552e8 344
72a3fe42
VM
345 raw.data = (void *)data;
346 raw.len = len;
347 raw.type = type;
3d3552e8 348
18e5b854 349 return git_odb__hashobj(id, &raw);
3d3552e8
RJ
350}
351
d69d0185
VM
352/**
353 * FAKE WSTREAM
354 */
355
356typedef struct {
357 git_odb_stream stream;
358 char *buffer;
359 size_t size, written;
ac3d33df 360 git_object_t type;
d69d0185
VM
361} fake_wstream;
362
fe0c6d4e 363static int fake_wstream__fwrite(git_odb_stream *_stream, const git_oid *oid)
d69d0185
VM
364{
365 fake_wstream *stream = (fake_wstream *)_stream;
fe0c6d4e 366 return _stream->backend->write(_stream->backend, oid, stream->buffer, stream->size, stream->type);
d69d0185
VM
367}
368
369static int fake_wstream__write(git_odb_stream *_stream, const char *data, size_t len)
370{
371 fake_wstream *stream = (fake_wstream *)_stream;
372
eae0bfdc 373 assert(stream->written + len <= stream->size);
d69d0185
VM
374
375 memcpy(stream->buffer + stream->written, data, len);
376 stream->written += len;
ae9e29fd 377 return 0;
d69d0185
VM
378}
379
380static void fake_wstream__free(git_odb_stream *_stream)
381{
382 fake_wstream *stream = (fake_wstream *)_stream;
383
3286c408
VM
384 git__free(stream->buffer);
385 git__free(stream);
d69d0185
VM
386}
387
ac3d33df 388static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, git_off_t size, git_object_t type)
d69d0185
VM
389{
390 fake_wstream *stream;
ac3d33df 391 size_t blobsize;
d69d0185 392
ac3d33df
JK
393 GIT_ERROR_CHECK_BLOBSIZE(size);
394 blobsize = (size_t)size;
77b339f7 395
d69d0185 396 stream = git__calloc(1, sizeof(fake_wstream));
ac3d33df 397 GIT_ERROR_CHECK_ALLOC(stream);
d69d0185 398
ac3d33df 399 stream->size = blobsize;
d69d0185 400 stream->type = type;
ac3d33df 401 stream->buffer = git__malloc(blobsize);
d69d0185 402 if (stream->buffer == NULL) {
3286c408 403 git__free(stream);
ae9e29fd 404 return -1;
d69d0185
VM
405 }
406
407 stream->stream.backend = backend;
408 stream->stream.read = NULL; /* read only */
409 stream->stream.write = &fake_wstream__write;
410 stream->stream.finalize_write = &fake_wstream__fwrite;
411 stream->stream.free = &fake_wstream__free;
412 stream->stream.mode = GIT_STREAM_WRONLY;
413
414 *stream_p = (git_odb_stream *)stream;
ae9e29fd 415 return 0;
d69d0185 416}
3d3552e8 417
7d7cd885
VM
418/***********************************************************
419 *
420 * OBJECT DATABASE PUBLIC API
421 *
422 * Public calls for the ODB functionality
423 *
424 ***********************************************************/
3d3552e8 425
39e1032c 426static int backend_sort_cmp(const void *a, const void *b)
7d7cd885 427{
de18f276
VM
428 const backend_internal *backend_a = (const backend_internal *)(a);
429 const backend_internal *backend_b = (const backend_internal *)(b);
d4b5a4e2 430
a0a1b19a
VM
431 if (backend_b->priority == backend_a->priority) {
432 if (backend_a->is_alternate)
433 return -1;
434 if (backend_b->is_alternate)
435 return 1;
436 return 0;
437 }
438 return (backend_b->priority - backend_a->priority);
3d3552e8
RJ
439}
440
7d7cd885 441int git_odb_new(git_odb **out)
3d3552e8 442{
7d7cd885 443 git_odb *db = git__calloc(1, sizeof(*db));
ac3d33df 444 GIT_ERROR_CHECK_ALLOC(db);
3d3552e8 445
6147f643
PP
446 if (git_cache_init(&db->own_cache) < 0) {
447 git__free(db);
448 return -1;
449 }
450 if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
451 git_cache_free(&db->own_cache);
3286c408 452 git__free(db);
ae9e29fd 453 return -1;
7d7cd885 454 }
3d3552e8 455
7d7cd885 456 *out = db;
9462c471 457 GIT_REFCOUNT_INC(db);
ae9e29fd 458 return 0;
3d3552e8
RJ
459}
460
a29c6b5f
VM
461static int add_backend_internal(
462 git_odb *odb, git_odb_backend *backend,
463 int priority, bool is_alternate, ino_t disk_inode)
e17a3f56 464{
d4b5a4e2
VM
465 backend_internal *internal;
466
7d7cd885 467 assert(odb && backend);
e17a3f56 468
ac3d33df 469 GIT_ERROR_CHECK_VERSION(backend, GIT_ODB_BACKEND_VERSION, "git_odb_backend");
55f6f21b 470
998f7b3d
RB
471 /* Check if the backend is already owned by another ODB */
472 assert(!backend->odb || backend->odb == odb);
e17a3f56 473
d4b5a4e2 474 internal = git__malloc(sizeof(backend_internal));
ac3d33df 475 GIT_ERROR_CHECK_ALLOC(internal);
d4b5a4e2
VM
476
477 internal->backend = backend;
478 internal->priority = priority;
479 internal->is_alternate = is_alternate;
a29c6b5f 480 internal->disk_inode = disk_inode;
e17a3f56 481
d4b5a4e2 482 if (git_vector_insert(&odb->backends, internal) < 0) {
3286c408 483 git__free(internal);
ae9e29fd 484 return -1;
d4b5a4e2 485 }
e17a3f56 486
7d7cd885 487 git_vector_sort(&odb->backends);
d4b5a4e2 488 internal->backend->odb = odb;
ae9e29fd 489 return 0;
e17a3f56
RJ
490}
491
d4b5a4e2
VM
492int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority)
493{
a29c6b5f 494 return add_backend_internal(odb, backend, priority, false, 0);
d4b5a4e2
VM
495}
496
497int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority)
498{
a29c6b5f 499 return add_backend_internal(odb, backend, priority, true, 0);
d4b5a4e2
VM
500}
501
83cc70d9
RB
502size_t git_odb_num_backends(git_odb *odb)
503{
504 assert(odb);
505 return odb->backends.length;
506}
507
f063f578
RB
508static int git_odb__error_unsupported_in_backend(const char *action)
509{
ac3d33df 510 git_error_set(GIT_ERROR_ODB,
909d5494 511 "cannot %s - unsupported in the loaded odb backends", action);
f063f578
RB
512 return -1;
513}
514
515
83cc70d9
RB
516int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos)
517{
518 backend_internal *internal;
519
31a14982 520 assert(out && odb);
83cc70d9
RB
521 internal = git_vector_get(&odb->backends, pos);
522
523 if (internal && internal->backend) {
524 *out = internal->backend;
525 return 0;
526 }
527
ac3d33df 528 git_error_set(GIT_ERROR_ODB, "no ODB backend loaded at index %" PRIuZ, pos);
83cc70d9
RB
529 return GIT_ENOTFOUND;
530}
531
1c04a96b 532int git_odb__add_default_backends(
a29c6b5f
VM
533 git_odb *db, const char *objects_dir,
534 bool as_alternates, int alternate_depth)
5a800efc 535{
a29c6b5f
VM
536 size_t i;
537 struct stat st;
c8a4e8a5 538 ino_t inode;
5a800efc 539 git_odb_backend *loose, *packed;
5a800efc 540
4ef2c79c
VM
541 /* TODO: inodes are not really relevant on Win32, so we need to find
542 * a cross-platform workaround for this */
c8a4e8a5
ET
543#ifdef GIT_WIN32
544 GIT_UNUSED(i);
545 GIT_UNUSED(st);
546
547 inode = 0;
548#else
a29c6b5f 549 if (p_stat(objects_dir, &st) < 0) {
dfec726b
VM
550 if (as_alternates)
551 return 0;
552
ac3d33df 553 git_error_set(GIT_ERROR_ODB, "failed to load object database in '%s'", objects_dir);
a29c6b5f
VM
554 return -1;
555 }
556
c8a4e8a5
ET
557 inode = st.st_ino;
558
a29c6b5f
VM
559 for (i = 0; i < db->backends.length; ++i) {
560 backend_internal *backend = git_vector_get(&db->backends, i);
c8a4e8a5 561 if (backend->disk_inode == inode)
a29c6b5f
VM
562 return 0;
563 }
4ef2c79c 564#endif
f063f578 565
5a800efc 566 /* add the loose object backend */
1c04a96b 567 if (git_odb_backend_loose(&loose, objects_dir, -1, db->do_fsync, 0, 0) < 0 ||
c8a4e8a5 568 add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, inode) < 0)
ae9e29fd 569 return -1;
5a800efc
VM
570
571 /* add the packed file backend */
ae9e29fd 572 if (git_odb_backend_pack(&packed, objects_dir) < 0 ||
c8a4e8a5 573 add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates, inode) < 0)
ae9e29fd 574 return -1;
5a800efc 575
85e7efa1 576 return load_alternates(db, objects_dir, alternate_depth);
5a800efc
VM
577}
578
85e7efa1 579static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth)
5a800efc 580{
97769280 581 git_buf alternates_path = GIT_BUF_INIT;
13224ea4 582 git_buf alternates_buf = GIT_BUF_INIT;
97769280 583 char *buffer;
97769280 584 const char *alternate;
ae9e29fd 585 int result = 0;
5a800efc 586
85e7efa1 587 /* Git reports an error, we just ignore anything deeper */
f063f578 588 if (alternate_depth > GIT_ALTERNATES_MAX_DEPTH)
85e7efa1 589 return 0;
85e7efa1 590
ae9e29fd
RB
591 if (git_buf_joinpath(&alternates_path, objects_dir, GIT_ALTERNATES_FILE) < 0)
592 return -1;
5a800efc 593
1a481123 594 if (git_path_exists(alternates_path.ptr) == false) {
ac3d33df 595 git_buf_dispose(&alternates_path);
ae9e29fd 596 return 0;
97769280 597 }
5a800efc 598
ae9e29fd 599 if (git_futils_readbuffer(&alternates_buf, alternates_path.ptr) < 0) {
ac3d33df 600 git_buf_dispose(&alternates_path);
ae9e29fd 601 return -1;
97769280 602 }
5a800efc 603
13224ea4 604 buffer = (char *)alternates_buf.ptr;
5a800efc
VM
605
606 /* add each alternate as a new backend; one alternate per line */
0291b5b7 607 while ((alternate = git__strtok(&buffer, "\r\n")) != NULL) {
0291b5b7
VM
608 if (*alternate == '\0' || *alternate == '#')
609 continue;
610
85e7efa1
CMN
611 /*
612 * Relative path: build based on the current `objects`
613 * folder. However, relative paths are only allowed in
614 * the current repository.
615 */
616 if (*alternate == '.' && !alternate_depth) {
ae9e29fd 617 if ((result = git_buf_joinpath(&alternates_path, objects_dir, alternate)) < 0)
97769280
RB
618 break;
619 alternate = git_buf_cstr(&alternates_path);
0291b5b7
VM
620 }
621
1c04a96b 622 if ((result = git_odb__add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0)
0291b5b7
VM
623 break;
624 }
5a800efc 625
ac3d33df
JK
626 git_buf_dispose(&alternates_path);
627 git_buf_dispose(&alternates_buf);
13224ea4 628
ae9e29fd 629 return result;
5a800efc 630}
e17a3f56 631
9507a434
VM
632int git_odb_add_disk_alternate(git_odb *odb, const char *path)
633{
1c04a96b 634 return git_odb__add_default_backends(odb, path, true, 0);
9507a434
VM
635}
636
7d7cd885 637int git_odb_open(git_odb **out, const char *objects_dir)
e17a3f56 638{
7d7cd885 639 git_odb *db;
e17a3f56 640
5a800efc
VM
641 assert(out && objects_dir);
642
643 *out = NULL;
644
ae9e29fd
RB
645 if (git_odb_new(&db) < 0)
646 return -1;
e17a3f56 647
1c04a96b 648 if (git_odb__add_default_backends(db, objects_dir, 0, 0) < 0) {
ae9e29fd
RB
649 git_odb_free(db);
650 return -1;
651 }
e17a3f56 652
7d7cd885 653 *out = db;
ae9e29fd 654 return 0;
7d7cd885 655}
e17a3f56 656
1c04a96b
ET
657int git_odb__set_caps(git_odb *odb, int caps)
658{
659 if (caps == GIT_ODB_CAP_FROM_OWNER) {
660 git_repository *repo = odb->rc.owner;
661 int val;
662
663 if (!repo) {
ac3d33df 664 git_error_set(GIT_ERROR_ODB, "cannot access repository to set odb caps");
1c04a96b
ET
665 return -1;
666 }
667
668 if (!git_repository__cvar(&val, repo, GIT_CVAR_FSYNCOBJECTFILES))
669 odb->do_fsync = !!val;
670 }
671
672 return 0;
673}
674
9462c471 675static void odb_free(git_odb *db)
a7c60cfc 676{
10c06114 677 size_t i;
a7c60cfc 678
7d7cd885 679 for (i = 0; i < db->backends.length; ++i) {
d4b5a4e2
VM
680 backend_internal *internal = git_vector_get(&db->backends, i);
681 git_odb_backend *backend = internal->backend;
a7c60cfc 682
d3b29fb9 683 backend->free(backend);
d4b5a4e2 684
3286c408 685 git__free(internal);
a7c60cfc
SP
686 }
687
7d7cd885 688 git_vector_free(&db->backends);
5df18424 689 git_cache_free(&db->own_cache);
f658dc43 690
6de9b2ee 691 git__memzero(db, sizeof(*db));
3286c408 692 git__free(db);
608d33fa
RJ
693}
694
9462c471
VM
695void git_odb_free(git_odb *db)
696{
697 if (db == NULL)
698 return;
699
700 GIT_REFCOUNT_DEC(db, odb_free);
701}
702
8f09a98e
ET
703static int odb_exists_1(
704 git_odb *db,
705 const git_oid *id,
706 bool only_refreshed)
608d33fa 707{
10c06114 708 size_t i;
ae9e29fd 709 bool found = false;
608d33fa 710
7d7cd885 711 for (i = 0; i < db->backends.length && !found; ++i) {
d4b5a4e2
VM
712 backend_internal *internal = git_vector_get(&db->backends, i);
713 git_odb_backend *b = internal->backend;
a7c60cfc 714
43820f20
VM
715 if (only_refreshed && !b->refresh)
716 continue;
717
b1a6c316 718 if (b->exists != NULL)
66566516 719 found = (bool)b->exists(b, id);
608d33fa 720 }
608d33fa 721
ae9e29fd 722 return (int)found;
2cdc4544
RJ
723}
724
8f09a98e
ET
725static int odb_freshen_1(
726 git_odb *db,
727 const git_oid *id,
728 bool only_refreshed)
729{
730 size_t i;
731 bool found = false;
732
733 for (i = 0; i < db->backends.length && !found; ++i) {
734 backend_internal *internal = git_vector_get(&db->backends, i);
735 git_odb_backend *b = internal->backend;
736
737 if (only_refreshed && !b->refresh)
738 continue;
739
740 if (b->freshen != NULL)
741 found = !b->freshen(b, id);
742 else if (b->exists != NULL)
743 found = b->exists(b, id);
744 }
745
746 return (int)found;
747}
748
52d03f37 749int git_odb__freshen(git_odb *db, const git_oid *id)
8f09a98e
ET
750{
751 assert(db && id);
752
753 if (odb_freshen_1(db, id, false))
754 return 1;
755
756 if (!git_odb_refresh(db))
757 return odb_freshen_1(db, id, true);
758
759 /* Failed to refresh, hence not found */
760 return 0;
761}
762
43820f20 763int git_odb_exists(git_odb *db, const git_oid *id)
f5753999 764{
43820f20 765 git_odb_object *object;
f5753999 766
43820f20 767 assert(db && id);
f5753999 768
eae0bfdc
PP
769 if (git_oid_iszero(id))
770 return 0;
771
43820f20
VM
772 if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
773 git_odb_object_free(object);
6c04269c 774 return 1;
f5753999
RB
775 }
776
43820f20
VM
777 if (odb_exists_1(db, id, false))
778 return 1;
779
780 if (!git_odb_refresh(db))
781 return odb_exists_1(db, id, true);
782
783 /* Failed to refresh, hence not found */
784 return 0;
785}
786
787static int odb_exists_prefix_1(git_oid *out, git_odb *db,
788 const git_oid *key, size_t len, bool only_refreshed)
789{
790 size_t i;
791 int error = GIT_ENOTFOUND, num_found = 0;
792 git_oid last_found = {{0}}, found;
89499078 793
f5753999
RB
794 for (i = 0; i < db->backends.length; ++i) {
795 backend_internal *internal = git_vector_get(&db->backends, i);
796 git_odb_backend *b = internal->backend;
797
43820f20
VM
798 if (only_refreshed && !b->refresh)
799 continue;
800
f5753999
RB
801 if (!b->exists_prefix)
802 continue;
803
43820f20 804 error = b->exists_prefix(&found, b, key, len);
f5753999
RB
805 if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
806 continue;
807 if (error)
808 return error;
809
810 /* make sure found item doesn't introduce ambiguity */
811 if (num_found) {
812 if (git_oid__cmp(&last_found, &found))
813 return git_odb__error_ambiguous("multiple matches for prefix");
814 } else {
815 git_oid_cpy(&last_found, &found);
816 num_found++;
817 }
818 }
819
820 if (!num_found)
43820f20
VM
821 return GIT_ENOTFOUND;
822
f5753999
RB
823 if (out)
824 git_oid_cpy(out, &last_found);
825
89499078 826 return 0;
f5753999
RB
827}
828
43820f20
VM
829int git_odb_exists_prefix(
830 git_oid *out, git_odb *db, const git_oid *short_id, size_t len)
831{
832 int error;
eae0bfdc 833 git_oid key = {{0}};
43820f20
VM
834
835 assert(db && short_id);
836
837 if (len < GIT_OID_MINPREFIXLEN)
838 return git_odb__error_ambiguous("prefix length too short");
43820f20 839
6c04269c 840 if (len >= GIT_OID_HEXSZ) {
43820f20
VM
841 if (git_odb_exists(db, short_id)) {
842 if (out)
843 git_oid_cpy(out, short_id);
844 return 0;
845 } else {
e10144ae
ET
846 return git_odb__error_notfound(
847 "no match for id prefix", short_id, len);
43820f20
VM
848 }
849 }
850
6c04269c 851 git_oid__cpy_prefix(&key, short_id, len);
43820f20
VM
852
853 error = odb_exists_prefix_1(out, db, &key, len, false);
854
855 if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
856 error = odb_exists_prefix_1(out, db, &key, len, true);
857
858 if (error == GIT_ENOTFOUND)
e10144ae 859 return git_odb__error_notfound("no match for id prefix", &key, len);
43820f20
VM
860
861 return error;
862}
863
4b1f0f79 864int git_odb_expand_ids(
6c04269c 865 git_odb *db,
62484f52
ET
866 git_odb_expand_id *ids,
867 size_t count)
6c04269c 868{
4416aa77 869 size_t i;
6c04269c 870
62484f52 871 assert(db && ids);
6c04269c 872
62484f52
ET
873 for (i = 0; i < count; i++) {
874 git_odb_expand_id *query = &ids[i];
9a786650 875 int error = GIT_EAMBIGUOUS;
6c04269c 876
e78d2ac9 877 if (!query->type)
ac3d33df 878 query->type = GIT_OBJECT_ANY;
e78d2ac9
VM
879
880 /* if we have a short OID, expand it first */
881 if (query->length >= GIT_OID_MINPREFIXLEN && query->length < GIT_OID_HEXSZ) {
882 git_oid actual_id;
883
884 error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false);
885 if (!error) {
886 git_oid_cpy(&query->id, &actual_id);
887 query->length = GIT_OID_HEXSZ;
888 }
6c04269c
ET
889 }
890
9a786650 891 /*
e78d2ac9
VM
892 * now we ought to have a 40-char OID, either because we've expanded it
893 * or because the user passed a full OID. Ensure its type is right.
6c04269c 894 */
e78d2ac9 895 if (query->length >= GIT_OID_HEXSZ) {
ac3d33df 896 git_object_t actual_type;
6c04269c 897
e78d2ac9
VM
898 error = odb_otype_fast(&actual_type, db, &query->id);
899 if (!error) {
ac3d33df 900 if (query->type != GIT_OBJECT_ANY && query->type != actual_type)
e78d2ac9
VM
901 error = GIT_ENOTFOUND;
902 else
903 query->type = actual_type;
904 }
905 }
4b1f0f79 906
9a786650 907 switch (error) {
e78d2ac9 908 /* no errors, so we've successfully expanded the OID */
9a786650 909 case 0:
e78d2ac9 910 continue;
9a786650
VM
911
912 /* the object is missing or ambiguous */
913 case GIT_ENOTFOUND:
914 case GIT_EAMBIGUOUS:
62484f52
ET
915 memset(&query->id, 0, sizeof(git_oid));
916 query->length = 0;
917 query->type = 0;
9a786650
VM
918 break;
919
920 /* something went very wrong with the ODB; bail hard */
921 default:
922 return error;
6c04269c
ET
923 }
924 }
925
ac3d33df 926 git_error_clear();
9a786650 927 return 0;
6c04269c
ET
928}
929
ac3d33df 930int git_odb_read_header(size_t *len_p, git_object_t *type_p, git_odb *db, const git_oid *id)
c6ac28fd
RB
931{
932 int error;
933 git_odb_object *object;
934
935 error = git_odb__read_header_or_object(&object, len_p, type_p, db, id);
936
937 if (object)
938 git_odb_object_free(object);
939
940 return error;
941}
942
4416aa77 943static int odb_read_header_1(
ac3d33df 944 size_t *len_p, git_object_t *type_p, git_odb *db,
4416aa77
VM
945 const git_oid *id, bool only_refreshed)
946{
947 size_t i;
ac3d33df 948 git_object_t ht;
1bbcb2b2
VM
949 bool passthrough = false;
950 int error;
4416aa77 951
ac3d33df 952 if (!only_refreshed && (ht = odb_hardcoded_type(id)) != GIT_OBJECT_INVALID) {
4416aa77
VM
953 *type_p = ht;
954 *len_p = 0;
955 return 0;
956 }
957
1bbcb2b2 958 for (i = 0; i < db->backends.length; ++i) {
4416aa77
VM
959 backend_internal *internal = git_vector_get(&db->backends, i);
960 git_odb_backend *b = internal->backend;
961
962 if (only_refreshed && !b->refresh)
963 continue;
964
1bbcb2b2
VM
965 if (!b->read_header) {
966 passthrough = true;
967 continue;
968 }
969
970 error = b->read_header(len_p, type_p, b, id);
971
972 switch (error) {
973 case GIT_PASSTHROUGH:
974 passthrough = true;
975 break;
976 case GIT_ENOTFOUND:
977 break;
978 default:
979 return error;
980 }
4416aa77
VM
981 }
982
1bbcb2b2 983 return passthrough ? GIT_PASSTHROUGH : GIT_ENOTFOUND;
4416aa77
VM
984}
985
c6ac28fd 986int git_odb__read_header_or_object(
ac3d33df 987 git_odb_object **out, size_t *len_p, git_object_t *type_p,
c6ac28fd 988 git_odb *db, const git_oid *id)
a7c60cfc 989{
904b67e6 990 int error = GIT_ENOTFOUND;
72a3fe42 991 git_odb_object *object;
a7c60cfc 992
c6ac28fd 993 assert(db && id && out && len_p && type_p);
72a3fe42 994
eae0bfdc
PP
995 *out = NULL;
996
997 if (git_oid_iszero(id))
998 return error_null_oid(GIT_ENOTFOUND, "cannot read object");
999
5df18424 1000 if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
8842c75f
VM
1001 *len_p = object->cached.size;
1002 *type_p = object->cached.type;
c6ac28fd 1003 *out = object;
ae9e29fd 1004 return 0;
72a3fe42 1005 }
608d33fa 1006
4416aa77 1007 error = odb_read_header_1(len_p, type_p, db, id, false);
c6ac28fd 1008
4416aa77
VM
1009 if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
1010 error = odb_read_header_1(len_p, type_p, db, id, true);
608d33fa 1011
4416aa77
VM
1012 if (error == GIT_ENOTFOUND)
1013 return git_odb__error_notfound("cannot read header for", id, GIT_OID_HEXSZ);
608d33fa 1014
4416aa77
VM
1015 /* we found the header; return early */
1016 if (!error)
ae9e29fd 1017 return 0;
984ed6b6 1018
4416aa77
VM
1019 if (error == GIT_PASSTHROUGH) {
1020 /*
1021 * no backend has header-reading functionality
1022 * so try using `git_odb_read` instead
1023 */
1024 error = git_odb_read(&object, db, id);
1025 if (!error) {
1026 *len_p = object->cached.size;
1027 *type_p = object->cached.type;
1028 *out = object;
1029 }
e1ac0101 1030 }
4416aa77
VM
1031
1032 return error;
e1ac0101
CMN
1033}
1034
43820f20
VM
1035static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id,
1036 bool only_refreshed)
a7c60cfc 1037{
43820f20 1038 size_t i;
72a3fe42 1039 git_rawobj raw;
78606263 1040 git_odb_object *object;
28a0741f 1041 git_oid hashed;
43820f20 1042 bool found = false;
7776db51 1043 int error = 0;
a7c60cfc 1044
eae0bfdc
PP
1045 if (!only_refreshed) {
1046 if ((error = odb_read_hardcoded(&found, &raw, id)) < 0)
1047 return error;
1048 }
4a863c06 1049
43820f20 1050 for (i = 0; i < db->backends.length && !found; ++i) {
d4b5a4e2
VM
1051 backend_internal *internal = git_vector_get(&db->backends, i);
1052 git_odb_backend *b = internal->backend;
7d7cd885 1053
43820f20
VM
1054 if (only_refreshed && !b->refresh)
1055 continue;
1056
b1a6c316 1057 if (b->read != NULL) {
28a0741f 1058 error = b->read(&raw.data, &raw.len, &raw.type, b, id);
43820f20
VM
1059 if (error == GIT_PASSTHROUGH || error == GIT_ENOTFOUND)
1060 continue;
1061
1062 if (error < 0)
1063 return error;
1064
1065 found = true;
f063f578 1066 }
72a3fe42
VM
1067 }
1068
43820f20
VM
1069 if (!found)
1070 return GIT_ENOTFOUND;
7d7cd885 1071
35079f50
PS
1072 if (git_odb__strict_hash_verification) {
1073 if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0)
1074 goto out;
28a0741f 1075
35079f50
PS
1076 if (!git_oid_equal(id, &hashed)) {
1077 error = git_odb__error_mismatch(id, &hashed);
1078 goto out;
1079 }
28a0741f
PS
1080 }
1081
ac3d33df 1082 git_error_clear();
eae0bfdc
PP
1083 if ((object = odb_object__alloc(id, &raw)) == NULL) {
1084 error = -1;
28a0741f 1085 goto out;
eae0bfdc 1086 }
78606263
RB
1087
1088 *out = git_cache_store_raw(odb_cache(db), object);
28a0741f
PS
1089
1090out:
1091 if (error)
1092 git__free(raw.data);
1093 return error;
2cdc4544
RJ
1094}
1095
43820f20
VM
1096int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
1097{
1098 int error;
1099
1100 assert(out && db && id);
1101
eae0bfdc
PP
1102 if (git_oid_iszero(id))
1103 return error_null_oid(GIT_ENOTFOUND, "cannot read object");
1104
43820f20
VM
1105 *out = git_cache_get_raw(odb_cache(db), id);
1106 if (*out != NULL)
1107 return 0;
1108
1109 error = odb_read_1(out, db, id, false);
1110
1111 if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
1112 error = odb_read_1(out, db, id, true);
1113
1114 if (error == GIT_ENOTFOUND)
e10144ae 1115 return git_odb__error_notfound("no match for id", id, GIT_OID_HEXSZ);
43820f20
VM
1116
1117 return error;
1118}
1119
ac3d33df 1120static int odb_otype_fast(git_object_t *type_p, git_odb *db, const git_oid *id)
4416aa77
VM
1121{
1122 git_odb_object *object;
1123 size_t _unused;
1124 int error;
1125
eae0bfdc
PP
1126 if (git_oid_iszero(id))
1127 return error_null_oid(GIT_ENOTFOUND, "cannot get object type");
1128
4416aa77
VM
1129 if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
1130 *type_p = object->cached.type;
6147f643 1131 git_odb_object_free(object);
4416aa77
VM
1132 return 0;
1133 }
eae0bfdc 1134
4416aa77
VM
1135 error = odb_read_header_1(&_unused, type_p, db, id, false);
1136
1137 if (error == GIT_PASSTHROUGH) {
1138 error = odb_read_1(&object, db, id, false);
1139 if (!error)
1140 *type_p = object->cached.type;
1141 git_odb_object_free(object);
1142 }
1143
1144 return error;
1145}
1146
43820f20
VM
1147static int read_prefix_1(git_odb_object **out, git_odb *db,
1148 const git_oid *key, size_t len, bool only_refreshed)
dd453c4d 1149{
10c06114 1150 size_t i;
7776db51 1151 int error = 0;
43820f20 1152 git_oid found_full_oid = {{0}};
14109620 1153 git_rawobj raw = {0};
c06e0003 1154 void *data = NULL;
b1a6c316 1155 bool found = false;
78606263 1156 git_odb_object *object;
dd453c4d 1157
24634c6f 1158 for (i = 0; i < db->backends.length; ++i) {
dd453c4d
MP
1159 backend_internal *internal = git_vector_get(&db->backends, i);
1160 git_odb_backend *b = internal->backend;
1161
43820f20
VM
1162 if (only_refreshed && !b->refresh)
1163 continue;
1164
b1a6c316 1165 if (b->read_prefix != NULL) {
24634c6f 1166 git_oid full_oid;
43820f20 1167 error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, key, len);
cb3010c5
ET
1168
1169 if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) {
1170 error = 0;
24634c6f 1171 continue;
cb3010c5 1172 }
24634c6f
HWN
1173
1174 if (error)
14109620 1175 goto out;
24634c6f 1176
c06e0003
CMN
1177 git__free(data);
1178 data = raw.data;
4a863c06 1179
e54cfb9b 1180 if (found && git_oid__cmp(&full_oid, &found_full_oid)) {
14109620
PS
1181 git_buf buf = GIT_BUF_INIT;
1182
1183 git_buf_printf(&buf, "multiple matches for prefix: %s",
1184 git_oid_tostr_s(&full_oid));
1185 git_buf_printf(&buf, " %s",
1186 git_oid_tostr_s(&found_full_oid));
1187
1188 error = git_odb__error_ambiguous(buf.ptr);
ac3d33df 1189 git_buf_dispose(&buf);
14109620 1190 goto out;
e54cfb9b 1191 }
4a863c06 1192
24634c6f
HWN
1193 found_full_oid = full_oid;
1194 found = true;
dd453c4d
MP
1195 }
1196 }
1197
24634c6f 1198 if (!found)
43820f20 1199 return GIT_ENOTFOUND;
dd453c4d 1200
e0973bc0
PS
1201 if (git_odb__strict_hash_verification) {
1202 git_oid hash;
1203
1204 if ((error = git_odb_hash(&hash, raw.data, raw.len, raw.type)) < 0)
1205 goto out;
1206
1207 if (!git_oid_equal(&found_full_oid, &hash)) {
1208 error = git_odb__error_mismatch(&found_full_oid, &hash);
1209 goto out;
1210 }
1211 }
1212
eae0bfdc
PP
1213 if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) {
1214 error = -1;
14109620 1215 goto out;
eae0bfdc 1216 }
78606263
RB
1217
1218 *out = git_cache_store_raw(odb_cache(db), object);
14109620
PS
1219
1220out:
1221 if (error)
1222 git__free(raw.data);
1223
1224 return error;
dd453c4d
MP
1225}
1226
43820f20
VM
1227int git_odb_read_prefix(
1228 git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len)
1229{
1230 git_oid key = {{0}};
1231 int error;
1232
1233 assert(out && db);
1234
1235 if (len < GIT_OID_MINPREFIXLEN)
1236 return git_odb__error_ambiguous("prefix length too short");
1237
1238 if (len > GIT_OID_HEXSZ)
1239 len = GIT_OID_HEXSZ;
1240
1241 if (len == GIT_OID_HEXSZ) {
1242 *out = git_cache_get_raw(odb_cache(db), short_id);
1243 if (*out != NULL)
1244 return 0;
1245 }
1246
6c04269c 1247 git_oid__cpy_prefix(&key, short_id, len);
43820f20
VM
1248
1249 error = read_prefix_1(out, db, &key, len, false);
1250
1251 if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
1252 error = read_prefix_1(out, db, &key, len, true);
1253
1254 if (error == GIT_ENOTFOUND)
e10144ae 1255 return git_odb__error_notfound("no match for prefix", &key, len);
43820f20
VM
1256
1257 return error;
1258}
1259
2e76b5fc 1260int git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload)
521aedad
CMN
1261{
1262 unsigned int i;
1263 backend_internal *internal;
5dca2010 1264
521aedad
CMN
1265 git_vector_foreach(&db->backends, i, internal) {
1266 git_odb_backend *b = internal->backend;
2e76b5fc 1267 int error = b->foreach(b, cb, payload);
ac3d33df 1268 if (error != 0)
5dca2010 1269 return error;
521aedad
CMN
1270 }
1271
1272 return 0;
1273}
1274
e1de726c 1275int git_odb_write(
ac3d33df 1276 git_oid *oid, git_odb *db, const void *data, size_t len, git_object_t type)
f6f72d7e 1277{
10c06114 1278 size_t i;
f6f72d7e 1279 int error = GIT_ERROR;
984ed6b6 1280 git_odb_stream *stream;
f6f72d7e
VM
1281
1282 assert(oid && db);
1283
4d185dd9 1284 git_odb_hash(oid, data, len, type);
eae0bfdc
PP
1285
1286 if (git_oid_iszero(oid))
1287 return error_null_oid(GIT_EINVALID, "cannot write object");
1288
52d03f37 1289 if (git_odb__freshen(db, oid))
4d185dd9
DMB
1290 return 0;
1291
f6f72d7e
VM
1292 for (i = 0; i < db->backends.length && error < 0; ++i) {
1293 backend_internal *internal = git_vector_get(&db->backends, i);
1294 git_odb_backend *b = internal->backend;
1295
1296 /* we don't write in alternates! */
1297 if (internal->is_alternate)
1298 continue;
1299
1300 if (b->write != NULL)
fe0c6d4e 1301 error = b->write(b, oid, data, len, type);
f6f72d7e
VM
1302 }
1303
e172cf08 1304 if (!error || error == GIT_PASSTHROUGH)
e1de726c 1305 return 0;
984ed6b6 1306
f063f578
RB
1307 /* if no backends were able to write the object directly, we try a
1308 * streaming write to the backends; just write the whole object into the
1309 * stream in one push
1310 */
e1de726c
RB
1311 if ((error = git_odb_open_wstream(&stream, db, len, type)) != 0)
1312 return error;
f6f72d7e 1313
090a07d2
CMN
1314 stream->write(stream, data, len);
1315 error = stream->finalize_write(stream, oid);
376e6c9f 1316 git_odb_stream_free(stream);
e1de726c
RB
1317
1318 return error;
f6f72d7e
VM
1319}
1320
ac3d33df 1321static int hash_header(git_hash_ctx *ctx, git_off_t size, git_object_t type)
8380b39a
CMN
1322{
1323 char header[64];
eae0bfdc
PP
1324 size_t hdrlen;
1325 int error;
8380b39a 1326
eae0bfdc
PP
1327 if ((error = git_odb__format_object_header(&hdrlen,
1328 header, sizeof(header), size, type)) < 0)
1329 return error;
1330
1331 return git_hash_update(ctx, header, hdrlen);
8380b39a
CMN
1332}
1333
e1de726c 1334int git_odb_open_wstream(
ac3d33df 1335 git_odb_stream **stream, git_odb *db, git_off_t size, git_object_t type)
a7c60cfc 1336{
f063f578 1337 size_t i, writes = 0;
7d7cd885 1338 int error = GIT_ERROR;
7bd2f401 1339 git_hash_ctx *ctx = NULL;
bed3229b 1340
72a3fe42 1341 assert(stream && db);
bed3229b 1342
7d7cd885 1343 for (i = 0; i < db->backends.length && error < 0; ++i) {
d4b5a4e2
VM
1344 backend_internal *internal = git_vector_get(&db->backends, i);
1345 git_odb_backend *b = internal->backend;
1346
1347 /* we don't write in alternates! */
1348 if (internal->is_alternate)
1349 continue;
255a0dab 1350
f063f578
RB
1351 if (b->writestream != NULL) {
1352 ++writes;
72a3fe42 1353 error = b->writestream(stream, b, size, type);
f063f578
RB
1354 } else if (b->write != NULL) {
1355 ++writes;
d69d0185 1356 error = init_fake_wstream(stream, b, size, type);
f063f578 1357 }
72a3fe42
VM
1358 }
1359
7bd2f401
ET
1360 if (error < 0) {
1361 if (error == GIT_PASSTHROUGH)
1362 error = 0;
1363 else if (!writes)
1364 error = git_odb__error_unsupported_in_backend("write object");
1365
1366 goto done;
1367 }
984ed6b6 1368
8380b39a 1369 ctx = git__malloc(sizeof(git_hash_ctx));
ac3d33df 1370 GIT_ERROR_CHECK_ALLOC(ctx);
8380b39a 1371
eae0bfdc
PP
1372 if ((error = git_hash_ctx_init(ctx)) < 0 ||
1373 (error = hash_header(ctx, size, type)) < 0)
7bd2f401 1374 goto done;
8380b39a 1375
8380b39a 1376 (*stream)->hash_ctx = ctx;
031f3f80 1377 (*stream)->declared_size = size;
1378 (*stream)->received_bytes = 0;
1379
7bd2f401 1380done:
eae0bfdc
PP
1381 if (error)
1382 git__free(ctx);
e1de726c 1383 return error;
72a3fe42
VM
1384}
1385
031f3f80 1386static int git_odb_stream__invalid_length(
1387 const git_odb_stream *stream,
1388 const char *action)
1389{
ac3d33df 1390 git_error_set(GIT_ERROR_ODB,
909d5494 1391 "cannot %s - "
6c7cee42
RD
1392 "Invalid length. %"PRId64" was expected. The "
1393 "total size of the received chunks amounts to %"PRId64".",
8d93a11c 1394 action, stream->declared_size, stream->received_bytes);
031f3f80 1395
1396 return -1;
1397}
1398
376e6c9f
CMN
1399int git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len)
1400{
8380b39a 1401 git_hash_update(stream->hash_ctx, buffer, len);
031f3f80 1402
1403 stream->received_bytes += len;
1404
1405 if (stream->received_bytes > stream->declared_size)
1406 return git_odb_stream__invalid_length(stream,
1407 "stream_write()");
1408
376e6c9f
CMN
1409 return stream->write(stream, buffer, len);
1410}
1411
1412int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream)
1413{
031f3f80 1414 if (stream->received_bytes != stream->declared_size)
1415 return git_odb_stream__invalid_length(stream,
1416 "stream_finalize_write()");
1417
8380b39a 1418 git_hash_final(out, stream->hash_ctx);
4047950f 1419
52d03f37 1420 if (git_odb__freshen(stream->backend->odb, out))
4047950f 1421 return 0;
1422
fe0c6d4e 1423 return stream->finalize_write(stream, out);
376e6c9f
CMN
1424}
1425
1426int git_odb_stream_read(git_odb_stream *stream, char *buffer, size_t len)
1427{
1428 return stream->read(stream, buffer, len);
1429}
1430
1431void git_odb_stream_free(git_odb_stream *stream)
1432{
ae3b6d61
BR
1433 if (stream == NULL)
1434 return;
1435
c251f3bb 1436 git_hash_ctx_cleanup(stream->hash_ctx);
8380b39a 1437 git__free(stream->hash_ctx);
376e6c9f
CMN
1438 stream->free(stream);
1439}
1440
eae0bfdc
PP
1441int git_odb_open_rstream(
1442 git_odb_stream **stream,
1443 size_t *len,
ac3d33df 1444 git_object_t *type,
eae0bfdc
PP
1445 git_odb *db,
1446 const git_oid *oid)
72a3fe42 1447{
f063f578 1448 size_t i, reads = 0;
72a3fe42
VM
1449 int error = GIT_ERROR;
1450
1451 assert(stream && db);
1452
1453 for (i = 0; i < db->backends.length && error < 0; ++i) {
1454 backend_internal *internal = git_vector_get(&db->backends, i);
1455 git_odb_backend *b = internal->backend;
1456
f063f578
RB
1457 if (b->readstream != NULL) {
1458 ++reads;
eae0bfdc 1459 error = b->readstream(stream, len, type, b, oid);
f063f578 1460 }
adc0327a
VM
1461 }
1462
e172cf08 1463 if (error == GIT_PASSTHROUGH)
e1de726c 1464 error = 0;
f063f578
RB
1465 if (error < 0 && !reads)
1466 error = git_odb__error_unsupported_in_backend("read object streamed");
984ed6b6 1467
e1de726c
RB
1468 return error;
1469}
1470
48e60ae7 1471int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_transfer_progress_cb progress_cb, void *progress_payload)
09cc0b92 1472{
f063f578 1473 size_t i, writes = 0;
09cc0b92
ET
1474 int error = GIT_ERROR;
1475
1476 assert(out && db);
1477
1478 for (i = 0; i < db->backends.length && error < 0; ++i) {
1479 backend_internal *internal = git_vector_get(&db->backends, i);
1480 git_odb_backend *b = internal->backend;
1481
1482 /* we don't write in alternates! */
1483 if (internal->is_alternate)
1484 continue;
1485
f063f578
RB
1486 if (b->writepack != NULL) {
1487 ++writes;
0b33fca0 1488 error = b->writepack(out, b, db, progress_cb, progress_payload);
f063f578 1489 }
09cc0b92
ET
1490 }
1491
1492 if (error == GIT_PASSTHROUGH)
1493 error = 0;
f063f578
RB
1494 if (error < 0 && !writes)
1495 error = git_odb__error_unsupported_in_backend("write pack");
09cc0b92
ET
1496
1497 return error;
1498}
1499
4a863c06 1500void *git_odb_backend_malloc(git_odb_backend *backend, size_t len)
c49d328c 1501{
0e9f2fce 1502 GIT_UNUSED(backend);
c49d328c
PK
1503 return git__malloc(len);
1504}
1505
4a863c06
VM
1506int git_odb_refresh(struct git_odb *db)
1507{
10c06114 1508 size_t i;
4a863c06
VM
1509 assert(db);
1510
1511 for (i = 0; i < db->backends.length; ++i) {
1512 backend_internal *internal = git_vector_get(&db->backends, i);
1513 git_odb_backend *b = internal->backend;
1514
1515 if (b->refresh != NULL) {
1516 int error = b->refresh(b);
1517 if (error < 0)
1518 return error;
1519 }
1520 }
1521
1522 return 0;
1523}
1524
28a0741f
PS
1525int git_odb__error_mismatch(const git_oid *expected, const git_oid *actual)
1526{
1527 char expected_oid[GIT_OID_HEXSZ + 1], actual_oid[GIT_OID_HEXSZ + 1];
1528
1529 git_oid_tostr(expected_oid, sizeof(expected_oid), expected);
1530 git_oid_tostr(actual_oid, sizeof(actual_oid), actual);
1531
ac3d33df 1532 git_error_set(GIT_ERROR_ODB, "object hash mismatch - expected %s but got %s",
28a0741f
PS
1533 expected_oid, actual_oid);
1534
1535 return GIT_EMISMATCH;
1536}
1537
e10144ae
ET
1538int git_odb__error_notfound(
1539 const char *message, const git_oid *oid, size_t oid_len)
e1de726c 1540{
282283ac
RB
1541 if (oid != NULL) {
1542 char oid_str[GIT_OID_HEXSZ + 1];
2076d329 1543 git_oid_tostr(oid_str, oid_len+1, oid);
ac3d33df 1544 git_error_set(GIT_ERROR_ODB, "object not found - %s (%.*s)",
901434b0 1545 message, (int) oid_len, oid_str);
282283ac 1546 } else
ac3d33df 1547 git_error_set(GIT_ERROR_ODB, "object not found - %s", message);
282283ac 1548
904b67e6 1549 return GIT_ENOTFOUND;
e1de726c
RB
1550}
1551
eae0bfdc
PP
1552static int error_null_oid(int error, const char *message)
1553{
ac3d33df 1554 git_error_set(GIT_ERROR_ODB, "odb: %s: null OID cannot exist", message);
eae0bfdc
PP
1555 return error;
1556}
1557
e1de726c
RB
1558int git_odb__error_ambiguous(const char *message)
1559{
ac3d33df 1560 git_error_set(GIT_ERROR_ODB, "ambiguous SHA1 prefix - %s", message);
904b67e6 1561 return GIT_EAMBIGUOUS;
7b6e8067
RJ
1562}
1563
bc91347b 1564int git_odb_init_backend(git_odb_backend *backend, unsigned int version)
b9f81997 1565{
bc91347b
RB
1566 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1567 backend, version, git_odb_backend, GIT_ODB_BACKEND_INIT);
1568 return 0;
b9f81997 1569}