]> git.proxmox.com Git - libgit2.git/blame - src/odb.c
Merge branch 'debian/experimental' into debian/sid
[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"
0c9c969a 13#include "futils.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,
0c9c969a 92 git_object_size_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{
0c9c969a
UG
323 uint64_t size;
324 int fd, error = 0;
325
326 if ((fd = git_futils_open_ro(path)) < 0)
e1de726c 327 return fd;
18e5b854 328
0c9c969a
UG
329 if ((error = git_futils_filesize(&size, fd)) < 0)
330 goto done;
331
332 if (!git__is_sizet(size)) {
ac3d33df 333 git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems");
0c9c969a
UG
334 error = -1;
335 goto done;
18e5b854
VM
336 }
337
0c9c969a
UG
338 error = git_odb__hashfd(out, fd, (size_t)size, type);
339
340done:
18e5b854 341 p_close(fd);
0c9c969a 342 return error;
18e5b854
VM
343}
344
ac3d33df 345int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type)
72a3fe42 346{
72a3fe42 347 git_rawobj raw;
3d3552e8 348
72a3fe42 349 assert(id);
3d3552e8 350
72a3fe42
VM
351 raw.data = (void *)data;
352 raw.len = len;
353 raw.type = type;
3d3552e8 354
18e5b854 355 return git_odb__hashobj(id, &raw);
3d3552e8
RJ
356}
357
d69d0185
VM
358/**
359 * FAKE WSTREAM
360 */
361
362typedef struct {
363 git_odb_stream stream;
364 char *buffer;
365 size_t size, written;
ac3d33df 366 git_object_t type;
d69d0185
VM
367} fake_wstream;
368
fe0c6d4e 369static int fake_wstream__fwrite(git_odb_stream *_stream, const git_oid *oid)
d69d0185
VM
370{
371 fake_wstream *stream = (fake_wstream *)_stream;
fe0c6d4e 372 return _stream->backend->write(_stream->backend, oid, stream->buffer, stream->size, stream->type);
d69d0185
VM
373}
374
375static int fake_wstream__write(git_odb_stream *_stream, const char *data, size_t len)
376{
377 fake_wstream *stream = (fake_wstream *)_stream;
378
eae0bfdc 379 assert(stream->written + len <= stream->size);
d69d0185
VM
380
381 memcpy(stream->buffer + stream->written, data, len);
382 stream->written += len;
ae9e29fd 383 return 0;
d69d0185
VM
384}
385
386static void fake_wstream__free(git_odb_stream *_stream)
387{
388 fake_wstream *stream = (fake_wstream *)_stream;
389
3286c408
VM
390 git__free(stream->buffer);
391 git__free(stream);
d69d0185
VM
392}
393
0c9c969a 394static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, git_object_size_t size, git_object_t type)
d69d0185
VM
395{
396 fake_wstream *stream;
ac3d33df 397 size_t blobsize;
d69d0185 398
ac3d33df
JK
399 GIT_ERROR_CHECK_BLOBSIZE(size);
400 blobsize = (size_t)size;
77b339f7 401
d69d0185 402 stream = git__calloc(1, sizeof(fake_wstream));
ac3d33df 403 GIT_ERROR_CHECK_ALLOC(stream);
d69d0185 404
ac3d33df 405 stream->size = blobsize;
d69d0185 406 stream->type = type;
ac3d33df 407 stream->buffer = git__malloc(blobsize);
d69d0185 408 if (stream->buffer == NULL) {
3286c408 409 git__free(stream);
ae9e29fd 410 return -1;
d69d0185
VM
411 }
412
413 stream->stream.backend = backend;
414 stream->stream.read = NULL; /* read only */
415 stream->stream.write = &fake_wstream__write;
416 stream->stream.finalize_write = &fake_wstream__fwrite;
417 stream->stream.free = &fake_wstream__free;
418 stream->stream.mode = GIT_STREAM_WRONLY;
419
420 *stream_p = (git_odb_stream *)stream;
ae9e29fd 421 return 0;
d69d0185 422}
3d3552e8 423
7d7cd885
VM
424/***********************************************************
425 *
426 * OBJECT DATABASE PUBLIC API
427 *
428 * Public calls for the ODB functionality
429 *
430 ***********************************************************/
3d3552e8 431
39e1032c 432static int backend_sort_cmp(const void *a, const void *b)
7d7cd885 433{
de18f276
VM
434 const backend_internal *backend_a = (const backend_internal *)(a);
435 const backend_internal *backend_b = (const backend_internal *)(b);
d4b5a4e2 436
a0a1b19a
VM
437 if (backend_b->priority == backend_a->priority) {
438 if (backend_a->is_alternate)
439 return -1;
440 if (backend_b->is_alternate)
441 return 1;
442 return 0;
443 }
444 return (backend_b->priority - backend_a->priority);
3d3552e8
RJ
445}
446
7d7cd885 447int git_odb_new(git_odb **out)
3d3552e8 448{
7d7cd885 449 git_odb *db = git__calloc(1, sizeof(*db));
ac3d33df 450 GIT_ERROR_CHECK_ALLOC(db);
3d3552e8 451
6147f643
PP
452 if (git_cache_init(&db->own_cache) < 0) {
453 git__free(db);
454 return -1;
455 }
456 if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
0c9c969a 457 git_cache_dispose(&db->own_cache);
3286c408 458 git__free(db);
ae9e29fd 459 return -1;
7d7cd885 460 }
3d3552e8 461
7d7cd885 462 *out = db;
9462c471 463 GIT_REFCOUNT_INC(db);
ae9e29fd 464 return 0;
3d3552e8
RJ
465}
466
a29c6b5f
VM
467static int add_backend_internal(
468 git_odb *odb, git_odb_backend *backend,
469 int priority, bool is_alternate, ino_t disk_inode)
e17a3f56 470{
d4b5a4e2
VM
471 backend_internal *internal;
472
7d7cd885 473 assert(odb && backend);
e17a3f56 474
ac3d33df 475 GIT_ERROR_CHECK_VERSION(backend, GIT_ODB_BACKEND_VERSION, "git_odb_backend");
55f6f21b 476
998f7b3d
RB
477 /* Check if the backend is already owned by another ODB */
478 assert(!backend->odb || backend->odb == odb);
e17a3f56 479
d4b5a4e2 480 internal = git__malloc(sizeof(backend_internal));
ac3d33df 481 GIT_ERROR_CHECK_ALLOC(internal);
d4b5a4e2
VM
482
483 internal->backend = backend;
484 internal->priority = priority;
485 internal->is_alternate = is_alternate;
a29c6b5f 486 internal->disk_inode = disk_inode;
e17a3f56 487
d4b5a4e2 488 if (git_vector_insert(&odb->backends, internal) < 0) {
3286c408 489 git__free(internal);
ae9e29fd 490 return -1;
d4b5a4e2 491 }
e17a3f56 492
7d7cd885 493 git_vector_sort(&odb->backends);
d4b5a4e2 494 internal->backend->odb = odb;
ae9e29fd 495 return 0;
e17a3f56
RJ
496}
497
d4b5a4e2
VM
498int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority)
499{
a29c6b5f 500 return add_backend_internal(odb, backend, priority, false, 0);
d4b5a4e2
VM
501}
502
503int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority)
504{
a29c6b5f 505 return add_backend_internal(odb, backend, priority, true, 0);
d4b5a4e2
VM
506}
507
83cc70d9
RB
508size_t git_odb_num_backends(git_odb *odb)
509{
510 assert(odb);
511 return odb->backends.length;
512}
513
f063f578
RB
514static int git_odb__error_unsupported_in_backend(const char *action)
515{
ac3d33df 516 git_error_set(GIT_ERROR_ODB,
909d5494 517 "cannot %s - unsupported in the loaded odb backends", action);
f063f578
RB
518 return -1;
519}
520
521
83cc70d9
RB
522int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos)
523{
524 backend_internal *internal;
525
31a14982 526 assert(out && odb);
83cc70d9
RB
527 internal = git_vector_get(&odb->backends, pos);
528
529 if (internal && internal->backend) {
530 *out = internal->backend;
531 return 0;
532 }
533
ac3d33df 534 git_error_set(GIT_ERROR_ODB, "no ODB backend loaded at index %" PRIuZ, pos);
83cc70d9
RB
535 return GIT_ENOTFOUND;
536}
537
1c04a96b 538int git_odb__add_default_backends(
a29c6b5f
VM
539 git_odb *db, const char *objects_dir,
540 bool as_alternates, int alternate_depth)
5a800efc 541{
a29c6b5f
VM
542 size_t i;
543 struct stat st;
c8a4e8a5 544 ino_t inode;
5a800efc 545 git_odb_backend *loose, *packed;
5a800efc 546
4ef2c79c
VM
547 /* TODO: inodes are not really relevant on Win32, so we need to find
548 * a cross-platform workaround for this */
c8a4e8a5
ET
549#ifdef GIT_WIN32
550 GIT_UNUSED(i);
551 GIT_UNUSED(st);
552
553 inode = 0;
554#else
a29c6b5f 555 if (p_stat(objects_dir, &st) < 0) {
dfec726b 556 if (as_alternates)
0c9c969a 557 /* this should warn */
dfec726b
VM
558 return 0;
559
ac3d33df 560 git_error_set(GIT_ERROR_ODB, "failed to load object database in '%s'", objects_dir);
a29c6b5f
VM
561 return -1;
562 }
563
c8a4e8a5
ET
564 inode = st.st_ino;
565
a29c6b5f
VM
566 for (i = 0; i < db->backends.length; ++i) {
567 backend_internal *backend = git_vector_get(&db->backends, i);
c8a4e8a5 568 if (backend->disk_inode == inode)
a29c6b5f
VM
569 return 0;
570 }
4ef2c79c 571#endif
f063f578 572
5a800efc 573 /* add the loose object backend */
1c04a96b 574 if (git_odb_backend_loose(&loose, objects_dir, -1, db->do_fsync, 0, 0) < 0 ||
c8a4e8a5 575 add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, inode) < 0)
ae9e29fd 576 return -1;
5a800efc
VM
577
578 /* add the packed file backend */
ae9e29fd 579 if (git_odb_backend_pack(&packed, objects_dir) < 0 ||
c8a4e8a5 580 add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates, inode) < 0)
ae9e29fd 581 return -1;
5a800efc 582
85e7efa1 583 return load_alternates(db, objects_dir, alternate_depth);
5a800efc
VM
584}
585
85e7efa1 586static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth)
5a800efc 587{
97769280 588 git_buf alternates_path = GIT_BUF_INIT;
13224ea4 589 git_buf alternates_buf = GIT_BUF_INIT;
97769280 590 char *buffer;
97769280 591 const char *alternate;
ae9e29fd 592 int result = 0;
5a800efc 593
85e7efa1 594 /* Git reports an error, we just ignore anything deeper */
f063f578 595 if (alternate_depth > GIT_ALTERNATES_MAX_DEPTH)
85e7efa1 596 return 0;
85e7efa1 597
ae9e29fd
RB
598 if (git_buf_joinpath(&alternates_path, objects_dir, GIT_ALTERNATES_FILE) < 0)
599 return -1;
5a800efc 600
1a481123 601 if (git_path_exists(alternates_path.ptr) == false) {
ac3d33df 602 git_buf_dispose(&alternates_path);
ae9e29fd 603 return 0;
97769280 604 }
5a800efc 605
ae9e29fd 606 if (git_futils_readbuffer(&alternates_buf, alternates_path.ptr) < 0) {
ac3d33df 607 git_buf_dispose(&alternates_path);
ae9e29fd 608 return -1;
97769280 609 }
5a800efc 610
13224ea4 611 buffer = (char *)alternates_buf.ptr;
5a800efc
VM
612
613 /* add each alternate as a new backend; one alternate per line */
0291b5b7 614 while ((alternate = git__strtok(&buffer, "\r\n")) != NULL) {
0291b5b7
VM
615 if (*alternate == '\0' || *alternate == '#')
616 continue;
617
85e7efa1
CMN
618 /*
619 * Relative path: build based on the current `objects`
620 * folder. However, relative paths are only allowed in
621 * the current repository.
622 */
623 if (*alternate == '.' && !alternate_depth) {
ae9e29fd 624 if ((result = git_buf_joinpath(&alternates_path, objects_dir, alternate)) < 0)
97769280
RB
625 break;
626 alternate = git_buf_cstr(&alternates_path);
0291b5b7
VM
627 }
628
1c04a96b 629 if ((result = git_odb__add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0)
0291b5b7
VM
630 break;
631 }
5a800efc 632
ac3d33df
JK
633 git_buf_dispose(&alternates_path);
634 git_buf_dispose(&alternates_buf);
13224ea4 635
ae9e29fd 636 return result;
5a800efc 637}
e17a3f56 638
9507a434
VM
639int git_odb_add_disk_alternate(git_odb *odb, const char *path)
640{
1c04a96b 641 return git_odb__add_default_backends(odb, path, true, 0);
9507a434
VM
642}
643
7d7cd885 644int git_odb_open(git_odb **out, const char *objects_dir)
e17a3f56 645{
7d7cd885 646 git_odb *db;
e17a3f56 647
5a800efc
VM
648 assert(out && objects_dir);
649
650 *out = NULL;
651
ae9e29fd
RB
652 if (git_odb_new(&db) < 0)
653 return -1;
e17a3f56 654
1c04a96b 655 if (git_odb__add_default_backends(db, objects_dir, 0, 0) < 0) {
ae9e29fd
RB
656 git_odb_free(db);
657 return -1;
658 }
e17a3f56 659
7d7cd885 660 *out = db;
ae9e29fd 661 return 0;
7d7cd885 662}
e17a3f56 663
1c04a96b
ET
664int git_odb__set_caps(git_odb *odb, int caps)
665{
666 if (caps == GIT_ODB_CAP_FROM_OWNER) {
667 git_repository *repo = odb->rc.owner;
668 int val;
669
670 if (!repo) {
ac3d33df 671 git_error_set(GIT_ERROR_ODB, "cannot access repository to set odb caps");
1c04a96b
ET
672 return -1;
673 }
674
0c9c969a 675 if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_FSYNCOBJECTFILES))
1c04a96b
ET
676 odb->do_fsync = !!val;
677 }
678
679 return 0;
680}
681
9462c471 682static void odb_free(git_odb *db)
a7c60cfc 683{
10c06114 684 size_t i;
a7c60cfc 685
7d7cd885 686 for (i = 0; i < db->backends.length; ++i) {
d4b5a4e2
VM
687 backend_internal *internal = git_vector_get(&db->backends, i);
688 git_odb_backend *backend = internal->backend;
a7c60cfc 689
d3b29fb9 690 backend->free(backend);
d4b5a4e2 691
3286c408 692 git__free(internal);
a7c60cfc
SP
693 }
694
7d7cd885 695 git_vector_free(&db->backends);
0c9c969a 696 git_cache_dispose(&db->own_cache);
f658dc43 697
6de9b2ee 698 git__memzero(db, sizeof(*db));
3286c408 699 git__free(db);
608d33fa
RJ
700}
701
9462c471
VM
702void git_odb_free(git_odb *db)
703{
704 if (db == NULL)
705 return;
706
707 GIT_REFCOUNT_DEC(db, odb_free);
708}
709
8f09a98e
ET
710static int odb_exists_1(
711 git_odb *db,
712 const git_oid *id,
713 bool only_refreshed)
608d33fa 714{
10c06114 715 size_t i;
ae9e29fd 716 bool found = false;
608d33fa 717
7d7cd885 718 for (i = 0; i < db->backends.length && !found; ++i) {
d4b5a4e2
VM
719 backend_internal *internal = git_vector_get(&db->backends, i);
720 git_odb_backend *b = internal->backend;
a7c60cfc 721
43820f20
VM
722 if (only_refreshed && !b->refresh)
723 continue;
724
b1a6c316 725 if (b->exists != NULL)
66566516 726 found = (bool)b->exists(b, id);
608d33fa 727 }
608d33fa 728
ae9e29fd 729 return (int)found;
2cdc4544
RJ
730}
731
8f09a98e
ET
732static int odb_freshen_1(
733 git_odb *db,
734 const git_oid *id,
735 bool only_refreshed)
736{
737 size_t i;
738 bool found = false;
739
740 for (i = 0; i < db->backends.length && !found; ++i) {
741 backend_internal *internal = git_vector_get(&db->backends, i);
742 git_odb_backend *b = internal->backend;
743
744 if (only_refreshed && !b->refresh)
745 continue;
746
747 if (b->freshen != NULL)
748 found = !b->freshen(b, id);
749 else if (b->exists != NULL)
750 found = b->exists(b, id);
751 }
752
753 return (int)found;
754}
755
52d03f37 756int git_odb__freshen(git_odb *db, const git_oid *id)
8f09a98e
ET
757{
758 assert(db && id);
759
760 if (odb_freshen_1(db, id, false))
761 return 1;
762
763 if (!git_odb_refresh(db))
764 return odb_freshen_1(db, id, true);
765
766 /* Failed to refresh, hence not found */
767 return 0;
768}
769
43820f20 770int git_odb_exists(git_odb *db, const git_oid *id)
f5753999 771{
43820f20 772 git_odb_object *object;
f5753999 773
43820f20 774 assert(db && id);
f5753999 775
0c9c969a 776 if (git_oid_is_zero(id))
eae0bfdc
PP
777 return 0;
778
43820f20
VM
779 if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
780 git_odb_object_free(object);
6c04269c 781 return 1;
f5753999
RB
782 }
783
43820f20
VM
784 if (odb_exists_1(db, id, false))
785 return 1;
786
787 if (!git_odb_refresh(db))
788 return odb_exists_1(db, id, true);
789
790 /* Failed to refresh, hence not found */
791 return 0;
792}
793
794static int odb_exists_prefix_1(git_oid *out, git_odb *db,
795 const git_oid *key, size_t len, bool only_refreshed)
796{
797 size_t i;
798 int error = GIT_ENOTFOUND, num_found = 0;
799 git_oid last_found = {{0}}, found;
89499078 800
f5753999
RB
801 for (i = 0; i < db->backends.length; ++i) {
802 backend_internal *internal = git_vector_get(&db->backends, i);
803 git_odb_backend *b = internal->backend;
804
43820f20
VM
805 if (only_refreshed && !b->refresh)
806 continue;
807
f5753999
RB
808 if (!b->exists_prefix)
809 continue;
810
43820f20 811 error = b->exists_prefix(&found, b, key, len);
f5753999
RB
812 if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
813 continue;
814 if (error)
815 return error;
816
817 /* make sure found item doesn't introduce ambiguity */
818 if (num_found) {
819 if (git_oid__cmp(&last_found, &found))
820 return git_odb__error_ambiguous("multiple matches for prefix");
821 } else {
822 git_oid_cpy(&last_found, &found);
823 num_found++;
824 }
825 }
826
827 if (!num_found)
43820f20
VM
828 return GIT_ENOTFOUND;
829
f5753999
RB
830 if (out)
831 git_oid_cpy(out, &last_found);
832
89499078 833 return 0;
f5753999
RB
834}
835
43820f20
VM
836int git_odb_exists_prefix(
837 git_oid *out, git_odb *db, const git_oid *short_id, size_t len)
838{
839 int error;
eae0bfdc 840 git_oid key = {{0}};
43820f20
VM
841
842 assert(db && short_id);
843
844 if (len < GIT_OID_MINPREFIXLEN)
845 return git_odb__error_ambiguous("prefix length too short");
43820f20 846
6c04269c 847 if (len >= GIT_OID_HEXSZ) {
43820f20
VM
848 if (git_odb_exists(db, short_id)) {
849 if (out)
850 git_oid_cpy(out, short_id);
851 return 0;
852 } else {
e10144ae
ET
853 return git_odb__error_notfound(
854 "no match for id prefix", short_id, len);
43820f20
VM
855 }
856 }
857
6c04269c 858 git_oid__cpy_prefix(&key, short_id, len);
43820f20
VM
859
860 error = odb_exists_prefix_1(out, db, &key, len, false);
861
862 if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
863 error = odb_exists_prefix_1(out, db, &key, len, true);
864
865 if (error == GIT_ENOTFOUND)
e10144ae 866 return git_odb__error_notfound("no match for id prefix", &key, len);
43820f20
VM
867
868 return error;
869}
870
4b1f0f79 871int git_odb_expand_ids(
6c04269c 872 git_odb *db,
62484f52
ET
873 git_odb_expand_id *ids,
874 size_t count)
6c04269c 875{
4416aa77 876 size_t i;
6c04269c 877
62484f52 878 assert(db && ids);
6c04269c 879
62484f52
ET
880 for (i = 0; i < count; i++) {
881 git_odb_expand_id *query = &ids[i];
9a786650 882 int error = GIT_EAMBIGUOUS;
6c04269c 883
e78d2ac9 884 if (!query->type)
ac3d33df 885 query->type = GIT_OBJECT_ANY;
e78d2ac9
VM
886
887 /* if we have a short OID, expand it first */
888 if (query->length >= GIT_OID_MINPREFIXLEN && query->length < GIT_OID_HEXSZ) {
889 git_oid actual_id;
890
891 error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false);
892 if (!error) {
893 git_oid_cpy(&query->id, &actual_id);
894 query->length = GIT_OID_HEXSZ;
895 }
6c04269c
ET
896 }
897
9a786650 898 /*
e78d2ac9
VM
899 * now we ought to have a 40-char OID, either because we've expanded it
900 * or because the user passed a full OID. Ensure its type is right.
6c04269c 901 */
e78d2ac9 902 if (query->length >= GIT_OID_HEXSZ) {
ac3d33df 903 git_object_t actual_type;
6c04269c 904
e78d2ac9
VM
905 error = odb_otype_fast(&actual_type, db, &query->id);
906 if (!error) {
ac3d33df 907 if (query->type != GIT_OBJECT_ANY && query->type != actual_type)
e78d2ac9
VM
908 error = GIT_ENOTFOUND;
909 else
910 query->type = actual_type;
911 }
912 }
4b1f0f79 913
9a786650 914 switch (error) {
e78d2ac9 915 /* no errors, so we've successfully expanded the OID */
9a786650 916 case 0:
e78d2ac9 917 continue;
9a786650
VM
918
919 /* the object is missing or ambiguous */
920 case GIT_ENOTFOUND:
921 case GIT_EAMBIGUOUS:
62484f52
ET
922 memset(&query->id, 0, sizeof(git_oid));
923 query->length = 0;
924 query->type = 0;
9a786650
VM
925 break;
926
927 /* something went very wrong with the ODB; bail hard */
928 default:
929 return error;
6c04269c
ET
930 }
931 }
932
ac3d33df 933 git_error_clear();
9a786650 934 return 0;
6c04269c
ET
935}
936
ac3d33df 937int git_odb_read_header(size_t *len_p, git_object_t *type_p, git_odb *db, const git_oid *id)
c6ac28fd
RB
938{
939 int error;
940 git_odb_object *object;
941
942 error = git_odb__read_header_or_object(&object, len_p, type_p, db, id);
943
944 if (object)
945 git_odb_object_free(object);
946
947 return error;
948}
949
4416aa77 950static int odb_read_header_1(
ac3d33df 951 size_t *len_p, git_object_t *type_p, git_odb *db,
4416aa77
VM
952 const git_oid *id, bool only_refreshed)
953{
954 size_t i;
ac3d33df 955 git_object_t ht;
1bbcb2b2
VM
956 bool passthrough = false;
957 int error;
4416aa77 958
ac3d33df 959 if (!only_refreshed && (ht = odb_hardcoded_type(id)) != GIT_OBJECT_INVALID) {
4416aa77
VM
960 *type_p = ht;
961 *len_p = 0;
962 return 0;
963 }
964
1bbcb2b2 965 for (i = 0; i < db->backends.length; ++i) {
4416aa77
VM
966 backend_internal *internal = git_vector_get(&db->backends, i);
967 git_odb_backend *b = internal->backend;
968
969 if (only_refreshed && !b->refresh)
970 continue;
971
1bbcb2b2
VM
972 if (!b->read_header) {
973 passthrough = true;
974 continue;
975 }
976
977 error = b->read_header(len_p, type_p, b, id);
978
979 switch (error) {
980 case GIT_PASSTHROUGH:
981 passthrough = true;
982 break;
983 case GIT_ENOTFOUND:
984 break;
985 default:
986 return error;
987 }
4416aa77
VM
988 }
989
1bbcb2b2 990 return passthrough ? GIT_PASSTHROUGH : GIT_ENOTFOUND;
4416aa77
VM
991}
992
c6ac28fd 993int git_odb__read_header_or_object(
ac3d33df 994 git_odb_object **out, size_t *len_p, git_object_t *type_p,
c6ac28fd 995 git_odb *db, const git_oid *id)
a7c60cfc 996{
904b67e6 997 int error = GIT_ENOTFOUND;
72a3fe42 998 git_odb_object *object;
a7c60cfc 999
c6ac28fd 1000 assert(db && id && out && len_p && type_p);
72a3fe42 1001
eae0bfdc
PP
1002 *out = NULL;
1003
0c9c969a 1004 if (git_oid_is_zero(id))
eae0bfdc
PP
1005 return error_null_oid(GIT_ENOTFOUND, "cannot read object");
1006
5df18424 1007 if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
8842c75f
VM
1008 *len_p = object->cached.size;
1009 *type_p = object->cached.type;
c6ac28fd 1010 *out = object;
ae9e29fd 1011 return 0;
72a3fe42 1012 }
608d33fa 1013
4416aa77 1014 error = odb_read_header_1(len_p, type_p, db, id, false);
c6ac28fd 1015
4416aa77
VM
1016 if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
1017 error = odb_read_header_1(len_p, type_p, db, id, true);
608d33fa 1018
4416aa77
VM
1019 if (error == GIT_ENOTFOUND)
1020 return git_odb__error_notfound("cannot read header for", id, GIT_OID_HEXSZ);
608d33fa 1021
4416aa77
VM
1022 /* we found the header; return early */
1023 if (!error)
ae9e29fd 1024 return 0;
984ed6b6 1025
4416aa77
VM
1026 if (error == GIT_PASSTHROUGH) {
1027 /*
1028 * no backend has header-reading functionality
1029 * so try using `git_odb_read` instead
1030 */
1031 error = git_odb_read(&object, db, id);
1032 if (!error) {
1033 *len_p = object->cached.size;
1034 *type_p = object->cached.type;
1035 *out = object;
1036 }
e1ac0101 1037 }
4416aa77
VM
1038
1039 return error;
e1ac0101
CMN
1040}
1041
43820f20
VM
1042static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id,
1043 bool only_refreshed)
a7c60cfc 1044{
43820f20 1045 size_t i;
72a3fe42 1046 git_rawobj raw;
78606263 1047 git_odb_object *object;
28a0741f 1048 git_oid hashed;
43820f20 1049 bool found = false;
7776db51 1050 int error = 0;
a7c60cfc 1051
eae0bfdc
PP
1052 if (!only_refreshed) {
1053 if ((error = odb_read_hardcoded(&found, &raw, id)) < 0)
1054 return error;
1055 }
4a863c06 1056
43820f20 1057 for (i = 0; i < db->backends.length && !found; ++i) {
d4b5a4e2
VM
1058 backend_internal *internal = git_vector_get(&db->backends, i);
1059 git_odb_backend *b = internal->backend;
7d7cd885 1060
43820f20
VM
1061 if (only_refreshed && !b->refresh)
1062 continue;
1063
b1a6c316 1064 if (b->read != NULL) {
28a0741f 1065 error = b->read(&raw.data, &raw.len, &raw.type, b, id);
43820f20
VM
1066 if (error == GIT_PASSTHROUGH || error == GIT_ENOTFOUND)
1067 continue;
1068
1069 if (error < 0)
1070 return error;
1071
1072 found = true;
f063f578 1073 }
72a3fe42
VM
1074 }
1075
43820f20
VM
1076 if (!found)
1077 return GIT_ENOTFOUND;
7d7cd885 1078
35079f50
PS
1079 if (git_odb__strict_hash_verification) {
1080 if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0)
1081 goto out;
28a0741f 1082
35079f50
PS
1083 if (!git_oid_equal(id, &hashed)) {
1084 error = git_odb__error_mismatch(id, &hashed);
1085 goto out;
1086 }
28a0741f
PS
1087 }
1088
ac3d33df 1089 git_error_clear();
eae0bfdc
PP
1090 if ((object = odb_object__alloc(id, &raw)) == NULL) {
1091 error = -1;
28a0741f 1092 goto out;
eae0bfdc 1093 }
78606263
RB
1094
1095 *out = git_cache_store_raw(odb_cache(db), object);
28a0741f
PS
1096
1097out:
1098 if (error)
1099 git__free(raw.data);
1100 return error;
2cdc4544
RJ
1101}
1102
43820f20
VM
1103int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
1104{
1105 int error;
1106
1107 assert(out && db && id);
1108
0c9c969a 1109 if (git_oid_is_zero(id))
eae0bfdc
PP
1110 return error_null_oid(GIT_ENOTFOUND, "cannot read object");
1111
43820f20
VM
1112 *out = git_cache_get_raw(odb_cache(db), id);
1113 if (*out != NULL)
1114 return 0;
1115
1116 error = odb_read_1(out, db, id, false);
1117
1118 if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
1119 error = odb_read_1(out, db, id, true);
1120
1121 if (error == GIT_ENOTFOUND)
e10144ae 1122 return git_odb__error_notfound("no match for id", id, GIT_OID_HEXSZ);
43820f20
VM
1123
1124 return error;
1125}
1126
ac3d33df 1127static int odb_otype_fast(git_object_t *type_p, git_odb *db, const git_oid *id)
4416aa77
VM
1128{
1129 git_odb_object *object;
1130 size_t _unused;
1131 int error;
1132
0c9c969a 1133 if (git_oid_is_zero(id))
eae0bfdc
PP
1134 return error_null_oid(GIT_ENOTFOUND, "cannot get object type");
1135
4416aa77
VM
1136 if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
1137 *type_p = object->cached.type;
6147f643 1138 git_odb_object_free(object);
4416aa77
VM
1139 return 0;
1140 }
eae0bfdc 1141
4416aa77
VM
1142 error = odb_read_header_1(&_unused, type_p, db, id, false);
1143
1144 if (error == GIT_PASSTHROUGH) {
1145 error = odb_read_1(&object, db, id, false);
1146 if (!error)
1147 *type_p = object->cached.type;
1148 git_odb_object_free(object);
1149 }
1150
1151 return error;
1152}
1153
43820f20
VM
1154static int read_prefix_1(git_odb_object **out, git_odb *db,
1155 const git_oid *key, size_t len, bool only_refreshed)
dd453c4d 1156{
10c06114 1157 size_t i;
7776db51 1158 int error = 0;
43820f20 1159 git_oid found_full_oid = {{0}};
14109620 1160 git_rawobj raw = {0};
c06e0003 1161 void *data = NULL;
b1a6c316 1162 bool found = false;
78606263 1163 git_odb_object *object;
dd453c4d 1164
24634c6f 1165 for (i = 0; i < db->backends.length; ++i) {
dd453c4d
MP
1166 backend_internal *internal = git_vector_get(&db->backends, i);
1167 git_odb_backend *b = internal->backend;
1168
43820f20
VM
1169 if (only_refreshed && !b->refresh)
1170 continue;
1171
b1a6c316 1172 if (b->read_prefix != NULL) {
24634c6f 1173 git_oid full_oid;
43820f20 1174 error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, key, len);
cb3010c5
ET
1175
1176 if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) {
1177 error = 0;
24634c6f 1178 continue;
cb3010c5 1179 }
24634c6f
HWN
1180
1181 if (error)
14109620 1182 goto out;
24634c6f 1183
c06e0003
CMN
1184 git__free(data);
1185 data = raw.data;
4a863c06 1186
e54cfb9b 1187 if (found && git_oid__cmp(&full_oid, &found_full_oid)) {
14109620
PS
1188 git_buf buf = GIT_BUF_INIT;
1189
1190 git_buf_printf(&buf, "multiple matches for prefix: %s",
1191 git_oid_tostr_s(&full_oid));
1192 git_buf_printf(&buf, " %s",
1193 git_oid_tostr_s(&found_full_oid));
1194
1195 error = git_odb__error_ambiguous(buf.ptr);
ac3d33df 1196 git_buf_dispose(&buf);
14109620 1197 goto out;
e54cfb9b 1198 }
4a863c06 1199
24634c6f
HWN
1200 found_full_oid = full_oid;
1201 found = true;
dd453c4d
MP
1202 }
1203 }
1204
24634c6f 1205 if (!found)
43820f20 1206 return GIT_ENOTFOUND;
dd453c4d 1207
e0973bc0
PS
1208 if (git_odb__strict_hash_verification) {
1209 git_oid hash;
1210
1211 if ((error = git_odb_hash(&hash, raw.data, raw.len, raw.type)) < 0)
1212 goto out;
1213
1214 if (!git_oid_equal(&found_full_oid, &hash)) {
1215 error = git_odb__error_mismatch(&found_full_oid, &hash);
1216 goto out;
1217 }
1218 }
1219
eae0bfdc
PP
1220 if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) {
1221 error = -1;
14109620 1222 goto out;
eae0bfdc 1223 }
78606263
RB
1224
1225 *out = git_cache_store_raw(odb_cache(db), object);
14109620
PS
1226
1227out:
1228 if (error)
1229 git__free(raw.data);
1230
1231 return error;
dd453c4d
MP
1232}
1233
43820f20
VM
1234int git_odb_read_prefix(
1235 git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len)
1236{
1237 git_oid key = {{0}};
1238 int error;
1239
1240 assert(out && db);
1241
1242 if (len < GIT_OID_MINPREFIXLEN)
1243 return git_odb__error_ambiguous("prefix length too short");
1244
1245 if (len > GIT_OID_HEXSZ)
1246 len = GIT_OID_HEXSZ;
1247
1248 if (len == GIT_OID_HEXSZ) {
1249 *out = git_cache_get_raw(odb_cache(db), short_id);
1250 if (*out != NULL)
1251 return 0;
1252 }
1253
6c04269c 1254 git_oid__cpy_prefix(&key, short_id, len);
43820f20
VM
1255
1256 error = read_prefix_1(out, db, &key, len, false);
1257
1258 if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
1259 error = read_prefix_1(out, db, &key, len, true);
1260
1261 if (error == GIT_ENOTFOUND)
e10144ae 1262 return git_odb__error_notfound("no match for prefix", &key, len);
43820f20
VM
1263
1264 return error;
1265}
1266
2e76b5fc 1267int git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload)
521aedad
CMN
1268{
1269 unsigned int i;
1270 backend_internal *internal;
5dca2010 1271
521aedad
CMN
1272 git_vector_foreach(&db->backends, i, internal) {
1273 git_odb_backend *b = internal->backend;
2e76b5fc 1274 int error = b->foreach(b, cb, payload);
ac3d33df 1275 if (error != 0)
5dca2010 1276 return error;
521aedad
CMN
1277 }
1278
1279 return 0;
1280}
1281
e1de726c 1282int git_odb_write(
ac3d33df 1283 git_oid *oid, git_odb *db, const void *data, size_t len, git_object_t type)
f6f72d7e 1284{
10c06114 1285 size_t i;
f6f72d7e 1286 int error = GIT_ERROR;
984ed6b6 1287 git_odb_stream *stream;
f6f72d7e
VM
1288
1289 assert(oid && db);
1290
4d185dd9 1291 git_odb_hash(oid, data, len, type);
eae0bfdc 1292
0c9c969a 1293 if (git_oid_is_zero(oid))
eae0bfdc
PP
1294 return error_null_oid(GIT_EINVALID, "cannot write object");
1295
52d03f37 1296 if (git_odb__freshen(db, oid))
4d185dd9
DMB
1297 return 0;
1298
f6f72d7e
VM
1299 for (i = 0; i < db->backends.length && error < 0; ++i) {
1300 backend_internal *internal = git_vector_get(&db->backends, i);
1301 git_odb_backend *b = internal->backend;
1302
1303 /* we don't write in alternates! */
1304 if (internal->is_alternate)
1305 continue;
1306
1307 if (b->write != NULL)
fe0c6d4e 1308 error = b->write(b, oid, data, len, type);
f6f72d7e
VM
1309 }
1310
e172cf08 1311 if (!error || error == GIT_PASSTHROUGH)
e1de726c 1312 return 0;
984ed6b6 1313
f063f578
RB
1314 /* if no backends were able to write the object directly, we try a
1315 * streaming write to the backends; just write the whole object into the
1316 * stream in one push
1317 */
e1de726c
RB
1318 if ((error = git_odb_open_wstream(&stream, db, len, type)) != 0)
1319 return error;
f6f72d7e 1320
090a07d2
CMN
1321 stream->write(stream, data, len);
1322 error = stream->finalize_write(stream, oid);
376e6c9f 1323 git_odb_stream_free(stream);
e1de726c
RB
1324
1325 return error;
f6f72d7e
VM
1326}
1327
0c9c969a 1328static int hash_header(git_hash_ctx *ctx, git_object_size_t size, git_object_t type)
8380b39a
CMN
1329{
1330 char header[64];
eae0bfdc
PP
1331 size_t hdrlen;
1332 int error;
8380b39a 1333
eae0bfdc
PP
1334 if ((error = git_odb__format_object_header(&hdrlen,
1335 header, sizeof(header), size, type)) < 0)
1336 return error;
1337
1338 return git_hash_update(ctx, header, hdrlen);
8380b39a
CMN
1339}
1340
e1de726c 1341int git_odb_open_wstream(
0c9c969a 1342 git_odb_stream **stream, git_odb *db, git_object_size_t size, git_object_t type)
a7c60cfc 1343{
f063f578 1344 size_t i, writes = 0;
7d7cd885 1345 int error = GIT_ERROR;
7bd2f401 1346 git_hash_ctx *ctx = NULL;
bed3229b 1347
72a3fe42 1348 assert(stream && db);
bed3229b 1349
7d7cd885 1350 for (i = 0; i < db->backends.length && error < 0; ++i) {
d4b5a4e2
VM
1351 backend_internal *internal = git_vector_get(&db->backends, i);
1352 git_odb_backend *b = internal->backend;
1353
1354 /* we don't write in alternates! */
1355 if (internal->is_alternate)
1356 continue;
255a0dab 1357
f063f578
RB
1358 if (b->writestream != NULL) {
1359 ++writes;
72a3fe42 1360 error = b->writestream(stream, b, size, type);
f063f578
RB
1361 } else if (b->write != NULL) {
1362 ++writes;
d69d0185 1363 error = init_fake_wstream(stream, b, size, type);
f063f578 1364 }
72a3fe42
VM
1365 }
1366
7bd2f401
ET
1367 if (error < 0) {
1368 if (error == GIT_PASSTHROUGH)
1369 error = 0;
1370 else if (!writes)
1371 error = git_odb__error_unsupported_in_backend("write object");
1372
1373 goto done;
1374 }
984ed6b6 1375
8380b39a 1376 ctx = git__malloc(sizeof(git_hash_ctx));
ac3d33df 1377 GIT_ERROR_CHECK_ALLOC(ctx);
8380b39a 1378
eae0bfdc
PP
1379 if ((error = git_hash_ctx_init(ctx)) < 0 ||
1380 (error = hash_header(ctx, size, type)) < 0)
7bd2f401 1381 goto done;
8380b39a 1382
8380b39a 1383 (*stream)->hash_ctx = ctx;
031f3f80 1384 (*stream)->declared_size = size;
1385 (*stream)->received_bytes = 0;
1386
7bd2f401 1387done:
eae0bfdc
PP
1388 if (error)
1389 git__free(ctx);
e1de726c 1390 return error;
72a3fe42
VM
1391}
1392
031f3f80 1393static int git_odb_stream__invalid_length(
1394 const git_odb_stream *stream,
1395 const char *action)
1396{
ac3d33df 1397 git_error_set(GIT_ERROR_ODB,
909d5494 1398 "cannot %s - "
6c7cee42
RD
1399 "Invalid length. %"PRId64" was expected. The "
1400 "total size of the received chunks amounts to %"PRId64".",
8d93a11c 1401 action, stream->declared_size, stream->received_bytes);
031f3f80 1402
1403 return -1;
1404}
1405
376e6c9f
CMN
1406int git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len)
1407{
8380b39a 1408 git_hash_update(stream->hash_ctx, buffer, len);
031f3f80 1409
1410 stream->received_bytes += len;
1411
1412 if (stream->received_bytes > stream->declared_size)
1413 return git_odb_stream__invalid_length(stream,
1414 "stream_write()");
1415
376e6c9f
CMN
1416 return stream->write(stream, buffer, len);
1417}
1418
1419int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream)
1420{
031f3f80 1421 if (stream->received_bytes != stream->declared_size)
1422 return git_odb_stream__invalid_length(stream,
1423 "stream_finalize_write()");
1424
8380b39a 1425 git_hash_final(out, stream->hash_ctx);
4047950f 1426
52d03f37 1427 if (git_odb__freshen(stream->backend->odb, out))
4047950f 1428 return 0;
1429
fe0c6d4e 1430 return stream->finalize_write(stream, out);
376e6c9f
CMN
1431}
1432
1433int git_odb_stream_read(git_odb_stream *stream, char *buffer, size_t len)
1434{
1435 return stream->read(stream, buffer, len);
1436}
1437
1438void git_odb_stream_free(git_odb_stream *stream)
1439{
ae3b6d61
BR
1440 if (stream == NULL)
1441 return;
1442
c251f3bb 1443 git_hash_ctx_cleanup(stream->hash_ctx);
8380b39a 1444 git__free(stream->hash_ctx);
376e6c9f
CMN
1445 stream->free(stream);
1446}
1447
eae0bfdc
PP
1448int git_odb_open_rstream(
1449 git_odb_stream **stream,
1450 size_t *len,
ac3d33df 1451 git_object_t *type,
eae0bfdc
PP
1452 git_odb *db,
1453 const git_oid *oid)
72a3fe42 1454{
f063f578 1455 size_t i, reads = 0;
72a3fe42
VM
1456 int error = GIT_ERROR;
1457
1458 assert(stream && db);
1459
1460 for (i = 0; i < db->backends.length && error < 0; ++i) {
1461 backend_internal *internal = git_vector_get(&db->backends, i);
1462 git_odb_backend *b = internal->backend;
1463
f063f578
RB
1464 if (b->readstream != NULL) {
1465 ++reads;
eae0bfdc 1466 error = b->readstream(stream, len, type, b, oid);
f063f578 1467 }
adc0327a
VM
1468 }
1469
e172cf08 1470 if (error == GIT_PASSTHROUGH)
e1de726c 1471 error = 0;
f063f578
RB
1472 if (error < 0 && !reads)
1473 error = git_odb__error_unsupported_in_backend("read object streamed");
984ed6b6 1474
e1de726c
RB
1475 return error;
1476}
1477
0c9c969a 1478int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_indexer_progress_cb progress_cb, void *progress_payload)
09cc0b92 1479{
f063f578 1480 size_t i, writes = 0;
09cc0b92
ET
1481 int error = GIT_ERROR;
1482
1483 assert(out && db);
1484
1485 for (i = 0; i < db->backends.length && error < 0; ++i) {
1486 backend_internal *internal = git_vector_get(&db->backends, i);
1487 git_odb_backend *b = internal->backend;
1488
1489 /* we don't write in alternates! */
1490 if (internal->is_alternate)
1491 continue;
1492
f063f578
RB
1493 if (b->writepack != NULL) {
1494 ++writes;
0b33fca0 1495 error = b->writepack(out, b, db, progress_cb, progress_payload);
f063f578 1496 }
09cc0b92
ET
1497 }
1498
1499 if (error == GIT_PASSTHROUGH)
1500 error = 0;
f063f578
RB
1501 if (error < 0 && !writes)
1502 error = git_odb__error_unsupported_in_backend("write pack");
09cc0b92
ET
1503
1504 return error;
1505}
1506
0c9c969a 1507void *git_odb_backend_data_alloc(git_odb_backend *backend, size_t len)
c49d328c 1508{
0e9f2fce 1509 GIT_UNUSED(backend);
c49d328c
PK
1510 return git__malloc(len);
1511}
1512
0c9c969a
UG
1513void *git_odb_backend_malloc(git_odb_backend *backend, size_t len)
1514{
1515 return git_odb_backend_data_alloc(backend, len);
1516}
1517
1518void git_odb_backend_data_free(git_odb_backend *backend, void *data)
1519{
1520 GIT_UNUSED(backend);
1521 git__free(data);
1522}
1523
4a863c06
VM
1524int git_odb_refresh(struct git_odb *db)
1525{
10c06114 1526 size_t i;
4a863c06
VM
1527 assert(db);
1528
1529 for (i = 0; i < db->backends.length; ++i) {
1530 backend_internal *internal = git_vector_get(&db->backends, i);
1531 git_odb_backend *b = internal->backend;
1532
1533 if (b->refresh != NULL) {
1534 int error = b->refresh(b);
1535 if (error < 0)
1536 return error;
1537 }
1538 }
1539
1540 return 0;
1541}
1542
28a0741f
PS
1543int git_odb__error_mismatch(const git_oid *expected, const git_oid *actual)
1544{
1545 char expected_oid[GIT_OID_HEXSZ + 1], actual_oid[GIT_OID_HEXSZ + 1];
1546
1547 git_oid_tostr(expected_oid, sizeof(expected_oid), expected);
1548 git_oid_tostr(actual_oid, sizeof(actual_oid), actual);
1549
ac3d33df 1550 git_error_set(GIT_ERROR_ODB, "object hash mismatch - expected %s but got %s",
28a0741f
PS
1551 expected_oid, actual_oid);
1552
1553 return GIT_EMISMATCH;
1554}
1555
e10144ae
ET
1556int git_odb__error_notfound(
1557 const char *message, const git_oid *oid, size_t oid_len)
e1de726c 1558{
282283ac
RB
1559 if (oid != NULL) {
1560 char oid_str[GIT_OID_HEXSZ + 1];
2076d329 1561 git_oid_tostr(oid_str, oid_len+1, oid);
ac3d33df 1562 git_error_set(GIT_ERROR_ODB, "object not found - %s (%.*s)",
901434b0 1563 message, (int) oid_len, oid_str);
282283ac 1564 } else
ac3d33df 1565 git_error_set(GIT_ERROR_ODB, "object not found - %s", message);
282283ac 1566
904b67e6 1567 return GIT_ENOTFOUND;
e1de726c
RB
1568}
1569
eae0bfdc
PP
1570static int error_null_oid(int error, const char *message)
1571{
ac3d33df 1572 git_error_set(GIT_ERROR_ODB, "odb: %s: null OID cannot exist", message);
eae0bfdc
PP
1573 return error;
1574}
1575
e1de726c
RB
1576int git_odb__error_ambiguous(const char *message)
1577{
ac3d33df 1578 git_error_set(GIT_ERROR_ODB, "ambiguous SHA1 prefix - %s", message);
904b67e6 1579 return GIT_EAMBIGUOUS;
7b6e8067
RJ
1580}
1581
bc91347b 1582int git_odb_init_backend(git_odb_backend *backend, unsigned int version)
b9f81997 1583{
bc91347b
RB
1584 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1585 backend, version, git_odb_backend, GIT_ODB_BACKEND_INIT);
1586 return 0;
b9f81997 1587}