Blame src/odb_loose.c

Packit Service 20376f
/*
Packit Service 20376f
 * Copyright (C) the libgit2 contributors. All rights reserved.
Packit Service 20376f
 *
Packit Service 20376f
 * This file is part of libgit2, distributed under the GNU GPL v2 with
Packit Service 20376f
 * a Linking Exception. For full terms see the included COPYING file.
Packit Service 20376f
 */
Packit Service 20376f
Packit Service 20376f
#include "common.h"
Packit Service 20376f
#include <zlib.h>
Packit Service 20376f
#include "git2/object.h"
Packit Service 20376f
#include "git2/sys/odb_backend.h"
Packit Service 20376f
#include "fileops.h"
Packit Service 20376f
#include "hash.h"
Packit Service 20376f
#include "odb.h"
Packit Service 20376f
#include "delta.h"
Packit Service 20376f
#include "filebuf.h"
Packit Service 20376f
#include "object.h"
Packit Service 20376f
Packit Service 20376f
#include "git2/odb_backend.h"
Packit Service 20376f
#include "git2/types.h"
Packit Service 20376f
Packit Service 20376f
typedef struct { /* object header data */
Packit Service 20376f
	git_otype type; /* object type */
Packit Service 20376f
	size_t	size; /* object size */
Packit Service 20376f
} obj_hdr;
Packit Service 20376f
Packit Service 20376f
typedef struct {
Packit Service 20376f
	git_odb_stream stream;
Packit Service 20376f
	git_filebuf fbuf;
Packit Service 20376f
} loose_writestream;
Packit Service 20376f
Packit Service 20376f
typedef struct loose_backend {
Packit Service 20376f
	git_odb_backend parent;
Packit Service 20376f
Packit Service 20376f
	int object_zlib_level; /** loose object zlib compression level. */
Packit Service 20376f
	int fsync_object_files; /** loose object file fsync flag. */
Packit Service 20376f
	mode_t object_file_mode;
Packit Service 20376f
	mode_t object_dir_mode;
Packit Service 20376f
Packit Service 20376f
	size_t objects_dirlen;
Packit Service 20376f
	char objects_dir[GIT_FLEX_ARRAY];
Packit Service 20376f
} loose_backend;
Packit Service 20376f
Packit Service 20376f
/* State structure for exploring directories,
Packit Service 20376f
 * in order to locate objects matching a short oid.
Packit Service 20376f
 */
Packit Service 20376f
typedef struct {
Packit Service 20376f
	size_t dir_len;
Packit Service 20376f
	unsigned char short_oid[GIT_OID_HEXSZ]; /* hex formatted oid to match */
Packit Service 20376f
	size_t short_oid_len;
Packit Service 20376f
	int found;				/* number of matching
Packit Service 20376f
						 * objects already found */
Packit Service 20376f
	unsigned char res_oid[GIT_OID_HEXSZ];	/* hex formatted oid of
Packit Service 20376f
						 * the object found */
Packit Service 20376f
} loose_locate_object_state;
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
/***********************************************************
Packit Service 20376f
 *
Packit Service 20376f
 * MISCELLANEOUS HELPER FUNCTIONS
Packit Service 20376f
 *
Packit Service 20376f
 ***********************************************************/
Packit Service 20376f
Packit Service 20376f
static int object_file_name(
Packit Service 20376f
	git_buf *name, const loose_backend *be, const git_oid *id)
Packit Service 20376f
{
Packit Service 20376f
	size_t alloclen;
Packit Service 20376f
Packit Service 20376f
	/* expand length for object root + 40 hex sha1 chars + 2 * '/' + '\0' */
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloclen, be->objects_dirlen, GIT_OID_HEXSZ);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 3);
Packit Service 20376f
	if (git_buf_grow(name, alloclen) < 0)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	git_buf_set(name, be->objects_dir, be->objects_dirlen);
Packit Service 20376f
	git_path_to_dir(name);
Packit Service 20376f
Packit Service 20376f
	/* loose object filename: aa/aaa... (41 bytes) */
Packit Service 20376f
	git_oid_pathfmt(name->ptr + name->size, id);
Packit Service 20376f
	name->size += GIT_OID_HEXSZ + 1;
Packit Service 20376f
	name->ptr[name->size] = '\0';
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int object_mkdir(const git_buf *name, const loose_backend *be)
Packit Service 20376f
{
Packit Service 20376f
	return git_futils_mkdir_relative(
Packit Service 20376f
		name->ptr + be->objects_dirlen, be->objects_dir, be->object_dir_mode,
Packit Service 20376f
		GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR, NULL);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static size_t get_binary_object_header(obj_hdr *hdr, git_buf *obj)
Packit Service 20376f
{
Packit Service 20376f
	unsigned long c;
Packit Service 20376f
	unsigned char *data = (unsigned char *)obj->ptr;
Packit Service 20376f
	size_t shift, size, used = 0;
Packit Service 20376f
Packit Service 20376f
	if (git_buf_len(obj) == 0)
Packit Service 20376f
		return 0;
Packit Service 20376f
Packit Service 20376f
	c = data[used++];
Packit Service 20376f
	hdr->type = (c >> 4) & 7;
Packit Service 20376f
Packit Service 20376f
	size = c & 15;
Packit Service 20376f
	shift = 4;
Packit Service 20376f
	while (c & 0x80) {
Packit Service 20376f
		if (git_buf_len(obj) <= used)
Packit Service 20376f
			return 0;
Packit Service 20376f
		if (sizeof(size_t) * 8 <= shift)
Packit Service 20376f
			return 0;
Packit Service 20376f
		c = data[used++];
Packit Service 20376f
		size += (c & 0x7f) << shift;
Packit Service 20376f
		shift += 7;
Packit Service 20376f
	}
Packit Service 20376f
	hdr->size = size;
Packit Service 20376f
Packit Service 20376f
	return used;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static size_t get_object_header(obj_hdr *hdr, unsigned char *data)
Packit Service 20376f
{
Packit Service 20376f
	char c, typename[10];
Packit Service 20376f
	size_t size, used = 0;
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * type name string followed by space.
Packit Service 20376f
	 */
Packit Service 20376f
	while ((c = data[used]) != ' ') {
Packit Service 20376f
		typename[used++] = c;
Packit Service 20376f
		if (used >= sizeof(typename))
Packit Service 20376f
			return 0;
Packit Service 20376f
	}
Packit Service 20376f
	typename[used] = 0;
Packit Service 20376f
	if (used == 0)
Packit Service 20376f
		return 0;
Packit Service 20376f
	hdr->type = git_object_string2type(typename);
Packit Service 20376f
	used++; /* consume the space */
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * length follows immediately in decimal (without
Packit Service 20376f
	 * leading zeros).
Packit Service 20376f
	 */
Packit Service 20376f
	size = data[used++] - '0';
Packit Service 20376f
	if (size > 9)
Packit Service 20376f
		return 0;
Packit Service 20376f
	if (size) {
Packit Service 20376f
		while ((c = data[used]) != '\0') {
Packit Service 20376f
			size_t d = c - '0';
Packit Service 20376f
			if (d > 9)
Packit Service 20376f
				break;
Packit Service 20376f
			used++;
Packit Service 20376f
			size = size * 10 + d;
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
	hdr->size = size;
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * the length must be followed by a zero byte
Packit Service 20376f
	 */
Packit Service 20376f
	if (data[used++] != '\0')
Packit Service 20376f
		return 0;
Packit Service 20376f
Packit Service 20376f
	return used;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
/***********************************************************
Packit Service 20376f
 *
Packit Service 20376f
 * ZLIB RELATED FUNCTIONS
Packit Service 20376f
 *
Packit Service 20376f
 ***********************************************************/
Packit Service 20376f
Packit Service 20376f
static void init_stream(z_stream *s, void *out, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	memset(s, 0, sizeof(*s));
Packit Service 20376f
	s->next_out = out;
Packit Service 20376f
	s->avail_out = (uInt)len;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void set_stream_input(z_stream *s, void *in, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	s->next_in = in;
Packit Service 20376f
	s->avail_in = (uInt)len;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void set_stream_output(z_stream *s, void *out, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	s->next_out = out;
Packit Service 20376f
	s->avail_out = (uInt)len;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
static int start_inflate(z_stream *s, git_buf *obj, void *out, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	int status;
Packit Service 20376f
Packit Service 20376f
	init_stream(s, out, len);
Packit Service 20376f
	set_stream_input(s, obj->ptr, git_buf_len(obj));
Packit Service 20376f
Packit Service 20376f
	if ((status = inflateInit(s)) < Z_OK)
Packit Service 20376f
		return status;
Packit Service 20376f
Packit Service 20376f
	return inflate(s, 0);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void abort_inflate(z_stream *s)
Packit Service 20376f
{
Packit Service 20376f
	inflateEnd(s);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int finish_inflate(z_stream *s)
Packit Service 20376f
{
Packit Service 20376f
	int status = Z_OK;
Packit Service 20376f
Packit Service 20376f
	while (status == Z_OK)
Packit Service 20376f
		status = inflate(s, Z_FINISH);
Packit Service 20376f
Packit Service 20376f
	inflateEnd(s);
Packit Service 20376f
Packit Service 20376f
	if ((status != Z_STREAM_END) || (s->avail_in != 0)) {
Packit Service 20376f
		giterr_set(GITERR_ZLIB, "failed to finish zlib inflation; stream aborted prematurely");
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int is_zlib_compressed_data(unsigned char *data)
Packit Service 20376f
{
Packit Service 20376f
	unsigned int w;
Packit Service 20376f
Packit Service 20376f
	w = ((unsigned int)(data[0]) << 8) + data[1];
Packit Service 20376f
	return (data[0] & 0x8F) == 0x08 && !(w % 31);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
Packit Service 20376f
{
Packit Service 20376f
	z_stream zs;
Packit Service 20376f
	int status = Z_OK;
Packit Service 20376f
Packit Service 20376f
	memset(&zs, 0x0, sizeof(zs));
Packit Service 20376f
Packit Service 20376f
	zs.next_out = out;
Packit Service 20376f
	zs.avail_out = (uInt)outlen;
Packit Service 20376f
Packit Service 20376f
	zs.next_in = in;
Packit Service 20376f
	zs.avail_in = (uInt)inlen;
Packit Service 20376f
Packit Service 20376f
	if (inflateInit(&zs) < Z_OK) {
Packit Service 20376f
		giterr_set(GITERR_ZLIB, "failed to inflate buffer");
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	while (status == Z_OK)
Packit Service 20376f
		status = inflate(&zs, Z_FINISH);
Packit Service 20376f
Packit Service 20376f
	inflateEnd(&zs);
Packit Service 20376f
Packit Service 20376f
	if (status != Z_STREAM_END /* || zs.avail_in != 0 */ ||
Packit Service 20376f
		zs.total_out != outlen)
Packit Service 20376f
	{
Packit Service 20376f
		giterr_set(GITERR_ZLIB, "failed to inflate buffer; stream aborted prematurely");
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr)
Packit Service 20376f
{
Packit Service 20376f
	unsigned char *buf, *head = hb;
Packit Service 20376f
	size_t tail, alloc_size;
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * allocate a buffer to hold the inflated data and copy the
Packit Service 20376f
	 * initial sequence of inflated data from the tail of the
Packit Service 20376f
	 * head buffer, if any.
Packit Service 20376f
	 */
Packit Service 20376f
	if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, hdr->size, 1) ||
Packit Service 20376f
		(buf = git__malloc(alloc_size)) == NULL) {
Packit Service 20376f
		inflateEnd(s);
Packit Service 20376f
		return NULL;
Packit Service 20376f
	}
Packit Service 20376f
	tail = s->total_out - used;
Packit Service 20376f
	if (used > 0 && tail > 0) {
Packit Service 20376f
		if (tail > hdr->size)
Packit Service 20376f
			tail = hdr->size;
Packit Service 20376f
		memcpy(buf, head + used, tail);
Packit Service 20376f
	}
Packit Service 20376f
	used = tail;
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * inflate the remainder of the object data, if any
Packit Service 20376f
	 */
Packit Service 20376f
	if (hdr->size < used)
Packit Service 20376f
		inflateEnd(s);
Packit Service 20376f
	else {
Packit Service 20376f
		set_stream_output(s, buf + used, hdr->size - used);
Packit Service 20376f
		if (finish_inflate(s)) {
Packit Service 20376f
			git__free(buf);
Packit Service 20376f
			return NULL;
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	return buf;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/*
Packit Service 20376f
 * At one point, there was a loose object format that was intended to
Packit Service 20376f
 * mimic the format used in pack-files. This was to allow easy copying
Packit Service 20376f
 * of loose object data into packs. This format is no longer used, but
Packit Service 20376f
 * we must still read it.
Packit Service 20376f
 */
Packit Service 20376f
static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj)
Packit Service 20376f
{
Packit Service 20376f
	unsigned char *in, *buf;
Packit Service 20376f
	obj_hdr hdr;
Packit Service 20376f
	size_t len, used, alloclen;
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * read the object header, which is an (uncompressed)
Packit Service 20376f
	 * binary encoding of the object type and size.
Packit Service 20376f
	 */
Packit Service 20376f
	if ((used = get_binary_object_header(&hdr, obj)) == 0 ||
Packit Service 20376f
		!git_object_typeisloose(hdr.type)) {
Packit Service 20376f
		giterr_set(GITERR_ODB, "failed to inflate loose object");
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * allocate a buffer and inflate the data into it
Packit Service 20376f
	 */
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloclen, hdr.size, 1);
Packit Service 20376f
	buf = git__malloc(alloclen);
Packit Service 20376f
	GITERR_CHECK_ALLOC(buf);
Packit Service 20376f
Packit Service 20376f
	in = ((unsigned char *)obj->ptr) + used;
Packit Service 20376f
	len = obj->size - used;
Packit Service 20376f
	if (inflate_buffer(in, len, buf, hdr.size) < 0) {
Packit Service 20376f
		git__free(buf);
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
	buf[hdr.size] = '\0';
Packit Service 20376f
Packit Service 20376f
	out->data = buf;
Packit Service 20376f
	out->len = hdr.size;
Packit Service 20376f
	out->type = hdr.type;
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int inflate_disk_obj(git_rawobj *out, git_buf *obj)
Packit Service 20376f
{
Packit Service 20376f
	unsigned char head[64], *buf;
Packit Service 20376f
	z_stream zs;
Packit Service 20376f
	obj_hdr hdr;
Packit Service 20376f
	size_t used;
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * check for a pack-like loose object
Packit Service 20376f
	 */
Packit Service 20376f
	if (!is_zlib_compressed_data((unsigned char *)obj->ptr))
Packit Service 20376f
		return inflate_packlike_loose_disk_obj(out, obj);
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * inflate the initial part of the io buffer in order
Packit Service 20376f
	 * to parse the object header (type and size).
Packit Service 20376f
	 */
Packit Service 20376f
	if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK ||
Packit Service 20376f
		(used = get_object_header(&hdr, head)) == 0 ||
Packit Service 20376f
		!git_object_typeisloose(hdr.type))
Packit Service 20376f
	{
Packit Service 20376f
		abort_inflate(&zs);
Packit Service 20376f
		giterr_set(GITERR_ODB, "failed to inflate disk object");
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/*
Packit Service 20376f
	 * allocate a buffer and inflate the object data into it
Packit Service 20376f
	 * (including the initial sequence in the head buffer).
Packit Service 20376f
	 */
Packit Service 20376f
	if ((buf = inflate_tail(&zs, head, used, &hdr)) == NULL)
Packit Service 20376f
		return -1;
Packit Service 20376f
	buf[hdr.size] = '\0';
Packit Service 20376f
Packit Service 20376f
	out->data = buf;
Packit Service 20376f
	out->len = hdr.size;
Packit Service 20376f
	out->type = hdr.type;
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
/***********************************************************
Packit Service 20376f
 *
Packit Service 20376f
 * ODB OBJECT READING & WRITING
Packit Service 20376f
 *
Packit Service 20376f
 * Backend for the public API; read headers and full objects
Packit Service 20376f
 * from the ODB. Write raw data to the ODB.
Packit Service 20376f
 *
Packit Service 20376f
 ***********************************************************/
Packit Service 20376f
Packit Service 20376f
static int read_loose(git_rawobj *out, git_buf *loc)
Packit Service 20376f
{
Packit Service 20376f
	int error;
Packit Service 20376f
	git_buf obj = GIT_BUF_INIT;
Packit Service 20376f
Packit Service 20376f
	assert(out && loc);
Packit Service 20376f
Packit Service 20376f
	if (git_buf_oom(loc))
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	out->data = NULL;
Packit Service 20376f
	out->len = 0;
Packit Service 20376f
	out->type = GIT_OBJ_BAD;
Packit Service 20376f
Packit Service 20376f
	if (!(error = git_futils_readbuffer(&obj, loc->ptr)))
Packit Service 20376f
		error = inflate_disk_obj(out, &obj);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&obj);
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int read_header_loose(git_rawobj *out, git_buf *loc)
Packit Service 20376f
{
Packit Service 20376f
	int error = 0, z_return = Z_ERRNO, read_bytes;
Packit Service 20376f
	git_file fd;
Packit Service 20376f
	z_stream zs;
Packit Service 20376f
	obj_hdr header_obj;
Packit Service 20376f
	unsigned char raw_buffer[16], inflated_buffer[64];
Packit Service 20376f
Packit Service 20376f
	assert(out && loc);
Packit Service 20376f
Packit Service 20376f
	if (git_buf_oom(loc))
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	out->data = NULL;
Packit Service 20376f
Packit Service 20376f
	if ((fd = git_futils_open_ro(loc->ptr)) < 0)
Packit Service 20376f
		return fd;
Packit Service 20376f
Packit Service 20376f
	init_stream(&zs, inflated_buffer, sizeof(inflated_buffer));
Packit Service 20376f
Packit Service 20376f
	z_return = inflateInit(&zs);
Packit Service 20376f
Packit Service 20376f
	while (z_return == Z_OK) {
Packit Service 20376f
		if ((read_bytes = p_read(fd, raw_buffer, sizeof(raw_buffer))) > 0) {
Packit Service 20376f
			set_stream_input(&zs, raw_buffer, read_bytes);
Packit Service 20376f
			z_return = inflate(&zs, 0);
Packit Service 20376f
		} else
Packit Service 20376f
			z_return = Z_STREAM_END;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if ((z_return != Z_STREAM_END && z_return != Z_BUF_ERROR)
Packit Service 20376f
		|| get_object_header(&header_obj, inflated_buffer) == 0
Packit Service 20376f
		|| git_object_typeisloose(header_obj.type) == 0)
Packit Service 20376f
	{
Packit Service 20376f
		giterr_set(GITERR_ZLIB, "failed to read loose object header");
Packit Service 20376f
		error = -1;
Packit Service 20376f
	} else {
Packit Service 20376f
		out->len = header_obj.size;
Packit Service 20376f
		out->type = header_obj.type;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	finish_inflate(&zs);
Packit Service 20376f
	p_close(fd);
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int locate_object(
Packit Service 20376f
	git_buf *object_location,
Packit Service 20376f
	loose_backend *backend,
Packit Service 20376f
	const git_oid *oid)
Packit Service 20376f
{
Packit Service 20376f
	int error = object_file_name(object_location, backend, oid);
Packit Service 20376f
Packit Service 20376f
	if (!error && !git_path_exists(object_location->ptr))
Packit Service 20376f
		return GIT_ENOTFOUND;
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* Explore an entry of a directory and see if it matches a short oid */
Packit Service 20376f
static int fn_locate_object_short_oid(void *state, git_buf *pathbuf) {
Packit Service 20376f
	loose_locate_object_state *sstate = (loose_locate_object_state *)state;
Packit Service 20376f
Packit Service 20376f
	if (git_buf_len(pathbuf) - sstate->dir_len != GIT_OID_HEXSZ - 2) {
Packit Service 20376f
		/* Entry cannot be an object. Continue to next entry */
Packit Service 20376f
		return 0;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (git_path_isdir(pathbuf->ptr) == false) {
Packit Service 20376f
		/* We are already in the directory matching the 2 first hex characters,
Packit Service 20376f
		 * compare the first ncmp characters of the oids */
Packit Service 20376f
		if (!memcmp(sstate->short_oid + 2,
Packit Service 20376f
			(unsigned char *)pathbuf->ptr + sstate->dir_len,
Packit Service 20376f
			sstate->short_oid_len - 2)) {
Packit Service 20376f
Packit Service 20376f
			if (!sstate->found) {
Packit Service 20376f
				sstate->res_oid[0] = sstate->short_oid[0];
Packit Service 20376f
				sstate->res_oid[1] = sstate->short_oid[1];
Packit Service 20376f
				memcpy(sstate->res_oid+2, pathbuf->ptr+sstate->dir_len, GIT_OID_HEXSZ-2);
Packit Service 20376f
			}
Packit Service 20376f
			sstate->found++;
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (sstate->found > 1)
Packit Service 20376f
		return GIT_EAMBIGUOUS;
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* Locate an object matching a given short oid */
Packit Service 20376f
static int locate_object_short_oid(
Packit Service 20376f
	git_buf *object_location,
Packit Service 20376f
	git_oid *res_oid,
Packit Service 20376f
	loose_backend *backend,
Packit Service 20376f
	const git_oid *short_oid,
Packit Service 20376f
	size_t len)
Packit Service 20376f
{
Packit Service 20376f
	char *objects_dir = backend->objects_dir;
Packit Service 20376f
	size_t dir_len = strlen(objects_dir), alloc_len;
Packit Service 20376f
	loose_locate_object_state state;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	/* prealloc memory for OBJ_DIR/xx/xx..38x..xx */
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 3);
Packit Service 20376f
	if (git_buf_grow(object_location, alloc_len) < 0)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	git_buf_set(object_location, objects_dir, dir_len);
Packit Service 20376f
	git_path_to_dir(object_location);
Packit Service 20376f
Packit Service 20376f
	/* save adjusted position at end of dir so it can be restored later */
Packit Service 20376f
	dir_len = git_buf_len(object_location);
Packit Service 20376f
Packit Service 20376f
	/* Convert raw oid to hex formatted oid */
Packit Service 20376f
	git_oid_fmt((char *)state.short_oid, short_oid);
Packit Service 20376f
Packit Service 20376f
	/* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */
Packit Service 20376f
	if (git_buf_put(object_location, (char *)state.short_oid, 3) < 0)
Packit Service 20376f
		return -1;
Packit Service 20376f
	object_location->ptr[object_location->size - 1] = '/';
Packit Service 20376f
Packit Service 20376f
	/* Check that directory exists */
Packit Service 20376f
	if (git_path_isdir(object_location->ptr) == false)
Packit Service 20376f
		return git_odb__error_notfound("no matching loose object for prefix",
Packit Service 20376f
			short_oid, len);
Packit Service 20376f
Packit Service 20376f
	state.dir_len = git_buf_len(object_location);
Packit Service 20376f
	state.short_oid_len = len;
Packit Service 20376f
	state.found = 0;
Packit Service 20376f
Packit Service 20376f
	/* Explore directory to find a unique object matching short_oid */
Packit Service 20376f
	error = git_path_direach(
Packit Service 20376f
		object_location, 0, fn_locate_object_short_oid, &state);
Packit Service 20376f
	if (error < 0 && error != GIT_EAMBIGUOUS)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	if (!state.found)
Packit Service 20376f
		return git_odb__error_notfound("no matching loose object for prefix",
Packit Service 20376f
			short_oid, len);
Packit Service 20376f
Packit Service 20376f
	if (state.found > 1)
Packit Service 20376f
		return git_odb__error_ambiguous("multiple matches in loose objects");
Packit Service 20376f
Packit Service 20376f
	/* Convert obtained hex formatted oid to raw */
Packit Service 20376f
	error = git_oid_fromstr(res_oid, (char *)state.res_oid);
Packit Service 20376f
	if (error)
Packit Service 20376f
		return error;
Packit Service 20376f
Packit Service 20376f
	/* Update the location according to the oid obtained */
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);
Packit Service 20376f
Packit Service 20376f
	git_buf_truncate(object_location, dir_len);
Packit Service 20376f
	if (git_buf_grow(object_location, alloc_len) < 0)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	git_oid_pathfmt(object_location->ptr + dir_len, res_oid);
Packit Service 20376f
Packit Service 20376f
	object_location->size += GIT_OID_HEXSZ + 1;
Packit Service 20376f
	object_location->ptr[object_location->size] = '\0';
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
/***********************************************************
Packit Service 20376f
 *
Packit Service 20376f
 * LOOSE BACKEND PUBLIC API
Packit Service 20376f
 *
Packit Service 20376f
 * Implement the git_odb_backend API calls
Packit Service 20376f
 *
Packit Service 20376f
 ***********************************************************/
Packit Service 20376f
Packit Service 20376f
static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
Packit Service 20376f
{
Packit Service 20376f
	git_buf object_path = GIT_BUF_INIT;
Packit Service 20376f
	git_rawobj raw;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	assert(backend && oid);
Packit Service 20376f
Packit Service 20376f
	raw.len = 0;
Packit Service 20376f
	raw.type = GIT_OBJ_BAD;
Packit Service 20376f
Packit Service 20376f
	if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) {
Packit Service 20376f
		error = git_odb__error_notfound("no matching loose object",
Packit Service 20376f
			oid, GIT_OID_HEXSZ);
Packit Service 20376f
	} else if ((error = read_header_loose(&raw, &object_path)) == 0) {
Packit Service 20376f
		*len_p = raw.len;
Packit Service 20376f
		*type_p = raw.type;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&object_path);
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
Packit Service 20376f
{
Packit Service 20376f
	git_buf object_path = GIT_BUF_INIT;
Packit Service 20376f
	git_rawobj raw;
Packit Service 20376f
	int error = 0;
Packit Service 20376f
Packit Service 20376f
	assert(backend && oid);
Packit Service 20376f
Packit Service 20376f
	if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) {
Packit Service 20376f
		error = git_odb__error_notfound("no matching loose object",
Packit Service 20376f
			oid, GIT_OID_HEXSZ);
Packit Service 20376f
	} else if ((error = read_loose(&raw, &object_path)) == 0) {
Packit Service 20376f
		*buffer_p = raw.data;
Packit Service 20376f
		*len_p = raw.len;
Packit Service 20376f
		*type_p = raw.type;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&object_path);
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int loose_backend__read_prefix(
Packit Service 20376f
	git_oid *out_oid,
Packit Service 20376f
	void **buffer_p,
Packit Service 20376f
	size_t *len_p,
Packit Service 20376f
	git_otype *type_p,
Packit Service 20376f
	git_odb_backend *backend,
Packit Service 20376f
	const git_oid *short_oid,
Packit Service 20376f
	size_t len)
Packit Service 20376f
{
Packit Service 20376f
	int error = 0;
Packit Service 20376f
Packit Service 20376f
	assert(len >= GIT_OID_MINPREFIXLEN && len <= GIT_OID_HEXSZ);
Packit Service 20376f
Packit Service 20376f
	if (len == GIT_OID_HEXSZ) {
Packit Service 20376f
		/* We can fall back to regular read method */
Packit Service 20376f
		error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid);
Packit Service 20376f
		if (!error)
Packit Service 20376f
			git_oid_cpy(out_oid, short_oid);
Packit Service 20376f
	} else {
Packit Service 20376f
		git_buf object_path = GIT_BUF_INIT;
Packit Service 20376f
		git_rawobj raw;
Packit Service 20376f
Packit Service 20376f
		assert(backend && short_oid);
Packit Service 20376f
Packit Service 20376f
		if ((error = locate_object_short_oid(&object_path, out_oid,
Packit Service 20376f
				(loose_backend *)backend, short_oid, len)) == 0 &&
Packit Service 20376f
			(error = read_loose(&raw, &object_path)) == 0)
Packit Service 20376f
		{
Packit Service 20376f
			*buffer_p = raw.data;
Packit Service 20376f
			*len_p = raw.len;
Packit Service 20376f
			*type_p = raw.type;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		git_buf_free(&object_path);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
Packit Service 20376f
{
Packit Service 20376f
	git_buf object_path = GIT_BUF_INIT;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	assert(backend && oid);
Packit Service 20376f
Packit Service 20376f
	error = locate_object(&object_path, (loose_backend *)backend, oid);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&object_path);
Packit Service 20376f
Packit Service 20376f
	return !error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int loose_backend__exists_prefix(
Packit Service 20376f
	git_oid *out, git_odb_backend *backend, const git_oid *short_id, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	git_buf object_path = GIT_BUF_INIT;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	assert(backend && out && short_id && len >= GIT_OID_MINPREFIXLEN);
Packit Service 20376f
Packit Service 20376f
	error = locate_object_short_oid(
Packit Service 20376f
		&object_path, out, (loose_backend *)backend, short_id, len);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&object_path);
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
struct foreach_state {
Packit Service 20376f
	size_t dir_len;
Packit Service 20376f
	git_odb_foreach_cb cb;
Packit Service 20376f
	void *data;
Packit Service 20376f
};
Packit Service 20376f
Packit Service 20376f
GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr)
Packit Service 20376f
{
Packit Service 20376f
	int v, i = 0;
Packit Service 20376f
	if (strlen(ptr) != GIT_OID_HEXSZ+1)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	if (ptr[2] != '/') {
Packit Service 20376f
		return -1;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	v = (git__fromhex(ptr[i]) << 4) | git__fromhex(ptr[i+1]);
Packit Service 20376f
	if (v < 0)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	oid->id[0] = (unsigned char) v;
Packit Service 20376f
Packit Service 20376f
	ptr += 3;
Packit Service 20376f
	for (i = 0; i < 38; i += 2) {
Packit Service 20376f
		v = (git__fromhex(ptr[i]) << 4) | git__fromhex(ptr[i + 1]);
Packit Service 20376f
		if (v < 0)
Packit Service 20376f
			return -1;
Packit Service 20376f
Packit Service 20376f
		oid->id[1 + i/2] = (unsigned char) v;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int foreach_object_dir_cb(void *_state, git_buf *path)
Packit Service 20376f
{
Packit Service 20376f
	git_oid oid;
Packit Service 20376f
	struct foreach_state *state = (struct foreach_state *) _state;
Packit Service 20376f
Packit Service 20376f
	if (filename_to_oid(&oid, path->ptr + state->dir_len) < 0)
Packit Service 20376f
		return 0;
Packit Service 20376f
Packit Service 20376f
	return giterr_set_after_callback_function(
Packit Service 20376f
		state->cb(&oid, state->data), "git_odb_foreach");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int foreach_cb(void *_state, git_buf *path)
Packit Service 20376f
{
Packit Service 20376f
	struct foreach_state *state = (struct foreach_state *) _state;
Packit Service 20376f
Packit Service 20376f
	/* non-dir is some stray file, ignore it */
Packit Service 20376f
	if (!git_path_isdir(git_buf_cstr(path)))
Packit Service 20376f
		return 0;
Packit Service 20376f
Packit Service 20376f
	return git_path_direach(path, 0, foreach_object_dir_cb, state);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb cb, void *data)
Packit Service 20376f
{
Packit Service 20376f
	char *objects_dir;
Packit Service 20376f
	int error;
Packit Service 20376f
	git_buf buf = GIT_BUF_INIT;
Packit Service 20376f
	struct foreach_state state;
Packit Service 20376f
	loose_backend *backend = (loose_backend *) _backend;
Packit Service 20376f
Packit Service 20376f
	assert(backend && cb);
Packit Service 20376f
Packit Service 20376f
	objects_dir = backend->objects_dir;
Packit Service 20376f
Packit Service 20376f
	git_buf_sets(&buf, objects_dir);
Packit Service 20376f
	git_path_to_dir(&buf;;
Packit Service 20376f
	if (git_buf_oom(&buf))
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	memset(&state, 0, sizeof(state));
Packit Service 20376f
	state.cb = cb;
Packit Service 20376f
	state.data = data;
Packit Service 20376f
	state.dir_len = git_buf_len(&buf;;
Packit Service 20376f
Packit Service 20376f
	error = git_path_direach(&buf, 0, foreach_cb, &state);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&buf;;
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int loose_backend__stream_fwrite(git_odb_stream *_stream, const git_oid *oid)
Packit Service 20376f
{
Packit Service 20376f
	loose_writestream *stream = (loose_writestream *)_stream;
Packit Service 20376f
	loose_backend *backend = (loose_backend *)_stream->backend;
Packit Service 20376f
	git_buf final_path = GIT_BUF_INIT;
Packit Service 20376f
	int error = 0;
Packit Service 20376f
Packit Service 20376f
	if (object_file_name(&final_path, backend, oid) < 0 ||
Packit Service 20376f
		object_mkdir(&final_path, backend) < 0)
Packit Service 20376f
		error = -1;
Packit Service 20376f
	else
Packit Service 20376f
		error = git_filebuf_commit_at(
Packit Service 20376f
			&stream->fbuf, final_path.ptr);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&final_path);
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len)
Packit Service 20376f
{
Packit Service 20376f
	loose_writestream *stream = (loose_writestream *)_stream;
Packit Service 20376f
	return git_filebuf_write(&stream->fbuf, data, len);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void loose_backend__stream_free(git_odb_stream *_stream)
Packit Service 20376f
{
Packit Service 20376f
	loose_writestream *stream = (loose_writestream *)_stream;
Packit Service 20376f
Packit Service 20376f
	git_filebuf_cleanup(&stream->fbuf);
Packit Service 20376f
	git__free(stream);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int filebuf_flags(loose_backend *backend)
Packit Service 20376f
{
Packit Service 20376f
	int flags = GIT_FILEBUF_TEMPORARY |
Packit Service 20376f
		(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT);
Packit Service 20376f
Packit Service 20376f
	if (backend->fsync_object_files || git_repository__fsync_gitdir)
Packit Service 20376f
		flags |= GIT_FILEBUF_FSYNC;
Packit Service 20376f
Packit Service 20376f
	return flags;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, git_off_t length, git_otype type)
Packit Service 20376f
{
Packit Service 20376f
	loose_backend *backend;
Packit Service 20376f
	loose_writestream *stream = NULL;
Packit Service 20376f
	char hdr[64];
Packit Service 20376f
	git_buf tmp_path = GIT_BUF_INIT;
Packit Service 20376f
	int hdrlen;
Packit Service 20376f
Packit Service 20376f
	assert(_backend && length >= 0);
Packit Service 20376f
Packit Service 20376f
	backend = (loose_backend *)_backend;
Packit Service 20376f
	*stream_out = NULL;
Packit Service 20376f
Packit Service 20376f
	hdrlen = git_odb__format_object_header(hdr, sizeof(hdr), length, type);
Packit Service 20376f
Packit Service 20376f
	stream = git__calloc(1, sizeof(loose_writestream));
Packit Service 20376f
	GITERR_CHECK_ALLOC(stream);
Packit Service 20376f
Packit Service 20376f
	stream->stream.backend = _backend;
Packit Service 20376f
	stream->stream.read = NULL; /* read only */
Packit Service 20376f
	stream->stream.write = &loose_backend__stream_write;
Packit Service 20376f
	stream->stream.finalize_write = &loose_backend__stream_fwrite;
Packit Service 20376f
	stream->stream.free = &loose_backend__stream_free;
Packit Service 20376f
	stream->stream.mode = GIT_STREAM_WRONLY;
Packit Service 20376f
Packit Service 20376f
	if (git_buf_joinpath(&tmp_path, backend->objects_dir, "tmp_object") < 0 ||
Packit Service 20376f
		git_filebuf_open(&stream->fbuf, tmp_path.ptr, filebuf_flags(backend),
Packit Service 20376f
			backend->object_file_mode) < 0 ||
Packit Service 20376f
		stream->stream.write((git_odb_stream *)stream, hdr, hdrlen) < 0)
Packit Service 20376f
	{
Packit Service 20376f
		git_filebuf_cleanup(&stream->fbuf);
Packit Service 20376f
		git__free(stream);
Packit Service 20376f
		stream = NULL;
Packit Service 20376f
	}
Packit Service 20376f
	git_buf_free(&tmp_path);
Packit Service 20376f
	*stream_out = (git_odb_stream *)stream;
Packit Service 20376f
Packit Service 20376f
	return !stream ? -1 : 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int loose_backend__write(git_odb_backend *_backend, const git_oid *oid, const void *data, size_t len, git_otype type)
Packit Service 20376f
{
Packit Service 20376f
	int error = 0, header_len;
Packit Service 20376f
	git_buf final_path = GIT_BUF_INIT;
Packit Service 20376f
	char header[64];
Packit Service 20376f
	git_filebuf fbuf = GIT_FILEBUF_INIT;
Packit Service 20376f
	loose_backend *backend;
Packit Service 20376f
Packit Service 20376f
	backend = (loose_backend *)_backend;
Packit Service 20376f
Packit Service 20376f
	/* prepare the header for the file */
Packit Service 20376f
	header_len = git_odb__format_object_header(header, sizeof(header), len, type);
Packit Service 20376f
Packit Service 20376f
	if (git_buf_joinpath(&final_path, backend->objects_dir, "tmp_object") < 0 ||
Packit Service 20376f
		git_filebuf_open(&fbuf, final_path.ptr, filebuf_flags(backend),
Packit Service 20376f
			backend->object_file_mode) < 0)
Packit Service 20376f
	{
Packit Service 20376f
		error = -1;
Packit Service 20376f
		goto cleanup;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	git_filebuf_write(&fbuf, header, header_len);
Packit Service 20376f
	git_filebuf_write(&fbuf, data, len);
Packit Service 20376f
Packit Service 20376f
	if (object_file_name(&final_path, backend, oid) < 0 ||
Packit Service 20376f
		object_mkdir(&final_path, backend) < 0 ||
Packit Service 20376f
		git_filebuf_commit_at(&fbuf, final_path.ptr) < 0)
Packit Service 20376f
		error = -1;
Packit Service 20376f
Packit Service 20376f
cleanup:
Packit Service 20376f
	if (error < 0)
Packit Service 20376f
		git_filebuf_cleanup(&fbuf);
Packit Service 20376f
	git_buf_free(&final_path);
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int loose_backend__freshen(
Packit Service 20376f
	git_odb_backend *_backend,
Packit Service 20376f
	const git_oid *oid)
Packit Service 20376f
{
Packit Service 20376f
	loose_backend *backend = (loose_backend *)_backend;
Packit Service 20376f
	git_buf path = GIT_BUF_INIT;
Packit Service 20376f
	int error;
Packit Service 20376f
Packit Service 20376f
	if (object_file_name(&path, backend, oid) < 0)
Packit Service 20376f
		return -1;
Packit Service 20376f
Packit Service 20376f
	error = git_futils_touch(path.ptr, NULL);
Packit Service 20376f
	git_buf_free(&path);
Packit Service 20376f
Packit Service 20376f
	return error;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void loose_backend__free(git_odb_backend *_backend)
Packit Service 20376f
{
Packit Service 20376f
	loose_backend *backend;
Packit Service 20376f
	assert(_backend);
Packit Service 20376f
	backend = (loose_backend *)_backend;
Packit Service 20376f
Packit Service 20376f
	git__free(backend);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int git_odb_backend_loose(
Packit Service 20376f
	git_odb_backend **backend_out,
Packit Service 20376f
	const char *objects_dir,
Packit Service 20376f
	int compression_level,
Packit Service 20376f
	int do_fsync,
Packit Service 20376f
	unsigned int dir_mode,
Packit Service 20376f
	unsigned int file_mode)
Packit Service 20376f
{
Packit Service 20376f
	loose_backend *backend;
Packit Service 20376f
	size_t objects_dirlen, alloclen;
Packit Service 20376f
Packit Service 20376f
	assert(backend_out && objects_dir);
Packit Service 20376f
Packit Service 20376f
	objects_dirlen = strlen(objects_dir);
Packit Service 20376f
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(loose_backend), objects_dirlen);
Packit Service 20376f
	GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 2);
Packit Service 20376f
	backend = git__calloc(1, alloclen);
Packit Service 20376f
	GITERR_CHECK_ALLOC(backend);
Packit Service 20376f
Packit Service 20376f
	backend->parent.version = GIT_ODB_BACKEND_VERSION;
Packit Service 20376f
	backend->objects_dirlen = objects_dirlen;
Packit Service 20376f
	memcpy(backend->objects_dir, objects_dir, objects_dirlen);
Packit Service 20376f
	if (backend->objects_dir[backend->objects_dirlen - 1] != '/')
Packit Service 20376f
		backend->objects_dir[backend->objects_dirlen++] = '/';
Packit Service 20376f
Packit Service 20376f
	if (compression_level < 0)
Packit Service 20376f
		compression_level = Z_BEST_SPEED;
Packit Service 20376f
Packit Service 20376f
	if (dir_mode == 0)
Packit Service 20376f
		dir_mode = GIT_OBJECT_DIR_MODE;
Packit Service 20376f
Packit Service 20376f
	if (file_mode == 0)
Packit Service 20376f
		file_mode = GIT_OBJECT_FILE_MODE;
Packit Service 20376f
Packit Service 20376f
	backend->object_zlib_level = compression_level;
Packit Service 20376f
	backend->fsync_object_files = do_fsync;
Packit Service 20376f
	backend->object_dir_mode = dir_mode;
Packit Service 20376f
	backend->object_file_mode = file_mode;
Packit Service 20376f
Packit Service 20376f
	backend->parent.read = &loose_backend__read;
Packit Service 20376f
	backend->parent.write = &loose_backend__write;
Packit Service 20376f
	backend->parent.read_prefix = &loose_backend__read_prefix;
Packit Service 20376f
	backend->parent.read_header = &loose_backend__read_header;
Packit Service 20376f
	backend->parent.writestream = &loose_backend__stream;
Packit Service 20376f
	backend->parent.exists = &loose_backend__exists;
Packit Service 20376f
	backend->parent.exists_prefix = &loose_backend__exists_prefix;
Packit Service 20376f
	backend->parent.foreach = &loose_backend__foreach;
Packit Service 20376f
	backend->parent.freshen = &loose_backend__freshen;
Packit Service 20376f
	backend->parent.free = &loose_backend__free;
Packit Service 20376f
Packit Service 20376f
	*backend_out = (git_odb_backend *)backend;
Packit Service 20376f
	return 0;
Packit Service 20376f
}