]>
Commit | Line | Data |
---|---|---|
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 |
35 | bool git_odb__strict_hash_verification = true; |
36 | ||
d4b5a4e2 VM |
37 | typedef 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 |
45 | static 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 | 55 | static int odb_otype_fast(git_object_t *type_p, git_odb *db, const git_oid *id); |
85e7efa1 | 56 | static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth); |
eae0bfdc | 57 | static int error_null_oid(int error, const char *message); |
85e7efa1 | 58 | |
ac3d33df | 59 | static 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 | 70 | static 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 |
88 | int 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 | 110 | int 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 | 142 | static 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 | 156 | void 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 |
164 | const git_oid *git_odb_object_id(git_odb_object *object) |
165 | { | |
166 | return &object->cached.oid; | |
167 | } | |
168 | ||
169 | const void *git_odb_object_data(git_odb_object *object) | |
170 | { | |
8842c75f | 171 | return object->buffer; |
1881f078 VM |
172 | } |
173 | ||
174 | size_t git_odb_object_size(git_odb_object *object) | |
175 | { | |
8842c75f | 176 | return object->cached.size; |
1881f078 VM |
177 | } |
178 | ||
ac3d33df | 179 | git_object_t git_odb_object_type(git_odb_object *object) |
1881f078 | 180 | { |
8842c75f | 181 | return object->cached.type; |
1881f078 VM |
182 | } |
183 | ||
98fec8a9 VM |
184 | int 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 | 191 | void 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 | 199 | int 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 | 241 | done: |
603bee07 | 242 | git_hash_ctx_cleanup(&ctx); |
d6fb0924 | 243 | return error; |
c52736fa VM |
244 | } |
245 | ||
60b9d3fc | 246 | int 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 |
275 | int 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 | 321 | int 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 | 339 | int 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 | ||
356 | typedef 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 | 363 | static 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 | ||
369 | static 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 | ||
380 | static 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 | 388 | static 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 | 426 | static 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 | 441 | int 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 |
461 | static 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 |
492 | int 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 | ||
497 | int 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 |
502 | size_t git_odb_num_backends(git_odb *odb) |
503 | { | |
504 | assert(odb); | |
505 | return odb->backends.length; | |
506 | } | |
507 | ||
f063f578 RB |
508 | static 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 |
516 | int 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 | 532 | int 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 | 579 | static 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 |
632 | int 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 | 637 | int 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 |
657 | int 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 | 675 | static 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 |
695 | void 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 |
703 | static 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 |
725 | static 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 | 749 | int 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 | 763 | int 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 | ||
787 | static 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 |
829 | int 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 | 864 | int 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 | 930 | int 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 | 943 | static 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 | 986 | int 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 |
1035 | static 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 | |
1090 | out: | |
1091 | if (error) | |
1092 | git__free(raw.data); | |
1093 | return error; | |
2cdc4544 RJ |
1094 | } |
1095 | ||
43820f20 VM |
1096 | int 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 | 1120 | static 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 |
1147 | static 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 | |
1220 | out: | |
1221 | if (error) | |
1222 | git__free(raw.data); | |
1223 | ||
1224 | return error; | |
dd453c4d MP |
1225 | } |
1226 | ||
43820f20 VM |
1227 | int 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 | 1260 | int 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 | 1275 | int 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 | 1321 | static 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 | 1334 | int 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 | 1380 | done: |
eae0bfdc PP |
1381 | if (error) |
1382 | git__free(ctx); | |
e1de726c | 1383 | return error; |
72a3fe42 VM |
1384 | } |
1385 | ||
031f3f80 | 1386 | static 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 |
1399 | int 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 | ||
1412 | int 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 | ||
1426 | int git_odb_stream_read(git_odb_stream *stream, char *buffer, size_t len) | |
1427 | { | |
1428 | return stream->read(stream, buffer, len); | |
1429 | } | |
1430 | ||
1431 | void 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 |
1441 | int 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 | 1471 | int 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 | 1500 | void *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 |
1506 | int 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 |
1525 | int 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 |
1538 | int 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 |
1552 | static 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 |
1558 | int 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 | 1564 | int 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 | } |