1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
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.
6  */
7 
8 #include "odb.h"
9 
10 #include <zlib.h>
11 #include "git2/object.h"
12 #include "git2/sys/odb_backend.h"
13 #include "futils.h"
14 #include "hash.h"
15 #include "delta.h"
16 #include "filter.h"
17 #include "repository.h"
18 #include "blob.h"
19 
20 #include "git2/odb_backend.h"
21 #include "git2/oid.h"
22 #include "git2/oidarray.h"
23 
24 #define GIT_ALTERNATES_FILE "info/alternates"
25 
26 #define GIT_ALTERNATES_MAX_DEPTH 5
27 
28 /*
29  * We work under the assumption that most objects for long-running
30  * operations will be packed
31  */
32 int git_odb__loose_priority = GIT_ODB_DEFAULT_LOOSE_PRIORITY;
33 int git_odb__packed_priority = GIT_ODB_DEFAULT_PACKED_PRIORITY;
34 
35 bool git_odb__strict_hash_verification = true;
36 
37 typedef struct
38 {
39 	git_odb_backend *backend;
40 	int priority;
41 	bool is_alternate;
42 	ino_t disk_inode;
43 } backend_internal;
44 
odb_cache(git_odb * odb)45 static git_cache *odb_cache(git_odb *odb)
46 {
47 	git_repository *owner = GIT_REFCOUNT_OWNER(odb);
48 	if (owner != NULL) {
49 		return &owner->objects;
50 	}
51 
52 	return &odb->own_cache;
53 }
54 
55 static int odb_otype_fast(git_object_t *type_p, git_odb *db, const git_oid *id);
56 static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth);
57 static int error_null_oid(int error, const char *message);
58 
odb_hardcoded_type(const git_oid * id)59 static git_object_t odb_hardcoded_type(const git_oid *id)
60 {
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 
64 	if (!git_oid_cmp(id, &empty_tree))
65 		return GIT_OBJECT_TREE;
66 
67 	return GIT_OBJECT_INVALID;
68 }
69 
odb_read_hardcoded(bool * found,git_rawobj * raw,const git_oid * id)70 static int odb_read_hardcoded(bool *found, git_rawobj *raw, const git_oid *id)
71 {
72 	git_object_t type;
73 
74 	*found = false;
75 
76 	if ((type = odb_hardcoded_type(id)) == GIT_OBJECT_INVALID)
77 		return 0;
78 
79 	raw->type = type;
80 	raw->len = 0;
81 	raw->data = git__calloc(1, sizeof(uint8_t));
82 	GIT_ERROR_CHECK_ALLOC(raw->data);
83 
84 	*found = true;
85 	return 0;
86 }
87 
git_odb__format_object_header(size_t * written,char * hdr,size_t hdr_size,git_object_size_t obj_len,git_object_t obj_type)88 int git_odb__format_object_header(
89 	size_t *written,
90 	char *hdr,
91 	size_t hdr_size,
92 	git_object_size_t obj_len,
93 	git_object_t obj_type)
94 {
95 	const char *type_str = git_object_type2string(obj_type);
96 	int hdr_max = (hdr_size > INT_MAX-2) ? (INT_MAX-2) : (int)hdr_size;
97 	int len;
98 
99 	len = p_snprintf(hdr, hdr_max, "%s %"PRId64, type_str, (int64_t)obj_len);
100 
101 	if (len < 0 || len >= hdr_max) {
102 		git_error_set(GIT_ERROR_OS, "object header creation failed");
103 		return -1;
104 	}
105 
106 	*written = (size_t)(len + 1);
107 	return 0;
108 }
109 
git_odb__hashobj(git_oid * id,git_rawobj * obj)110 int git_odb__hashobj(git_oid *id, git_rawobj *obj)
111 {
112 	git_buf_vec vec[2];
113 	char header[64];
114 	size_t hdrlen;
115 	int error;
116 
117 	GIT_ASSERT_ARG(id);
118 	GIT_ASSERT_ARG(obj);
119 
120 	if (!git_object_typeisloose(obj->type)) {
121 		git_error_set(GIT_ERROR_INVALID, "invalid object type");
122 		return -1;
123 	}
124 
125 	if (!obj->data && obj->len != 0) {
126 		git_error_set(GIT_ERROR_INVALID, "invalid object");
127 		return -1;
128 	}
129 
130 	if ((error = git_odb__format_object_header(&hdrlen,
131 		header, sizeof(header), obj->len, obj->type)) < 0)
132 		return error;
133 
134 	vec[0].data = header;
135 	vec[0].len = hdrlen;
136 	vec[1].data = obj->data;
137 	vec[1].len = obj->len;
138 
139 	return git_hash_vec(id, vec, 2);
140 }
141 
142 
odb_object__alloc(const git_oid * oid,git_rawobj * source)143 static git_odb_object *odb_object__alloc(const git_oid *oid, git_rawobj *source)
144 {
145 	git_odb_object *object = git__calloc(1, sizeof(git_odb_object));
146 
147 	if (object != NULL) {
148 		git_oid_cpy(&object->cached.oid, oid);
149 		object->cached.type = source->type;
150 		object->cached.size = source->len;
151 		object->buffer      = source->data;
152 	}
153 
154 	return object;
155 }
156 
git_odb_object__free(void * object)157 void git_odb_object__free(void *object)
158 {
159 	if (object != NULL) {
160 		git__free(((git_odb_object *)object)->buffer);
161 		git__free(object);
162 	}
163 }
164 
git_odb_object_id(git_odb_object * object)165 const git_oid *git_odb_object_id(git_odb_object *object)
166 {
167 	return &object->cached.oid;
168 }
169 
git_odb_object_data(git_odb_object * object)170 const void *git_odb_object_data(git_odb_object *object)
171 {
172 	return object->buffer;
173 }
174 
git_odb_object_size(git_odb_object * object)175 size_t git_odb_object_size(git_odb_object *object)
176 {
177 	return object->cached.size;
178 }
179 
git_odb_object_type(git_odb_object * object)180 git_object_t git_odb_object_type(git_odb_object *object)
181 {
182 	return object->cached.type;
183 }
184 
git_odb_object_dup(git_odb_object ** dest,git_odb_object * source)185 int git_odb_object_dup(git_odb_object **dest, git_odb_object *source)
186 {
187 	git_cached_obj_incref(source);
188 	*dest = source;
189 	return 0;
190 }
191 
git_odb_object_free(git_odb_object * object)192 void git_odb_object_free(git_odb_object *object)
193 {
194 	if (object == NULL)
195 		return;
196 
197 	git_cached_obj_decref(object);
198 }
199 
git_odb__hashfd(git_oid * out,git_file fd,size_t size,git_object_t type)200 int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_object_t type)
201 {
202 	size_t hdr_len;
203 	char hdr[64], buffer[FILEIO_BUFSIZE];
204 	git_hash_ctx ctx;
205 	ssize_t read_len = 0;
206 	int error = 0;
207 
208 	if (!git_object_typeisloose(type)) {
209 		git_error_set(GIT_ERROR_INVALID, "invalid object type for hash");
210 		return -1;
211 	}
212 
213 	if ((error = git_hash_ctx_init(&ctx)) < 0)
214 		return error;
215 
216 	if ((error = git_odb__format_object_header(&hdr_len, hdr,
217 		sizeof(hdr), size, type)) < 0)
218 		goto done;
219 
220 	if ((error = git_hash_update(&ctx, hdr, hdr_len)) < 0)
221 		goto done;
222 
223 	while (size > 0 && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) {
224 		if ((error = git_hash_update(&ctx, buffer, read_len)) < 0)
225 			goto done;
226 
227 		size -= read_len;
228 	}
229 
230 	/* If p_read returned an error code, the read obviously failed.
231 	 * If size is not zero, the file was truncated after we originally
232 	 * stat'd it, so we consider this a read failure too */
233 	if (read_len < 0 || size > 0) {
234 		git_error_set(GIT_ERROR_OS, "error reading file for hashing");
235 		error = -1;
236 
237 		goto done;
238 	}
239 
240 	error = git_hash_final(out, &ctx);
241 
242 done:
243 	git_hash_ctx_cleanup(&ctx);
244 	return error;
245 }
246 
git_odb__hashfd_filtered(git_oid * out,git_file fd,size_t size,git_object_t type,git_filter_list * fl)247 int git_odb__hashfd_filtered(
248 	git_oid *out, git_file fd, size_t size, git_object_t type, git_filter_list *fl)
249 {
250 	int error;
251 	git_buf raw = GIT_BUF_INIT;
252 
253 	if (!fl)
254 		return git_odb__hashfd(out, fd, size, type);
255 
256 	/* size of data is used in header, so we have to read the whole file
257 	 * into memory to apply filters before beginning to calculate the hash
258 	 */
259 
260 	if (!(error = git_futils_readbuffer_fd(&raw, fd, size))) {
261 		git_buf post = GIT_BUF_INIT;
262 
263 		error = git_filter_list__convert_buf(&post, fl, &raw);
264 
265 		if (!error)
266 			error = git_odb_hash(out, post.ptr, post.size, type);
267 
268 		git_buf_dispose(&post);
269 	}
270 
271 	return error;
272 }
273 
git_odb__hashlink(git_oid * out,const char * path)274 int git_odb__hashlink(git_oid *out, const char *path)
275 {
276 	struct stat st;
277 	int size;
278 	int result;
279 
280 	if (git_path_lstat(path, &st) < 0)
281 		return -1;
282 
283 	if (!git__is_int(st.st_size) || (int)st.st_size < 0) {
284 		git_error_set(GIT_ERROR_FILESYSTEM, "file size overflow for 32-bit systems");
285 		return -1;
286 	}
287 
288 	size = (int)st.st_size;
289 
290 	if (S_ISLNK(st.st_mode)) {
291 		char *link_data;
292 		int read_len;
293 		size_t alloc_size;
294 
295 		GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size, size, 1);
296 		link_data = git__malloc(alloc_size);
297 		GIT_ERROR_CHECK_ALLOC(link_data);
298 
299 		read_len = p_readlink(path, link_data, size);
300 		if (read_len == -1) {
301 			git_error_set(GIT_ERROR_OS, "failed to read symlink data for '%s'", path);
302 			git__free(link_data);
303 			return -1;
304 		}
305 		GIT_ASSERT(read_len <= size);
306 		link_data[read_len] = '\0';
307 
308 		result = git_odb_hash(out, link_data, read_len, GIT_OBJECT_BLOB);
309 		git__free(link_data);
310 	} else {
311 		int fd = git_futils_open_ro(path);
312 		if (fd < 0)
313 			return -1;
314 		result = git_odb__hashfd(out, fd, size, GIT_OBJECT_BLOB);
315 		p_close(fd);
316 	}
317 
318 	return result;
319 }
320 
git_odb_hashfile(git_oid * out,const char * path,git_object_t type)321 int git_odb_hashfile(git_oid *out, const char *path, git_object_t type)
322 {
323 	uint64_t size;
324 	int fd, error = 0;
325 
326 	if ((fd = git_futils_open_ro(path)) < 0)
327 		return fd;
328 
329 	if ((error = git_futils_filesize(&size, fd)) < 0)
330 		goto done;
331 
332 	if (!git__is_sizet(size)) {
333 		git_error_set(GIT_ERROR_OS, "file size overflow for 32-bit systems");
334 		error = -1;
335 		goto done;
336 	}
337 
338 	error = git_odb__hashfd(out, fd, (size_t)size, type);
339 
340 done:
341 	p_close(fd);
342 	return error;
343 }
344 
git_odb_hash(git_oid * id,const void * data,size_t len,git_object_t type)345 int git_odb_hash(git_oid *id, const void *data, size_t len, git_object_t type)
346 {
347 	git_rawobj raw;
348 
349 	GIT_ASSERT_ARG(id);
350 
351 	raw.data = (void *)data;
352 	raw.len = len;
353 	raw.type = type;
354 
355 	return git_odb__hashobj(id, &raw);
356 }
357 
358 /**
359  * FAKE WSTREAM
360  */
361 
362 typedef struct {
363 	git_odb_stream stream;
364 	char *buffer;
365 	size_t size, written;
366 	git_object_t type;
367 } fake_wstream;
368 
fake_wstream__fwrite(git_odb_stream * _stream,const git_oid * oid)369 static int fake_wstream__fwrite(git_odb_stream *_stream, const git_oid *oid)
370 {
371 	fake_wstream *stream = (fake_wstream *)_stream;
372 	return _stream->backend->write(_stream->backend, oid, stream->buffer, stream->size, stream->type);
373 }
374 
fake_wstream__write(git_odb_stream * _stream,const char * data,size_t len)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 
379 	GIT_ASSERT(stream->written + len <= stream->size);
380 
381 	memcpy(stream->buffer + stream->written, data, len);
382 	stream->written += len;
383 	return 0;
384 }
385 
fake_wstream__free(git_odb_stream * _stream)386 static void fake_wstream__free(git_odb_stream *_stream)
387 {
388 	fake_wstream *stream = (fake_wstream *)_stream;
389 
390 	git__free(stream->buffer);
391 	git__free(stream);
392 }
393 
init_fake_wstream(git_odb_stream ** stream_p,git_odb_backend * backend,git_object_size_t size,git_object_t type)394 static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, git_object_size_t size, git_object_t type)
395 {
396 	fake_wstream *stream;
397 	size_t blobsize;
398 
399 	GIT_ERROR_CHECK_BLOBSIZE(size);
400 	blobsize = (size_t)size;
401 
402 	stream = git__calloc(1, sizeof(fake_wstream));
403 	GIT_ERROR_CHECK_ALLOC(stream);
404 
405 	stream->size = blobsize;
406 	stream->type = type;
407 	stream->buffer = git__malloc(blobsize);
408 	if (stream->buffer == NULL) {
409 		git__free(stream);
410 		return -1;
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;
421 	return 0;
422 }
423 
424 /***********************************************************
425  *
426  * OBJECT DATABASE PUBLIC API
427  *
428  * Public calls for the ODB functionality
429  *
430  ***********************************************************/
431 
backend_sort_cmp(const void * a,const void * b)432 static int backend_sort_cmp(const void *a, const void *b)
433 {
434 	const backend_internal *backend_a = (const backend_internal *)(a);
435 	const backend_internal *backend_b = (const backend_internal *)(b);
436 
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);
445 }
446 
git_odb_new(git_odb ** out)447 int git_odb_new(git_odb **out)
448 {
449 	git_odb *db = git__calloc(1, sizeof(*db));
450 	GIT_ERROR_CHECK_ALLOC(db);
451 
452 	if (git_mutex_init(&db->lock) < 0) {
453 		git__free(db);
454 		return -1;
455 	}
456 	if (git_cache_init(&db->own_cache) < 0) {
457 		git_mutex_free(&db->lock);
458 		git__free(db);
459 		return -1;
460 	}
461 	if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) {
462 		git_cache_dispose(&db->own_cache);
463 		git_mutex_free(&db->lock);
464 		git__free(db);
465 		return -1;
466 	}
467 
468 	*out = db;
469 	GIT_REFCOUNT_INC(db);
470 	return 0;
471 }
472 
add_backend_internal(git_odb * odb,git_odb_backend * backend,int priority,bool is_alternate,ino_t disk_inode)473 static int add_backend_internal(
474 	git_odb *odb, git_odb_backend *backend,
475 	int priority, bool is_alternate, ino_t disk_inode)
476 {
477 	backend_internal *internal;
478 
479 	GIT_ASSERT_ARG(odb);
480 	GIT_ASSERT_ARG(backend);
481 
482 	GIT_ERROR_CHECK_VERSION(backend, GIT_ODB_BACKEND_VERSION, "git_odb_backend");
483 
484 	/* Check if the backend is already owned by another ODB */
485 	GIT_ASSERT(!backend->odb || backend->odb == odb);
486 
487 	internal = git__malloc(sizeof(backend_internal));
488 	GIT_ERROR_CHECK_ALLOC(internal);
489 
490 	internal->backend = backend;
491 	internal->priority = priority;
492 	internal->is_alternate = is_alternate;
493 	internal->disk_inode = disk_inode;
494 
495 	if (git_mutex_lock(&odb->lock) < 0) {
496 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
497 		return -1;
498 	}
499 	if (git_vector_insert(&odb->backends, internal) < 0) {
500 		git_mutex_unlock(&odb->lock);
501 		git__free(internal);
502 		return -1;
503 	}
504 	git_vector_sort(&odb->backends);
505 	internal->backend->odb = odb;
506 	git_mutex_unlock(&odb->lock);
507 	return 0;
508 }
509 
git_odb_add_backend(git_odb * odb,git_odb_backend * backend,int priority)510 int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority)
511 {
512 	return add_backend_internal(odb, backend, priority, false, 0);
513 }
514 
git_odb_add_alternate(git_odb * odb,git_odb_backend * backend,int priority)515 int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority)
516 {
517 	return add_backend_internal(odb, backend, priority, true, 0);
518 }
519 
git_odb_num_backends(git_odb * odb)520 size_t git_odb_num_backends(git_odb *odb)
521 {
522 	size_t length;
523 	bool locked = true;
524 
525 	GIT_ASSERT_ARG(odb);
526 
527 	if (git_mutex_lock(&odb->lock) < 0) {
528 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
529 		locked = false;
530 	}
531 	length = odb->backends.length;
532 	if (locked)
533 		git_mutex_unlock(&odb->lock);
534 	return length;
535 }
536 
git_odb__error_unsupported_in_backend(const char * action)537 static int git_odb__error_unsupported_in_backend(const char *action)
538 {
539 	git_error_set(GIT_ERROR_ODB,
540 		"cannot %s - unsupported in the loaded odb backends", action);
541 	return -1;
542 }
543 
544 
git_odb_get_backend(git_odb_backend ** out,git_odb * odb,size_t pos)545 int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos)
546 {
547 	backend_internal *internal;
548 	int error;
549 
550 	GIT_ASSERT_ARG(out);
551 	GIT_ASSERT_ARG(odb);
552 
553 
554 	if ((error = git_mutex_lock(&odb->lock)) < 0) {
555 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
556 		return error;
557 	}
558 	internal = git_vector_get(&odb->backends, pos);
559 
560 	if (!internal || !internal->backend) {
561 		git_mutex_unlock(&odb->lock);
562 
563 		git_error_set(GIT_ERROR_ODB, "no ODB backend loaded at index %" PRIuZ, pos);
564 		return GIT_ENOTFOUND;
565 	}
566 	*out = internal->backend;
567 	git_mutex_unlock(&odb->lock);
568 
569 	return 0;
570 }
571 
git_odb__add_default_backends(git_odb * db,const char * objects_dir,bool as_alternates,int alternate_depth)572 int git_odb__add_default_backends(
573 	git_odb *db, const char *objects_dir,
574 	bool as_alternates, int alternate_depth)
575 {
576 	size_t i = 0;
577 	struct stat st;
578 	ino_t inode;
579 	git_odb_backend *loose, *packed;
580 
581 	/* TODO: inodes are not really relevant on Win32, so we need to find
582 	 * a cross-platform workaround for this */
583 #ifdef GIT_WIN32
584 	GIT_UNUSED(i);
585 	GIT_UNUSED(&st);
586 
587 	inode = 0;
588 #else
589 	if (p_stat(objects_dir, &st) < 0) {
590 		if (as_alternates)
591 			/* this should warn */
592 			return 0;
593 
594 		git_error_set(GIT_ERROR_ODB, "failed to load object database in '%s'", objects_dir);
595 		return -1;
596 	}
597 
598 	inode = st.st_ino;
599 
600 	if (git_mutex_lock(&db->lock) < 0) {
601 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
602 		return -1;
603 	}
604 	for (i = 0; i < db->backends.length; ++i) {
605 		backend_internal *backend = git_vector_get(&db->backends, i);
606 		if (backend->disk_inode == inode) {
607 			git_mutex_unlock(&db->lock);
608 			return 0;
609 		}
610 	}
611 	git_mutex_unlock(&db->lock);
612 #endif
613 
614 	/* add the loose object backend */
615 	if (git_odb_backend_loose(&loose, objects_dir, -1, db->do_fsync, 0, 0) < 0 ||
616 		add_backend_internal(db, loose, git_odb__loose_priority, as_alternates, inode) < 0)
617 		return -1;
618 
619 	/* add the packed file backend */
620 	if (git_odb_backend_pack(&packed, objects_dir) < 0 ||
621 		add_backend_internal(db, packed, git_odb__packed_priority, as_alternates, inode) < 0)
622 		return -1;
623 
624 	if (git_mutex_lock(&db->lock) < 0) {
625 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
626 		return -1;
627 	}
628 	if (!db->cgraph && git_commit_graph_new(&db->cgraph, objects_dir, false) < 0) {
629 		git_mutex_unlock(&db->lock);
630 		return -1;
631 	}
632 	git_mutex_unlock(&db->lock);
633 
634 	return load_alternates(db, objects_dir, alternate_depth);
635 }
636 
load_alternates(git_odb * odb,const char * objects_dir,int alternate_depth)637 static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth)
638 {
639 	git_buf alternates_path = GIT_BUF_INIT;
640 	git_buf alternates_buf = GIT_BUF_INIT;
641 	char *buffer;
642 	const char *alternate;
643 	int result = 0;
644 
645 	/* Git reports an error, we just ignore anything deeper */
646 	if (alternate_depth > GIT_ALTERNATES_MAX_DEPTH)
647 		return 0;
648 
649 	if (git_buf_joinpath(&alternates_path, objects_dir, GIT_ALTERNATES_FILE) < 0)
650 		return -1;
651 
652 	if (git_path_exists(alternates_path.ptr) == false) {
653 		git_buf_dispose(&alternates_path);
654 		return 0;
655 	}
656 
657 	if (git_futils_readbuffer(&alternates_buf, alternates_path.ptr) < 0) {
658 		git_buf_dispose(&alternates_path);
659 		return -1;
660 	}
661 
662 	buffer = (char *)alternates_buf.ptr;
663 
664 	/* add each alternate as a new backend; one alternate per line */
665 	while ((alternate = git__strtok(&buffer, "\r\n")) != NULL) {
666 		if (*alternate == '\0' || *alternate == '#')
667 			continue;
668 
669 		/*
670 		 * Relative path: build based on the current `objects`
671 		 * folder. However, relative paths are only allowed in
672 		 * the current repository.
673 		 */
674 		if (*alternate == '.' && !alternate_depth) {
675 			if ((result = git_buf_joinpath(&alternates_path, objects_dir, alternate)) < 0)
676 				break;
677 			alternate = git_buf_cstr(&alternates_path);
678 		}
679 
680 		if ((result = git_odb__add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0)
681 			break;
682 	}
683 
684 	git_buf_dispose(&alternates_path);
685 	git_buf_dispose(&alternates_buf);
686 
687 	return result;
688 }
689 
git_odb_add_disk_alternate(git_odb * odb,const char * path)690 int git_odb_add_disk_alternate(git_odb *odb, const char *path)
691 {
692 	return git_odb__add_default_backends(odb, path, true, 0);
693 }
694 
git_odb_set_commit_graph(git_odb * odb,git_commit_graph * cgraph)695 int git_odb_set_commit_graph(git_odb *odb, git_commit_graph *cgraph)
696 {
697 	int error = 0;
698 
699 	GIT_ASSERT_ARG(odb);
700 
701 	if ((error = git_mutex_lock(&odb->lock)) < 0) {
702 		git_error_set(GIT_ERROR_ODB, "failed to acquire the db lock");
703 		return error;
704 	}
705 	git_commit_graph_free(odb->cgraph);
706 	odb->cgraph = cgraph;
707 	git_mutex_unlock(&odb->lock);
708 
709 	return error;
710 }
711 
git_odb_open(git_odb ** out,const char * objects_dir)712 int git_odb_open(git_odb **out, const char *objects_dir)
713 {
714 	git_odb *db;
715 
716 	GIT_ASSERT_ARG(out);
717 	GIT_ASSERT_ARG(objects_dir);
718 
719 	*out = NULL;
720 
721 	if (git_odb_new(&db) < 0)
722 		return -1;
723 
724 	if (git_odb__add_default_backends(db, objects_dir, 0, 0) < 0) {
725 		git_odb_free(db);
726 		return -1;
727 	}
728 
729 	*out = db;
730 	return 0;
731 }
732 
git_odb__set_caps(git_odb * odb,int caps)733 int git_odb__set_caps(git_odb *odb, int caps)
734 {
735 	if (caps == GIT_ODB_CAP_FROM_OWNER) {
736 		git_repository *repo = GIT_REFCOUNT_OWNER(odb);
737 		int val;
738 
739 		if (!repo) {
740 			git_error_set(GIT_ERROR_ODB, "cannot access repository to set odb caps");
741 			return -1;
742 		}
743 
744 		if (!git_repository__configmap_lookup(&val, repo, GIT_CONFIGMAP_FSYNCOBJECTFILES))
745 			odb->do_fsync = !!val;
746 	}
747 
748 	return 0;
749 }
750 
odb_free(git_odb * db)751 static void odb_free(git_odb *db)
752 {
753 	size_t i;
754 	bool locked = true;
755 
756 	if (git_mutex_lock(&db->lock) < 0) {
757 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
758 		locked = false;
759 	}
760 	for (i = 0; i < db->backends.length; ++i) {
761 		backend_internal *internal = git_vector_get(&db->backends, i);
762 		git_odb_backend *backend = internal->backend;
763 
764 		backend->free(backend);
765 
766 		git__free(internal);
767 	}
768 	if (locked)
769 		git_mutex_unlock(&db->lock);
770 
771 	git_commit_graph_free(db->cgraph);
772 	git_vector_free(&db->backends);
773 	git_cache_dispose(&db->own_cache);
774 	git_mutex_free(&db->lock);
775 
776 	git__memzero(db, sizeof(*db));
777 	git__free(db);
778 }
779 
git_odb_free(git_odb * db)780 void git_odb_free(git_odb *db)
781 {
782 	if (db == NULL)
783 		return;
784 
785 	GIT_REFCOUNT_DEC(db, odb_free);
786 }
787 
odb_exists_1(git_odb * db,const git_oid * id,bool only_refreshed)788 static int odb_exists_1(
789 	git_odb *db,
790 	const git_oid *id,
791 	bool only_refreshed)
792 {
793 	size_t i;
794 	bool found = false;
795 	int error;
796 
797 	if ((error = git_mutex_lock(&db->lock)) < 0) {
798 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
799 		return error;
800 	}
801 	for (i = 0; i < db->backends.length && !found; ++i) {
802 		backend_internal *internal = git_vector_get(&db->backends, i);
803 		git_odb_backend *b = internal->backend;
804 
805 		if (only_refreshed && !b->refresh)
806 			continue;
807 
808 		if (b->exists != NULL)
809 			found = (bool)b->exists(b, id);
810 	}
811 	git_mutex_unlock(&db->lock);
812 
813 	return (int)found;
814 }
815 
git_odb__get_commit_graph_file(git_commit_graph_file ** out,git_odb * db)816 int git_odb__get_commit_graph_file(git_commit_graph_file **out, git_odb *db)
817 {
818 	int error = 0;
819 	git_commit_graph_file *result = NULL;
820 
821 	if ((error = git_mutex_lock(&db->lock)) < 0) {
822 		git_error_set(GIT_ERROR_ODB, "failed to acquire the db lock");
823 		return error;
824 	}
825 	if (!db->cgraph) {
826 		error = GIT_ENOTFOUND;
827 		goto done;
828 	}
829 	error = git_commit_graph_get_file(&result, db->cgraph);
830 	if (error)
831 		goto done;
832 	*out = result;
833 
834 done:
835 	git_mutex_unlock(&db->lock);
836 	return error;
837 }
838 
odb_freshen_1(git_odb * db,const git_oid * id,bool only_refreshed)839 static int odb_freshen_1(
840 	git_odb *db,
841 	const git_oid *id,
842 	bool only_refreshed)
843 {
844 	size_t i;
845 	bool found = false;
846 	int error;
847 
848 	if ((error = git_mutex_lock(&db->lock)) < 0) {
849 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
850 		return error;
851 	}
852 	for (i = 0; i < db->backends.length && !found; ++i) {
853 		backend_internal *internal = git_vector_get(&db->backends, i);
854 		git_odb_backend *b = internal->backend;
855 
856 		if (only_refreshed && !b->refresh)
857 			continue;
858 
859 		if (b->freshen != NULL)
860 			found = !b->freshen(b, id);
861 		else if (b->exists != NULL)
862 			found = b->exists(b, id);
863 	}
864 	git_mutex_unlock(&db->lock);
865 
866 	return (int)found;
867 }
868 
git_odb__freshen(git_odb * db,const git_oid * id)869 int git_odb__freshen(git_odb *db, const git_oid *id)
870 {
871 	GIT_ASSERT_ARG(db);
872 	GIT_ASSERT_ARG(id);
873 
874 	if (odb_freshen_1(db, id, false))
875 		return 1;
876 
877 	if (!git_odb_refresh(db))
878 		return odb_freshen_1(db, id, true);
879 
880 	/* Failed to refresh, hence not found */
881 	return 0;
882 }
883 
git_odb_exists(git_odb * db,const git_oid * id)884 int git_odb_exists(git_odb *db, const git_oid *id)
885 {
886 	git_odb_object *object;
887 
888 	GIT_ASSERT_ARG(db);
889 	GIT_ASSERT_ARG(id);
890 
891 	if (git_oid_is_zero(id))
892 		return 0;
893 
894 	if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
895 		git_odb_object_free(object);
896 		return 1;
897 	}
898 
899 	if (odb_exists_1(db, id, false))
900 		return 1;
901 
902 	if (!git_odb_refresh(db))
903 		return odb_exists_1(db, id, true);
904 
905 	/* Failed to refresh, hence not found */
906 	return 0;
907 }
908 
odb_exists_prefix_1(git_oid * out,git_odb * db,const git_oid * key,size_t len,bool only_refreshed)909 static int odb_exists_prefix_1(git_oid *out, git_odb *db,
910 	const git_oid *key, size_t len, bool only_refreshed)
911 {
912 	size_t i;
913 	int error = GIT_ENOTFOUND, num_found = 0;
914 	git_oid last_found = {{0}}, found;
915 
916 	if ((error = git_mutex_lock(&db->lock)) < 0) {
917 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
918 		return error;
919 	}
920 	error = GIT_ENOTFOUND;
921 	for (i = 0; i < db->backends.length; ++i) {
922 		backend_internal *internal = git_vector_get(&db->backends, i);
923 		git_odb_backend *b = internal->backend;
924 
925 		if (only_refreshed && !b->refresh)
926 			continue;
927 
928 		if (!b->exists_prefix)
929 			continue;
930 
931 		error = b->exists_prefix(&found, b, key, len);
932 		if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH)
933 			continue;
934 		if (error) {
935 			git_mutex_unlock(&db->lock);
936 			return error;
937 		}
938 
939 		/* make sure found item doesn't introduce ambiguity */
940 		if (num_found) {
941 			if (git_oid__cmp(&last_found, &found)) {
942 				git_mutex_unlock(&db->lock);
943 				return git_odb__error_ambiguous("multiple matches for prefix");
944 			}
945 		} else {
946 			git_oid_cpy(&last_found, &found);
947 			num_found++;
948 		}
949 	}
950 	git_mutex_unlock(&db->lock);
951 
952 	if (!num_found)
953 		return GIT_ENOTFOUND;
954 
955 	if (out)
956 		git_oid_cpy(out, &last_found);
957 
958 	return 0;
959 }
960 
git_odb_exists_prefix(git_oid * out,git_odb * db,const git_oid * short_id,size_t len)961 int git_odb_exists_prefix(
962 	git_oid *out, git_odb *db, const git_oid *short_id, size_t len)
963 {
964 	int error;
965 	git_oid key = {{0}};
966 
967 	GIT_ASSERT_ARG(db);
968 	GIT_ASSERT_ARG(short_id);
969 
970 	if (len < GIT_OID_MINPREFIXLEN)
971 		return git_odb__error_ambiguous("prefix length too short");
972 
973 	if (len >= GIT_OID_HEXSZ) {
974 		if (git_odb_exists(db, short_id)) {
975 			if (out)
976 				git_oid_cpy(out, short_id);
977 			return 0;
978 		} else {
979 			return git_odb__error_notfound(
980 				"no match for id prefix", short_id, len);
981 		}
982 	}
983 
984 	git_oid__cpy_prefix(&key, short_id, len);
985 
986 	error = odb_exists_prefix_1(out, db, &key, len, false);
987 
988 	if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
989 		error = odb_exists_prefix_1(out, db, &key, len, true);
990 
991 	if (error == GIT_ENOTFOUND)
992 		return git_odb__error_notfound("no match for id prefix", &key, len);
993 
994 	return error;
995 }
996 
git_odb_expand_ids(git_odb * db,git_odb_expand_id * ids,size_t count)997 int git_odb_expand_ids(
998 	git_odb *db,
999 	git_odb_expand_id *ids,
1000 	size_t count)
1001 {
1002 	size_t i;
1003 
1004 	GIT_ASSERT_ARG(db);
1005 	GIT_ASSERT_ARG(ids);
1006 
1007 	for (i = 0; i < count; i++) {
1008 		git_odb_expand_id *query = &ids[i];
1009 		int error = GIT_EAMBIGUOUS;
1010 
1011 		if (!query->type)
1012 			query->type = GIT_OBJECT_ANY;
1013 
1014 		/* if we have a short OID, expand it first */
1015 		if (query->length >= GIT_OID_MINPREFIXLEN && query->length < GIT_OID_HEXSZ) {
1016 			git_oid actual_id;
1017 
1018 			error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false);
1019 			if (!error) {
1020 				git_oid_cpy(&query->id, &actual_id);
1021 				query->length = GIT_OID_HEXSZ;
1022 			}
1023 		}
1024 
1025 		/*
1026 		 * now we ought to have a 40-char OID, either because we've expanded it
1027 		 * or because the user passed a full OID. Ensure its type is right.
1028 		 */
1029 		if (query->length >= GIT_OID_HEXSZ) {
1030 			git_object_t actual_type;
1031 
1032 			error = odb_otype_fast(&actual_type, db, &query->id);
1033 			if (!error) {
1034 				if (query->type != GIT_OBJECT_ANY && query->type != actual_type)
1035 					error = GIT_ENOTFOUND;
1036 				else
1037 					query->type = actual_type;
1038 			}
1039 		}
1040 
1041 		switch (error) {
1042 		/* no errors, so we've successfully expanded the OID */
1043 		case 0:
1044 			continue;
1045 
1046 		/* the object is missing or ambiguous */
1047 		case GIT_ENOTFOUND:
1048 		case GIT_EAMBIGUOUS:
1049 			memset(&query->id, 0, sizeof(git_oid));
1050 			query->length = 0;
1051 			query->type = 0;
1052 			break;
1053 
1054 		/* something went very wrong with the ODB; bail hard */
1055 		default:
1056 			return error;
1057 		}
1058 	}
1059 
1060 	git_error_clear();
1061 	return 0;
1062 }
1063 
git_odb_read_header(size_t * len_p,git_object_t * type_p,git_odb * db,const git_oid * id)1064 int git_odb_read_header(size_t *len_p, git_object_t *type_p, git_odb *db, const git_oid *id)
1065 {
1066 	int error;
1067 	git_odb_object *object;
1068 
1069 	error = git_odb__read_header_or_object(&object, len_p, type_p, db, id);
1070 
1071 	if (object)
1072 		git_odb_object_free(object);
1073 
1074 	return error;
1075 }
1076 
odb_read_header_1(size_t * len_p,git_object_t * type_p,git_odb * db,const git_oid * id,bool only_refreshed)1077 static int odb_read_header_1(
1078 	size_t *len_p, git_object_t *type_p, git_odb *db,
1079 	const git_oid *id, bool only_refreshed)
1080 {
1081 	size_t i;
1082 	git_object_t ht;
1083 	bool passthrough = false;
1084 	int error;
1085 
1086 	if (!only_refreshed && (ht = odb_hardcoded_type(id)) != GIT_OBJECT_INVALID) {
1087 		*type_p = ht;
1088 		*len_p = 0;
1089 		return 0;
1090 	}
1091 
1092 	if ((error = git_mutex_lock(&db->lock)) < 0) {
1093 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
1094 		return error;
1095 	}
1096 	for (i = 0; i < db->backends.length; ++i) {
1097 		backend_internal *internal = git_vector_get(&db->backends, i);
1098 		git_odb_backend *b = internal->backend;
1099 
1100 		if (only_refreshed && !b->refresh)
1101 			continue;
1102 
1103 		if (!b->read_header) {
1104 			passthrough = true;
1105 			continue;
1106 		}
1107 
1108 		error = b->read_header(len_p, type_p, b, id);
1109 
1110 		switch (error) {
1111 		case GIT_PASSTHROUGH:
1112 			passthrough = true;
1113 			break;
1114 		case GIT_ENOTFOUND:
1115 			break;
1116 		default:
1117 			git_mutex_unlock(&db->lock);
1118 			return error;
1119 		}
1120 	}
1121 	git_mutex_unlock(&db->lock);
1122 
1123 	return passthrough ? GIT_PASSTHROUGH : GIT_ENOTFOUND;
1124 }
1125 
git_odb__read_header_or_object(git_odb_object ** out,size_t * len_p,git_object_t * type_p,git_odb * db,const git_oid * id)1126 int git_odb__read_header_or_object(
1127 	git_odb_object **out, size_t *len_p, git_object_t *type_p,
1128 	git_odb *db, const git_oid *id)
1129 {
1130 	int error = GIT_ENOTFOUND;
1131 	git_odb_object *object;
1132 
1133 	GIT_ASSERT_ARG(db);
1134 	GIT_ASSERT_ARG(id);
1135 	GIT_ASSERT_ARG(out);
1136 	GIT_ASSERT_ARG(len_p);
1137 	GIT_ASSERT_ARG(type_p);
1138 
1139 	*out = NULL;
1140 
1141 	if (git_oid_is_zero(id))
1142 		return error_null_oid(GIT_ENOTFOUND, "cannot read object");
1143 
1144 	if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
1145 		*len_p = object->cached.size;
1146 		*type_p = object->cached.type;
1147 		*out = object;
1148 		return 0;
1149 	}
1150 
1151 	error = odb_read_header_1(len_p, type_p, db, id, false);
1152 
1153 	if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
1154 		error = odb_read_header_1(len_p, type_p, db, id, true);
1155 
1156 	if (error == GIT_ENOTFOUND)
1157 		return git_odb__error_notfound("cannot read header for", id, GIT_OID_HEXSZ);
1158 
1159 	/* we found the header; return early */
1160 	if (!error)
1161 		return 0;
1162 
1163 	if (error == GIT_PASSTHROUGH) {
1164 		/*
1165 		 * no backend has header-reading functionality
1166 		 * so try using `git_odb_read` instead
1167 		 */
1168 		error = git_odb_read(&object, db, id);
1169 		if (!error) {
1170 			*len_p = object->cached.size;
1171 			*type_p = object->cached.type;
1172 			*out = object;
1173 		}
1174 	}
1175 
1176 	return error;
1177 }
1178 
odb_read_1(git_odb_object ** out,git_odb * db,const git_oid * id,bool only_refreshed)1179 static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id,
1180 		bool only_refreshed)
1181 {
1182 	size_t i;
1183 	git_rawobj raw;
1184 	git_odb_object *object;
1185 	git_oid hashed;
1186 	bool found = false;
1187 	int error = 0;
1188 
1189 	if (!only_refreshed) {
1190 		if ((error = odb_read_hardcoded(&found, &raw, id)) < 0)
1191 			return error;
1192 	}
1193 
1194 	if ((error = git_mutex_lock(&db->lock)) < 0) {
1195 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
1196 		return error;
1197 	}
1198 	for (i = 0; i < db->backends.length && !found; ++i) {
1199 		backend_internal *internal = git_vector_get(&db->backends, i);
1200 		git_odb_backend *b = internal->backend;
1201 
1202 		if (only_refreshed && !b->refresh)
1203 			continue;
1204 
1205 		if (b->read != NULL) {
1206 			error = b->read(&raw.data, &raw.len, &raw.type, b, id);
1207 			if (error == GIT_PASSTHROUGH || error == GIT_ENOTFOUND)
1208 				continue;
1209 
1210 			if (error < 0) {
1211 				git_mutex_unlock(&db->lock);
1212 				return error;
1213 			}
1214 
1215 			found = true;
1216 		}
1217 	}
1218 	git_mutex_unlock(&db->lock);
1219 
1220 	if (!found)
1221 		return GIT_ENOTFOUND;
1222 
1223 	if (git_odb__strict_hash_verification) {
1224 		if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0)
1225 			goto out;
1226 
1227 		if (!git_oid_equal(id, &hashed)) {
1228 			error = git_odb__error_mismatch(id, &hashed);
1229 			goto out;
1230 		}
1231 	}
1232 
1233 	git_error_clear();
1234 	if ((object = odb_object__alloc(id, &raw)) == NULL) {
1235 		error = -1;
1236 		goto out;
1237 	}
1238 
1239 	*out = git_cache_store_raw(odb_cache(db), object);
1240 
1241 out:
1242 	if (error)
1243 		git__free(raw.data);
1244 	return error;
1245 }
1246 
git_odb_read(git_odb_object ** out,git_odb * db,const git_oid * id)1247 int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
1248 {
1249 	int error;
1250 
1251 	GIT_ASSERT_ARG(out);
1252 	GIT_ASSERT_ARG(db);
1253 	GIT_ASSERT_ARG(id);
1254 
1255 	if (git_oid_is_zero(id))
1256 		return error_null_oid(GIT_ENOTFOUND, "cannot read object");
1257 
1258 	*out = git_cache_get_raw(odb_cache(db), id);
1259 	if (*out != NULL)
1260 		return 0;
1261 
1262 	error = odb_read_1(out, db, id, false);
1263 
1264 	if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
1265 		error = odb_read_1(out, db, id, true);
1266 
1267 	if (error == GIT_ENOTFOUND)
1268 		return git_odb__error_notfound("no match for id", id, GIT_OID_HEXSZ);
1269 
1270 	return error;
1271 }
1272 
odb_otype_fast(git_object_t * type_p,git_odb * db,const git_oid * id)1273 static int odb_otype_fast(git_object_t *type_p, git_odb *db, const git_oid *id)
1274 {
1275 	git_odb_object *object;
1276 	size_t _unused;
1277 	int error;
1278 
1279 	if (git_oid_is_zero(id))
1280 		return error_null_oid(GIT_ENOTFOUND, "cannot get object type");
1281 
1282 	if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
1283 		*type_p = object->cached.type;
1284 		git_odb_object_free(object);
1285 		return 0;
1286 	}
1287 
1288 	error = odb_read_header_1(&_unused, type_p, db, id, false);
1289 
1290 	if (error == GIT_PASSTHROUGH) {
1291 		error = odb_read_1(&object, db, id, false);
1292 		if (!error)
1293 			*type_p = object->cached.type;
1294 		git_odb_object_free(object);
1295 	}
1296 
1297 	return error;
1298 }
1299 
read_prefix_1(git_odb_object ** out,git_odb * db,const git_oid * key,size_t len,bool only_refreshed)1300 static int read_prefix_1(git_odb_object **out, git_odb *db,
1301 		const git_oid *key, size_t len, bool only_refreshed)
1302 {
1303 	size_t i;
1304 	int error = 0;
1305 	git_oid found_full_oid = {{0}};
1306 	git_rawobj raw = {0};
1307 	void *data = NULL;
1308 	bool found = false;
1309 	git_odb_object *object;
1310 
1311 	if ((error = git_mutex_lock(&db->lock)) < 0) {
1312 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
1313 		return error;
1314 	}
1315 	for (i = 0; i < db->backends.length; ++i) {
1316 		backend_internal *internal = git_vector_get(&db->backends, i);
1317 		git_odb_backend *b = internal->backend;
1318 
1319 		if (only_refreshed && !b->refresh)
1320 			continue;
1321 
1322 		if (b->read_prefix != NULL) {
1323 			git_oid full_oid;
1324 			error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, key, len);
1325 
1326 			if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) {
1327 				error = 0;
1328 				continue;
1329 			}
1330 
1331 			if (error) {
1332 				git_mutex_unlock(&db->lock);
1333 				goto out;
1334 			}
1335 
1336 			git__free(data);
1337 			data = raw.data;
1338 
1339 			if (found && git_oid__cmp(&full_oid, &found_full_oid)) {
1340 				git_buf buf = GIT_BUF_INIT;
1341 
1342 				git_buf_printf(&buf, "multiple matches for prefix: %s",
1343 					git_oid_tostr_s(&full_oid));
1344 				git_buf_printf(&buf, " %s",
1345 					git_oid_tostr_s(&found_full_oid));
1346 
1347 				error = git_odb__error_ambiguous(buf.ptr);
1348 				git_buf_dispose(&buf);
1349 				git_mutex_unlock(&db->lock);
1350 				goto out;
1351 			}
1352 
1353 			found_full_oid = full_oid;
1354 			found = true;
1355 		}
1356 	}
1357 	git_mutex_unlock(&db->lock);
1358 
1359 	if (!found)
1360 		return GIT_ENOTFOUND;
1361 
1362 	if (git_odb__strict_hash_verification) {
1363 		git_oid hash;
1364 
1365 		if ((error = git_odb_hash(&hash, raw.data, raw.len, raw.type)) < 0)
1366 			goto out;
1367 
1368 		if (!git_oid_equal(&found_full_oid, &hash)) {
1369 			error = git_odb__error_mismatch(&found_full_oid, &hash);
1370 			goto out;
1371 		}
1372 	}
1373 
1374 	if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) {
1375 		error = -1;
1376 		goto out;
1377 	}
1378 
1379 	*out = git_cache_store_raw(odb_cache(db), object);
1380 
1381 out:
1382 	if (error)
1383 		git__free(raw.data);
1384 
1385 	return error;
1386 }
1387 
git_odb_read_prefix(git_odb_object ** out,git_odb * db,const git_oid * short_id,size_t len)1388 int git_odb_read_prefix(
1389 	git_odb_object **out, git_odb *db, const git_oid *short_id, size_t len)
1390 {
1391 	git_oid key = {{0}};
1392 	int error;
1393 
1394 	GIT_ASSERT_ARG(out);
1395 	GIT_ASSERT_ARG(db);
1396 
1397 	if (len < GIT_OID_MINPREFIXLEN)
1398 		return git_odb__error_ambiguous("prefix length too short");
1399 
1400 	if (len > GIT_OID_HEXSZ)
1401 		len = GIT_OID_HEXSZ;
1402 
1403 	if (len == GIT_OID_HEXSZ) {
1404 		*out = git_cache_get_raw(odb_cache(db), short_id);
1405 		if (*out != NULL)
1406 			return 0;
1407 	}
1408 
1409 	git_oid__cpy_prefix(&key, short_id, len);
1410 
1411 	error = read_prefix_1(out, db, &key, len, false);
1412 
1413 	if (error == GIT_ENOTFOUND && !git_odb_refresh(db))
1414 		error = read_prefix_1(out, db, &key, len, true);
1415 
1416 	if (error == GIT_ENOTFOUND)
1417 		return git_odb__error_notfound("no match for prefix", &key, len);
1418 
1419 	return error;
1420 }
1421 
git_odb_foreach(git_odb * db,git_odb_foreach_cb cb,void * payload)1422 int git_odb_foreach(git_odb *db, git_odb_foreach_cb cb, void *payload)
1423 {
1424 	unsigned int i;
1425 	git_vector backends = GIT_VECTOR_INIT;
1426 	backend_internal *internal;
1427 	int error = 0;
1428 
1429 	/* Make a copy of the backends vector to invoke the callback without holding the lock. */
1430 	if ((error = git_mutex_lock(&db->lock)) < 0) {
1431 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
1432 		goto cleanup;
1433 	}
1434 	error = git_vector_dup(&backends, &db->backends, NULL);
1435 	git_mutex_unlock(&db->lock);
1436 
1437 	if (error < 0)
1438 		goto cleanup;
1439 
1440 	git_vector_foreach(&backends, i, internal) {
1441 		git_odb_backend *b = internal->backend;
1442 		error = b->foreach(b, cb, payload);
1443 		if (error != 0)
1444 			goto cleanup;
1445 	}
1446 
1447 cleanup:
1448 	git_vector_free(&backends);
1449 
1450 	return error;
1451 }
1452 
git_odb_write(git_oid * oid,git_odb * db,const void * data,size_t len,git_object_t type)1453 int git_odb_write(
1454 	git_oid *oid, git_odb *db, const void *data, size_t len, git_object_t type)
1455 {
1456 	size_t i;
1457 	int error;
1458 	git_odb_stream *stream;
1459 
1460 	GIT_ASSERT_ARG(oid);
1461 	GIT_ASSERT_ARG(db);
1462 
1463 	if ((error = git_odb_hash(oid, data, len, type)) < 0)
1464 		return error;
1465 
1466 	if (git_oid_is_zero(oid))
1467 		return error_null_oid(GIT_EINVALID, "cannot write object");
1468 
1469 	if (git_odb__freshen(db, oid))
1470 		return 0;
1471 
1472 	if ((error = git_mutex_lock(&db->lock)) < 0) {
1473 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
1474 		return error;
1475 	}
1476 	for (i = 0, error = GIT_ERROR; i < db->backends.length && error < 0; ++i) {
1477 		backend_internal *internal = git_vector_get(&db->backends, i);
1478 		git_odb_backend *b = internal->backend;
1479 
1480 		/* we don't write in alternates! */
1481 		if (internal->is_alternate)
1482 			continue;
1483 
1484 		if (b->write != NULL)
1485 			error = b->write(b, oid, data, len, type);
1486 	}
1487 	git_mutex_unlock(&db->lock);
1488 
1489 	if (!error || error == GIT_PASSTHROUGH)
1490 		return 0;
1491 
1492 	/* if no backends were able to write the object directly, we try a
1493 	 * streaming write to the backends; just write the whole object into the
1494 	 * stream in one push
1495 	 */
1496 	if ((error = git_odb_open_wstream(&stream, db, len, type)) != 0)
1497 		return error;
1498 
1499 	stream->write(stream, data, len);
1500 	error = stream->finalize_write(stream, oid);
1501 	git_odb_stream_free(stream);
1502 
1503 	return error;
1504 }
1505 
hash_header(git_hash_ctx * ctx,git_object_size_t size,git_object_t type)1506 static int hash_header(git_hash_ctx *ctx, git_object_size_t size, git_object_t type)
1507 {
1508 	char header[64];
1509 	size_t hdrlen;
1510 	int error;
1511 
1512 	 if ((error = git_odb__format_object_header(&hdrlen,
1513 		header, sizeof(header), size, type)) < 0)
1514 		return error;
1515 
1516 	return git_hash_update(ctx, header, hdrlen);
1517 }
1518 
git_odb_open_wstream(git_odb_stream ** stream,git_odb * db,git_object_size_t size,git_object_t type)1519 int git_odb_open_wstream(
1520 	git_odb_stream **stream, git_odb *db, git_object_size_t size, git_object_t type)
1521 {
1522 	size_t i, writes = 0;
1523 	int error = GIT_ERROR;
1524 	git_hash_ctx *ctx = NULL;
1525 
1526 	GIT_ASSERT_ARG(stream);
1527 	GIT_ASSERT_ARG(db);
1528 
1529 	if ((error = git_mutex_lock(&db->lock)) < 0) {
1530 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
1531 		return error;
1532 	}
1533 	error = GIT_ERROR;
1534 	for (i = 0; i < db->backends.length && error < 0; ++i) {
1535 		backend_internal *internal = git_vector_get(&db->backends, i);
1536 		git_odb_backend *b = internal->backend;
1537 
1538 		/* we don't write in alternates! */
1539 		if (internal->is_alternate)
1540 			continue;
1541 
1542 		if (b->writestream != NULL) {
1543 			++writes;
1544 			error = b->writestream(stream, b, size, type);
1545 		} else if (b->write != NULL) {
1546 			++writes;
1547 			error = init_fake_wstream(stream, b, size, type);
1548 		}
1549 	}
1550 	git_mutex_unlock(&db->lock);
1551 
1552 	if (error < 0) {
1553 		if (error == GIT_PASSTHROUGH)
1554 			error = 0;
1555 		else if (!writes)
1556 			error = git_odb__error_unsupported_in_backend("write object");
1557 
1558 		goto done;
1559 	}
1560 
1561 	ctx = git__malloc(sizeof(git_hash_ctx));
1562 	GIT_ERROR_CHECK_ALLOC(ctx);
1563 
1564 	if ((error = git_hash_ctx_init(ctx)) < 0 ||
1565 		(error = hash_header(ctx, size, type)) < 0)
1566 		goto done;
1567 
1568 	(*stream)->hash_ctx = ctx;
1569 	(*stream)->declared_size = size;
1570 	(*stream)->received_bytes = 0;
1571 
1572 done:
1573 	if (error)
1574 		git__free(ctx);
1575 	return error;
1576 }
1577 
git_odb_stream__invalid_length(const git_odb_stream * stream,const char * action)1578 static int git_odb_stream__invalid_length(
1579 	const git_odb_stream *stream,
1580 	const char *action)
1581 {
1582 	git_error_set(GIT_ERROR_ODB,
1583 		"cannot %s - "
1584 		"Invalid length. %"PRId64" was expected. The "
1585 		"total size of the received chunks amounts to %"PRId64".",
1586 		action, stream->declared_size, stream->received_bytes);
1587 
1588 	return -1;
1589 }
1590 
git_odb_stream_write(git_odb_stream * stream,const char * buffer,size_t len)1591 int git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len)
1592 {
1593 	git_hash_update(stream->hash_ctx, buffer, len);
1594 
1595 	stream->received_bytes += len;
1596 
1597 	if (stream->received_bytes > stream->declared_size)
1598 		return git_odb_stream__invalid_length(stream,
1599 			"stream_write()");
1600 
1601 	return stream->write(stream, buffer, len);
1602 }
1603 
git_odb_stream_finalize_write(git_oid * out,git_odb_stream * stream)1604 int git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream)
1605 {
1606 	if (stream->received_bytes != stream->declared_size)
1607 		return git_odb_stream__invalid_length(stream,
1608 			"stream_finalize_write()");
1609 
1610 	git_hash_final(out, stream->hash_ctx);
1611 
1612 	if (git_odb__freshen(stream->backend->odb, out))
1613 		return 0;
1614 
1615 	return stream->finalize_write(stream, out);
1616 }
1617 
git_odb_stream_read(git_odb_stream * stream,char * buffer,size_t len)1618 int git_odb_stream_read(git_odb_stream *stream, char *buffer, size_t len)
1619 {
1620 	return stream->read(stream, buffer, len);
1621 }
1622 
git_odb_stream_free(git_odb_stream * stream)1623 void git_odb_stream_free(git_odb_stream *stream)
1624 {
1625 	if (stream == NULL)
1626 		return;
1627 
1628 	git_hash_ctx_cleanup(stream->hash_ctx);
1629 	git__free(stream->hash_ctx);
1630 	stream->free(stream);
1631 }
1632 
git_odb_open_rstream(git_odb_stream ** stream,size_t * len,git_object_t * type,git_odb * db,const git_oid * oid)1633 int git_odb_open_rstream(
1634 	git_odb_stream **stream,
1635 	size_t *len,
1636 	git_object_t *type,
1637 	git_odb *db,
1638 	const git_oid *oid)
1639 {
1640 	size_t i, reads = 0;
1641 	int error = GIT_ERROR;
1642 
1643 	GIT_ASSERT_ARG(stream);
1644 	GIT_ASSERT_ARG(db);
1645 
1646 	if ((error = git_mutex_lock(&db->lock)) < 0) {
1647 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
1648 		return error;
1649 	}
1650 	error = GIT_ERROR;
1651 	for (i = 0; i < db->backends.length && error < 0; ++i) {
1652 		backend_internal *internal = git_vector_get(&db->backends, i);
1653 		git_odb_backend *b = internal->backend;
1654 
1655 		if (b->readstream != NULL) {
1656 			++reads;
1657 			error = b->readstream(stream, len, type, b, oid);
1658 		}
1659 	}
1660 	git_mutex_unlock(&db->lock);
1661 
1662 	if (error == GIT_PASSTHROUGH)
1663 		error = 0;
1664 	if (error < 0 && !reads)
1665 		error = git_odb__error_unsupported_in_backend("read object streamed");
1666 
1667 	return error;
1668 }
1669 
git_odb_write_pack(struct git_odb_writepack ** out,git_odb * db,git_indexer_progress_cb progress_cb,void * progress_payload)1670 int git_odb_write_pack(struct git_odb_writepack **out, git_odb *db, git_indexer_progress_cb progress_cb, void *progress_payload)
1671 {
1672 	size_t i, writes = 0;
1673 	int error = GIT_ERROR;
1674 
1675 	GIT_ASSERT_ARG(out);
1676 	GIT_ASSERT_ARG(db);
1677 
1678 	if ((error = git_mutex_lock(&db->lock)) < 0) {
1679 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
1680 		return error;
1681 	}
1682 	error = GIT_ERROR;
1683 	for (i = 0; i < db->backends.length && error < 0; ++i) {
1684 		backend_internal *internal = git_vector_get(&db->backends, i);
1685 		git_odb_backend *b = internal->backend;
1686 
1687 		/* we don't write in alternates! */
1688 		if (internal->is_alternate)
1689 			continue;
1690 
1691 		if (b->writepack != NULL) {
1692 			++writes;
1693 			error = b->writepack(out, b, db, progress_cb, progress_payload);
1694 		}
1695 	}
1696 	git_mutex_unlock(&db->lock);
1697 
1698 	if (error == GIT_PASSTHROUGH)
1699 		error = 0;
1700 	if (error < 0 && !writes)
1701 		error = git_odb__error_unsupported_in_backend("write pack");
1702 
1703 	return error;
1704 }
1705 
git_odb_write_multi_pack_index(git_odb * db)1706 int git_odb_write_multi_pack_index(git_odb *db)
1707 {
1708 	size_t i, writes = 0;
1709 	int error = GIT_ERROR;
1710 
1711 	GIT_ASSERT_ARG(db);
1712 
1713 	for (i = 0; i < db->backends.length && error < 0; ++i) {
1714 		backend_internal *internal = git_vector_get(&db->backends, i);
1715 		git_odb_backend *b = internal->backend;
1716 
1717 		/* we don't write in alternates! */
1718 		if (internal->is_alternate)
1719 			continue;
1720 
1721 		if (b->writemidx != NULL) {
1722 			++writes;
1723 			error = b->writemidx(b);
1724 		}
1725 	}
1726 
1727 	if (error == GIT_PASSTHROUGH)
1728 		error = 0;
1729 	if (error < 0 && !writes)
1730 		error = git_odb__error_unsupported_in_backend("write multi-pack-index");
1731 
1732 	return error;
1733 }
1734 
git_odb_backend_data_alloc(git_odb_backend * backend,size_t len)1735 void *git_odb_backend_data_alloc(git_odb_backend *backend, size_t len)
1736 {
1737 	GIT_UNUSED(backend);
1738 	return git__malloc(len);
1739 }
1740 
1741 #ifndef GIT_DEPRECATE_HARD
git_odb_backend_malloc(git_odb_backend * backend,size_t len)1742 void *git_odb_backend_malloc(git_odb_backend *backend, size_t len)
1743 {
1744 	return git_odb_backend_data_alloc(backend, len);
1745 }
1746 #endif
1747 
git_odb_backend_data_free(git_odb_backend * backend,void * data)1748 void git_odb_backend_data_free(git_odb_backend *backend, void *data)
1749 {
1750 	GIT_UNUSED(backend);
1751 	git__free(data);
1752 }
1753 
git_odb_refresh(struct git_odb * db)1754 int git_odb_refresh(struct git_odb *db)
1755 {
1756 	size_t i;
1757 	int error;
1758 
1759 	GIT_ASSERT_ARG(db);
1760 
1761 	if ((error = git_mutex_lock(&db->lock)) < 0) {
1762 		git_error_set(GIT_ERROR_ODB, "failed to acquire the odb lock");
1763 		return error;
1764 	}
1765 	for (i = 0; i < db->backends.length; ++i) {
1766 		backend_internal *internal = git_vector_get(&db->backends, i);
1767 		git_odb_backend *b = internal->backend;
1768 
1769 		if (b->refresh != NULL) {
1770 			int error = b->refresh(b);
1771 			if (error < 0) {
1772 				git_mutex_unlock(&db->lock);
1773 				return error;
1774 			}
1775 		}
1776 	}
1777 	if (db->cgraph)
1778 		git_commit_graph_refresh(db->cgraph);
1779 	git_mutex_unlock(&db->lock);
1780 
1781 	return 0;
1782 }
1783 
git_odb__error_mismatch(const git_oid * expected,const git_oid * actual)1784 int git_odb__error_mismatch(const git_oid *expected, const git_oid *actual)
1785 {
1786 	char expected_oid[GIT_OID_HEXSZ + 1], actual_oid[GIT_OID_HEXSZ + 1];
1787 
1788 	git_oid_tostr(expected_oid, sizeof(expected_oid), expected);
1789 	git_oid_tostr(actual_oid, sizeof(actual_oid), actual);
1790 
1791 	git_error_set(GIT_ERROR_ODB, "object hash mismatch - expected %s but got %s",
1792 		expected_oid, actual_oid);
1793 
1794 	return GIT_EMISMATCH;
1795 }
1796 
git_odb__error_notfound(const char * message,const git_oid * oid,size_t oid_len)1797 int git_odb__error_notfound(
1798 	const char *message, const git_oid *oid, size_t oid_len)
1799 {
1800 	if (oid != NULL) {
1801 		char oid_str[GIT_OID_HEXSZ + 1];
1802 		git_oid_tostr(oid_str, oid_len+1, oid);
1803 		git_error_set(GIT_ERROR_ODB, "object not found - %s (%.*s)",
1804 			message, (int) oid_len, oid_str);
1805 	} else
1806 		git_error_set(GIT_ERROR_ODB, "object not found - %s", message);
1807 
1808 	return GIT_ENOTFOUND;
1809 }
1810 
error_null_oid(int error,const char * message)1811 static int error_null_oid(int error, const char *message)
1812 {
1813 	git_error_set(GIT_ERROR_ODB, "odb: %s: null OID cannot exist", message);
1814 	return error;
1815 }
1816 
git_odb__error_ambiguous(const char * message)1817 int git_odb__error_ambiguous(const char *message)
1818 {
1819 	git_error_set(GIT_ERROR_ODB, "ambiguous SHA1 prefix - %s", message);
1820 	return GIT_EAMBIGUOUS;
1821 }
1822 
git_odb_init_backend(git_odb_backend * backend,unsigned int version)1823 int git_odb_init_backend(git_odb_backend *backend, unsigned int version)
1824 {
1825 	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1826 		backend, version, git_odb_backend, GIT_ODB_BACKEND_INIT);
1827 	return 0;
1828 }
1829