]>
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" |
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 |
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, | |
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 | 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 | { |
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 | ||
340 | done: | |
18e5b854 | 341 | p_close(fd); |
0c9c969a | 342 | return error; |
18e5b854 VM |
343 | } |
344 | ||
ac3d33df | 345 | int 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 | ||
362 | typedef 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 | 369 | static 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 | ||
375 | static 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 | ||
386 | static 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 | 394 | static 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 | 432 | static 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 | 447 | int 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 |
467 | static 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 |
498 | int 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 | ||
503 | int 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 |
508 | size_t git_odb_num_backends(git_odb *odb) |
509 | { | |
510 | assert(odb); | |
511 | return odb->backends.length; | |
512 | } | |
513 | ||
f063f578 RB |
514 | static 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 |
522 | int 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 | 538 | int 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 | 586 | static 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 |
639 | int 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 | 644 | int 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 |
664 | int 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 | 682 | static 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 |
702 | void 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 |
710 | static 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 |
732 | static 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 | 756 | int 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 | 770 | int 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 | ||
794 | static 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 |
836 | int 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 | 871 | int 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 | 937 | int 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 | 950 | static 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 | 993 | int 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 |
1042 | static 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 | |
1097 | out: | |
1098 | if (error) | |
1099 | git__free(raw.data); | |
1100 | return error; | |
2cdc4544 RJ |
1101 | } |
1102 | ||
43820f20 VM |
1103 | int 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 | 1127 | static 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 |
1154 | static 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 | |
1227 | out: | |
1228 | if (error) | |
1229 | git__free(raw.data); | |
1230 | ||
1231 | return error; | |
dd453c4d MP |
1232 | } |
1233 | ||
43820f20 VM |
1234 | int 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 | 1267 | int 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 | 1282 | int 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 | 1328 | static 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 | 1341 | int 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 | 1387 | done: |
eae0bfdc PP |
1388 | if (error) |
1389 | git__free(ctx); | |
e1de726c | 1390 | return error; |
72a3fe42 VM |
1391 | } |
1392 | ||
031f3f80 | 1393 | static 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 |
1406 | int 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 | ||
1419 | int 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 | ||
1433 | int git_odb_stream_read(git_odb_stream *stream, char *buffer, size_t len) | |
1434 | { | |
1435 | return stream->read(stream, buffer, len); | |
1436 | } | |
1437 | ||
1438 | void 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 |
1448 | int 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 | 1478 | int 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 | 1507 | void *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 |
1513 | void *git_odb_backend_malloc(git_odb_backend *backend, size_t len) |
1514 | { | |
1515 | return git_odb_backend_data_alloc(backend, len); | |
1516 | } | |
1517 | ||
1518 | void git_odb_backend_data_free(git_odb_backend *backend, void *data) | |
1519 | { | |
1520 | GIT_UNUSED(backend); | |
1521 | git__free(data); | |
1522 | } | |
1523 | ||
4a863c06 VM |
1524 | int 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 |
1543 | int 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 |
1556 | int 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 |
1570 | static 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 |
1576 | int 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 | 1582 | int 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 | } |