2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
10 #include "git2/object.h"
11 #include "git2/refs.h"
12 #include "git2/refdb.h"
13 #include "git2/sys/refdb_backend.h"
20 #define DEFAULT_NESTING_LEVEL 5
21 #define MAX_NESTING_LEVEL 10
23 int git_refdb_new(git_refdb
**out
, git_repository
*repo
)
29 db
= git__calloc(1, sizeof(*db
));
30 GIT_ERROR_CHECK_ALLOC(db
);
39 int git_refdb_open(git_refdb
**out
, git_repository
*repo
)
42 git_refdb_backend
*dir
;
48 if (git_refdb_new(&db
, repo
) < 0)
51 /* Add the default (filesystem) backend */
52 if (git_refdb_backend_fs(&dir
, repo
) < 0) {
64 static void refdb_free_backend(git_refdb
*db
)
67 db
->backend
->free(db
->backend
);
70 int git_refdb_set_backend(git_refdb
*db
, git_refdb_backend
*backend
)
72 GIT_ERROR_CHECK_VERSION(backend
, GIT_REFDB_BACKEND_VERSION
, "git_refdb_backend");
74 if (!backend
->exists
|| !backend
->lookup
|| !backend
->iterator
||
75 !backend
->write
|| !backend
->rename
|| !backend
->del
||
76 !backend
->has_log
|| !backend
->ensure_log
|| !backend
->free
||
77 !backend
->reflog_read
|| !backend
->reflog_write
||
78 !backend
->reflog_rename
|| !backend
->reflog_delete
||
79 (backend
->lock
&& !backend
->unlock
)) {
80 git_error_set(GIT_ERROR_REFERENCE
, "incomplete refdb backend implementation");
84 refdb_free_backend(db
);
85 db
->backend
= backend
;
90 int git_refdb_compress(git_refdb
*db
)
94 if (db
->backend
->compress
)
95 return db
->backend
->compress(db
->backend
);
100 void git_refdb__free(git_refdb
*db
)
102 refdb_free_backend(db
);
103 git__memzero(db
, sizeof(*db
));
107 void git_refdb_free(git_refdb
*db
)
112 GIT_REFCOUNT_DEC(db
, git_refdb__free
);
115 int git_refdb_exists(int *exists
, git_refdb
*refdb
, const char *ref_name
)
117 assert(exists
&& refdb
&& refdb
->backend
);
119 return refdb
->backend
->exists(exists
, refdb
->backend
, ref_name
);
122 int git_refdb_lookup(git_reference
**out
, git_refdb
*db
, const char *ref_name
)
127 assert(db
&& db
->backend
&& out
&& ref_name
);
129 error
= db
->backend
->lookup(&ref
, db
->backend
, ref_name
);
133 GIT_REFCOUNT_INC(db
);
140 int git_refdb_resolve(
143 const char *ref_name
,
146 git_reference
*ref
= NULL
;
147 int error
= 0, nesting
;
151 if (max_nesting
> MAX_NESTING_LEVEL
)
152 max_nesting
= MAX_NESTING_LEVEL
;
153 else if (max_nesting
< 0)
154 max_nesting
= DEFAULT_NESTING_LEVEL
;
156 if ((error
= git_refdb_lookup(&ref
, db
, ref_name
)) < 0)
159 for (nesting
= 0; nesting
< max_nesting
; nesting
++) {
160 git_reference
*resolved
;
162 if (ref
->type
== GIT_REFERENCE_DIRECT
)
165 if ((error
= git_refdb_lookup(&resolved
, db
, git_reference_symbolic_target(ref
))) < 0) {
166 /* If we found a symbolic reference with a nonexistent target, return it. */
167 if (error
== GIT_ENOTFOUND
) {
175 git_reference_free(ref
);
179 if (ref
->type
!= GIT_REFERENCE_DIRECT
&& max_nesting
!= 0) {
180 git_error_set(GIT_ERROR_REFERENCE
,
181 "cannot resolve reference (>%u levels deep)", max_nesting
);
189 git_reference_free(ref
);
193 int git_refdb_iterator(git_reference_iterator
**out
, git_refdb
*db
, const char *glob
)
197 if (!db
->backend
|| !db
->backend
->iterator
) {
198 git_error_set(GIT_ERROR_REFERENCE
, "this backend doesn't support iterators");
202 if ((error
= db
->backend
->iterator(out
, db
->backend
, glob
)) < 0)
205 GIT_REFCOUNT_INC(db
);
211 int git_refdb_iterator_next(git_reference
**out
, git_reference_iterator
*iter
)
215 if ((error
= iter
->next(out
, iter
)) < 0)
218 GIT_REFCOUNT_INC(iter
->db
);
219 (*out
)->db
= iter
->db
;
224 int git_refdb_iterator_next_name(const char **out
, git_reference_iterator
*iter
)
226 return iter
->next_name(out
, iter
);
229 void git_refdb_iterator_free(git_reference_iterator
*iter
)
231 GIT_REFCOUNT_DEC(iter
->db
, git_refdb__free
);
235 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
)
237 assert(db
&& db
->backend
);
239 GIT_REFCOUNT_INC(db
);
242 return db
->backend
->write(db
->backend
, ref
, force
, who
, message
, old_id
, old_target
);
245 int git_refdb_rename(
248 const char *old_name
,
249 const char *new_name
,
251 const git_signature
*who
,
256 assert(db
&& db
->backend
);
257 error
= db
->backend
->rename(out
, db
->backend
, old_name
, new_name
, force
, who
, message
);
262 GIT_REFCOUNT_INC(db
);
269 int git_refdb_delete(struct git_refdb
*db
, const char *ref_name
, const git_oid
*old_id
, const char *old_target
)
271 assert(db
&& db
->backend
);
272 return db
->backend
->del(db
->backend
, ref_name
, old_id
, old_target
);
275 int git_refdb_reflog_read(git_reflog
**out
, git_refdb
*db
, const char *name
)
279 assert(db
&& db
->backend
);
281 if ((error
= db
->backend
->reflog_read(out
, db
->backend
, name
)) < 0)
284 GIT_REFCOUNT_INC(db
);
290 int git_refdb_should_write_reflog(int *out
, git_refdb
*db
, const git_reference
*ref
)
294 error
= git_repository__configmap_lookup(&logall
, db
->repo
, GIT_CONFIGMAP_LOGALLREFUPDATES
);
298 /* Defaults to the opposite of the repo being bare */
299 if (logall
== GIT_LOGALLREFUPDATES_UNSET
)
300 logall
= !git_repository_is_bare(db
->repo
);
304 case GIT_LOGALLREFUPDATES_FALSE
:
308 case GIT_LOGALLREFUPDATES_TRUE
:
309 /* Only write if it already has a log,
310 * or if it's under heads/, remotes/ or notes/
312 *out
= git_refdb_has_log(db
, ref
->name
) ||
313 !git__prefixcmp(ref
->name
, GIT_REFS_HEADS_DIR
) ||
314 !git__strcmp(ref
->name
, GIT_HEAD_FILE
) ||
315 !git__prefixcmp(ref
->name
, GIT_REFS_REMOTES_DIR
) ||
316 !git__prefixcmp(ref
->name
, GIT_REFS_NOTES_DIR
);
319 case GIT_LOGALLREFUPDATES_ALWAYS
:
327 int git_refdb_should_write_head_reflog(int *out
, git_refdb
*db
, const git_reference
*ref
)
329 git_reference
*head
= NULL
, *resolved
= NULL
;
335 if (ref
->type
== GIT_REFERENCE_SYMBOLIC
) {
340 if ((error
= git_refdb_lookup(&head
, db
, GIT_HEAD_FILE
)) < 0)
343 if (git_reference_type(head
) == GIT_REFERENCE_DIRECT
)
346 /* Go down the symref chain until we find the branch */
347 if ((error
= git_refdb_resolve(&resolved
, db
, git_reference_symbolic_target(head
), -1)) < 0) {
348 if (error
!= GIT_ENOTFOUND
)
351 name
= git_reference_symbolic_target(head
);
352 } else if (git_reference_type(resolved
) == GIT_REFERENCE_SYMBOLIC
) {
353 name
= git_reference_symbolic_target(resolved
);
355 name
= git_reference_name(resolved
);
358 if (strcmp(name
, ref
->name
))
364 git_reference_free(resolved
);
365 git_reference_free(head
);
369 int git_refdb_has_log(git_refdb
*db
, const char *refname
)
371 assert(db
&& refname
);
373 return db
->backend
->has_log(db
->backend
, refname
);
376 int git_refdb_ensure_log(git_refdb
*db
, const char *refname
)
378 assert(db
&& refname
);
380 return db
->backend
->ensure_log(db
->backend
, refname
);
383 int git_refdb_init_backend(git_refdb_backend
*backend
, unsigned int version
)
385 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
386 backend
, version
, git_refdb_backend
, GIT_REFDB_BACKEND_INIT
);
390 int git_refdb_lock(void **payload
, git_refdb
*db
, const char *refname
)
392 assert(payload
&& db
&& refname
);
394 if (!db
->backend
->lock
) {
395 git_error_set(GIT_ERROR_REFERENCE
, "backend does not support locking");
399 return db
->backend
->lock(payload
, db
->backend
, refname
);
402 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
)
406 return db
->backend
->unlock(db
->backend
, payload
, success
, update_reflog
, ref
, sig
, message
);