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 "refdb.h"
9 
10 #include "git2/object.h"
11 #include "git2/refs.h"
12 #include "git2/refdb.h"
13 #include "git2/sys/refdb_backend.h"
14 
15 #include "hash.h"
16 #include "refs.h"
17 #include "reflog.h"
18 #include "posix.h"
19 
git_refdb_new(git_refdb ** out,git_repository * repo)20 int git_refdb_new(git_refdb **out, git_repository *repo)
21 {
22 	git_refdb *db;
23 
24 	assert(out && repo);
25 
26 	db = git__calloc(1, sizeof(*db));
27 	GITERR_CHECK_ALLOC(db);
28 
29 	db->repo = repo;
30 
31 	*out = db;
32 	GIT_REFCOUNT_INC(db);
33 	return 0;
34 }
35 
git_refdb_open(git_refdb ** out,git_repository * repo)36 int git_refdb_open(git_refdb **out, git_repository *repo)
37 {
38 	git_refdb *db;
39 	git_refdb_backend *dir;
40 
41 	assert(out && repo);
42 
43 	*out = NULL;
44 
45 	if (git_refdb_new(&db, repo) < 0)
46 		return -1;
47 
48 	/* Add the default (filesystem) backend */
49 	if (git_refdb_backend_fs(&dir, repo) < 0) {
50 		git_refdb_free(db);
51 		return -1;
52 	}
53 
54 	db->repo = repo;
55 	db->backend = dir;
56 
57 	*out = db;
58 	return 0;
59 }
60 
refdb_free_backend(git_refdb * db)61 static void refdb_free_backend(git_refdb *db)
62 {
63 	if (db->backend)
64 		db->backend->free(db->backend);
65 }
66 
git_refdb_set_backend(git_refdb * db,git_refdb_backend * backend)67 int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend)
68 {
69 	refdb_free_backend(db);
70 	db->backend = backend;
71 
72 	return 0;
73 }
74 
git_refdb_compress(git_refdb * db)75 int git_refdb_compress(git_refdb *db)
76 {
77 	assert(db);
78 
79 	if (db->backend->compress)
80 		return db->backend->compress(db->backend);
81 
82 	return 0;
83 }
84 
git_refdb__free(git_refdb * db)85 void git_refdb__free(git_refdb *db)
86 {
87 	refdb_free_backend(db);
88 	git__memzero(db, sizeof(*db));
89 	git__free(db);
90 }
91 
git_refdb_free(git_refdb * db)92 void git_refdb_free(git_refdb *db)
93 {
94 	if (db == NULL)
95 		return;
96 
97 	GIT_REFCOUNT_DEC(db, git_refdb__free);
98 }
99 
git_refdb_exists(int * exists,git_refdb * refdb,const char * ref_name)100 int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name)
101 {
102 	assert(exists && refdb && refdb->backend);
103 
104 	return refdb->backend->exists(exists, refdb->backend, ref_name);
105 }
106 
git_refdb_lookup(git_reference ** out,git_refdb * db,const char * ref_name)107 int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name)
108 {
109 	git_reference *ref;
110 	int error;
111 
112 	assert(db && db->backend && out && ref_name);
113 
114 	error = db->backend->lookup(&ref, db->backend, ref_name);
115 	if (error < 0)
116 		return error;
117 
118 	GIT_REFCOUNT_INC(db);
119 	ref->db = db;
120 
121 	*out = ref;
122 	return 0;
123 }
124 
git_refdb_iterator(git_reference_iterator ** out,git_refdb * db,const char * glob)125 int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob)
126 {
127 	int error;
128 
129 	if (!db->backend || !db->backend->iterator) {
130 		giterr_set(GITERR_REFERENCE, "this backend doesn't support iterators");
131 		return -1;
132 	}
133 
134 	if ((error = db->backend->iterator(out, db->backend, glob)) < 0)
135 		return error;
136 
137 	GIT_REFCOUNT_INC(db);
138 	(*out)->db = db;
139 
140 	return 0;
141 }
142 
git_refdb_iterator_next(git_reference ** out,git_reference_iterator * iter)143 int git_refdb_iterator_next(git_reference **out, git_reference_iterator *iter)
144 {
145 	int error;
146 
147 	if ((error = iter->next(out, iter)) < 0)
148 		return error;
149 
150 	GIT_REFCOUNT_INC(iter->db);
151 	(*out)->db = iter->db;
152 
153 	return 0;
154 }
155 
git_refdb_iterator_next_name(const char ** out,git_reference_iterator * iter)156 int git_refdb_iterator_next_name(const char **out, git_reference_iterator *iter)
157 {
158 	return iter->next_name(out, iter);
159 }
160 
git_refdb_iterator_free(git_reference_iterator * iter)161 void git_refdb_iterator_free(git_reference_iterator *iter)
162 {
163 	GIT_REFCOUNT_DEC(iter->db, git_refdb__free);
164 	iter->free(iter);
165 }
166 
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)167 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)
168 {
169 	assert(db && db->backend);
170 
171 	GIT_REFCOUNT_INC(db);
172 	ref->db = db;
173 
174 	return db->backend->write(db->backend, ref, force, who, message, old_id, old_target);
175 }
176 
git_refdb_rename(git_reference ** out,git_refdb * db,const char * old_name,const char * new_name,int force,const git_signature * who,const char * message)177 int git_refdb_rename(
178 	git_reference **out,
179 	git_refdb *db,
180 	const char *old_name,
181 	const char *new_name,
182 	int force,
183 	const git_signature *who,
184 	const char *message)
185 {
186 	int error;
187 
188 	assert(db && db->backend);
189 	error = db->backend->rename(out, db->backend, old_name, new_name, force, who, message);
190 	if (error < 0)
191 		return error;
192 
193 	if (out) {
194 		GIT_REFCOUNT_INC(db);
195 		(*out)->db = db;
196 	}
197 
198 	return 0;
199 }
200 
git_refdb_delete(struct git_refdb * db,const char * ref_name,const git_oid * old_id,const char * old_target)201 int git_refdb_delete(struct git_refdb *db, const char *ref_name, const git_oid *old_id, const char *old_target)
202 {
203 	assert(db && db->backend);
204 	return db->backend->del(db->backend, ref_name, old_id, old_target);
205 }
206 
git_refdb_reflog_read(git_reflog ** out,git_refdb * db,const char * name)207 int git_refdb_reflog_read(git_reflog **out, git_refdb *db,  const char *name)
208 {
209 	int error;
210 
211 	assert(db && db->backend);
212 
213 	if ((error = db->backend->reflog_read(out, db->backend, name)) < 0)
214 		return error;
215 
216 	GIT_REFCOUNT_INC(db);
217 	(*out)->db = db;
218 
219 	return 0;
220 }
221 
git_refdb_has_log(git_refdb * db,const char * refname)222 int git_refdb_has_log(git_refdb *db, const char *refname)
223 {
224 	assert(db && refname);
225 
226 	return db->backend->has_log(db->backend, refname);
227 }
228 
git_refdb_ensure_log(git_refdb * db,const char * refname)229 int git_refdb_ensure_log(git_refdb *db, const char *refname)
230 {
231 	assert(db && refname);
232 
233 	return db->backend->ensure_log(db->backend, refname);
234 }
235 
git_refdb_init_backend(git_refdb_backend * backend,unsigned int version)236 int git_refdb_init_backend(git_refdb_backend *backend, unsigned int version)
237 {
238 	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
239 		backend, version, git_refdb_backend, GIT_REFDB_BACKEND_INIT);
240 	return 0;
241 }
242 
git_refdb_lock(void ** payload,git_refdb * db,const char * refname)243 int git_refdb_lock(void **payload, git_refdb *db, const char *refname)
244 {
245 	assert(payload && db && refname);
246 
247 	if (!db->backend->lock) {
248 		giterr_set(GITERR_REFERENCE, "backend does not support locking");
249 		return -1;
250 	}
251 
252 	return db->backend->lock(payload, db->backend, refname);
253 }
254 
git_refdb_unlock(git_refdb * db,void * payload,int success,int update_reflog,const git_reference * ref,const git_signature * sig,const char * message)255 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)
256 {
257 	assert(db);
258 
259 	return db->backend->unlock(db->backend, payload, success, update_reflog, ref, sig, message);
260 }
261