refdb.c 5.65 KB
Newer Older
1 2 3 4 5 6 7
/*
 * Copyright (C) the libgit2 contributors. All rights reserved.
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */

8
#include "refdb.h"
9

10 11 12
#include "git2/object.h"
#include "git2/refs.h"
#include "git2/refdb.h"
13 14
#include "git2/sys/refdb_backend.h"

15 16
#include "hash.h"
#include "refs.h"
17
#include "reflog.h"
18
#include "posix.h"
19 20 21 22 23 24 25 26

int git_refdb_new(git_refdb **out, git_repository *repo)
{
	git_refdb *db;

	assert(out && repo);

	db = git__calloc(1, sizeof(*db));
27
	GIT_ERROR_CHECK_ALLOC(db);
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

	db->repo = repo;

	*out = db;
	GIT_REFCOUNT_INC(db);
	return 0;
}

int git_refdb_open(git_refdb **out, git_repository *repo)
{
	git_refdb *db;
	git_refdb_backend *dir;

	assert(out && repo);

	*out = NULL;

	if (git_refdb_new(&db, repo) < 0)
		return -1;

	/* Add the default (filesystem) backend */
49
	if (git_refdb_backend_fs(&dir, repo) < 0) {
50 51 52 53 54 55 56 57 58 59 60
		git_refdb_free(db);
		return -1;
	}

	db->repo = repo;
	db->backend = dir;

	*out = db;
	return 0;
}

61
static void refdb_free_backend(git_refdb *db)
62
{
63 64
	if (db->backend)
		db->backend->free(db->backend);
65
}
66

67 68
int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend)
{
69 70
	GIT_ERROR_CHECK_VERSION(backend, GIT_REFDB_BACKEND_VERSION, "git_refdb_backend");

71 72 73 74 75 76 77 78 79 80
	if (!backend->exists || !backend->lookup || !backend->iterator ||
	    !backend->write || !backend->rename || !backend->del ||
	    !backend->has_log || !backend->ensure_log || !backend->free ||
	    !backend->reflog_read || !backend->reflog_write ||
	    !backend->reflog_rename || !backend->reflog_delete ||
	    (backend->lock && !backend->unlock)) {
		git_error_set(GIT_ERROR_REFERENCE, "incomplete refdb backend implementation");
		return GIT_EINVALID;
	}

81
	refdb_free_backend(db);
82 83 84 85 86 87 88 89
	db->backend = backend;

	return 0;
}

int git_refdb_compress(git_refdb *db)
{
	assert(db);
90

91
	if (db->backend->compress)
92
		return db->backend->compress(db->backend);
93

94 95 96
	return 0;
}

Vicent Marti committed
97
void git_refdb__free(git_refdb *db)
98
{
99
	refdb_free_backend(db);
100
	git__memzero(db, sizeof(*db));
101 102 103
	git__free(db);
}

104 105 106 107 108
void git_refdb_free(git_refdb *db)
{
	if (db == NULL)
		return;

Vicent Marti committed
109
	GIT_REFCOUNT_DEC(db, git_refdb__free);
110 111
}

112 113 114 115 116 117 118 119 120
int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name)
{
	assert(exists && refdb && refdb->backend);

	return refdb->backend->exists(exists, refdb->backend, ref_name);
}

int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name)
{
121 122 123
	git_reference *ref;
	int error;

124
	assert(db && db->backend && out && ref_name);
125

126 127 128 129 130 131
	error = db->backend->lookup(&ref, db->backend, ref_name);
	if (error < 0)
		return error;

	GIT_REFCOUNT_INC(db);
	ref->db = db;
132

133 134
	*out = ref;
	return 0;
135 136
}

137
int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob)
138
{
139 140
	int error;

141
	if (!db->backend || !db->backend->iterator) {
142
		git_error_set(GIT_ERROR_REFERENCE, "this backend doesn't support iterators");
143 144 145
		return -1;
	}

146 147
	if ((error = db->backend->iterator(out, db->backend, glob)) < 0)
		return error;
148

149 150 151
	GIT_REFCOUNT_INC(db);
	(*out)->db = db;

152 153 154
	return 0;
}

155
int git_refdb_iterator_next(git_reference **out, git_reference_iterator *iter)
156
{
157
	int error;
158

159 160
	if ((error = iter->next(out, iter)) < 0)
		return error;
161

162 163
	GIT_REFCOUNT_INC(iter->db);
	(*out)->db = iter->db;
164 165 166 167

	return 0;
}

168
int git_refdb_iterator_next_name(const char **out, git_reference_iterator *iter)
169
{
170
	return iter->next_name(out, iter);
171 172 173 174
}

void git_refdb_iterator_free(git_reference_iterator *iter)
{
Vicent Marti committed
175
	GIT_REFCOUNT_DEC(iter->db, git_refdb__free);
176
	iter->free(iter);
177 178
}

179
int git_refdb_write(git_refdb *db, git_reference *ref, int force, const git_signature *who, const char *message, const git_oid *old_id, const char *old_target)
180 181
{
	assert(db && db->backend);
Vicent Marti committed
182 183 184 185

	GIT_REFCOUNT_INC(db);
	ref->db = db;

186
	return db->backend->write(db->backend, ref, force, who, message, old_id, old_target);
Vicent Marti committed
187 188 189 190 191 192 193
}

int git_refdb_rename(
	git_reference **out,
	git_refdb *db,
	const char *old_name,
	const char *new_name,
194
	int force,
195
	const git_signature *who,
196
	const char *message)
Vicent Marti committed
197 198 199 200
{
	int error;

	assert(db && db->backend);
201
	error = db->backend->rename(out, db->backend, old_name, new_name, force, who, message);
Vicent Marti committed
202 203 204 205 206 207 208 209 210
	if (error < 0)
		return error;

	if (out) {
		GIT_REFCOUNT_INC(db);
		(*out)->db = db;
	}

	return 0;
211 212
}

213
int git_refdb_delete(struct git_refdb *db, const char *ref_name, const git_oid *old_id, const char *old_target)
214 215
{
	assert(db && db->backend);
216
	return db->backend->del(db->backend, ref_name, old_id, old_target);
217
}
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232

int git_refdb_reflog_read(git_reflog **out, git_refdb *db,  const char *name)
{
	int error;

	assert(db && db->backend);

	if ((error = db->backend->reflog_read(out, db->backend, name)) < 0)
		return error;

	GIT_REFCOUNT_INC(db);
	(*out)->db = db;

	return 0;
}
233

234 235 236 237 238 239 240
int git_refdb_has_log(git_refdb *db, const char *refname)
{
	assert(db && refname);

	return db->backend->has_log(db->backend, refname);
}

241 242 243 244 245 246
int git_refdb_ensure_log(git_refdb *db, const char *refname)
{
	assert(db && refname);

	return db->backend->ensure_log(db->backend, refname);
}
247

248
int git_refdb_init_backend(git_refdb_backend *backend, unsigned int version)
249
{
250 251 252
	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
		backend, version, git_refdb_backend, GIT_REFDB_BACKEND_INIT);
	return 0;
253
}
254 255 256 257 258 259

int git_refdb_lock(void **payload, git_refdb *db, const char *refname)
{
	assert(payload && db && refname);

	if (!db->backend->lock) {
260
		git_error_set(GIT_ERROR_REFERENCE, "backend does not support locking");
261 262 263 264 265 266 267 268 269 270 271 272
		return -1;
	}

	return db->backend->lock(payload, db->backend, refname);
}

int git_refdb_unlock(git_refdb *db, void *payload, int success, int update_reflog, const git_reference *ref, const git_signature *sig, const char *message)
{
	assert(db);

	return db->backend->unlock(db->backend, payload, success, update_reflog, ref, sig, message);
}