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
)
30 db
= git__calloc(1, sizeof(*db
));
31 GIT_ERROR_CHECK_ALLOC(db
);
40 int git_refdb_open(git_refdb
**out
, git_repository
*repo
)
43 git_refdb_backend
*dir
;
50 if (git_refdb_new(&db
, repo
) < 0)
53 /* Add the default (filesystem) backend */
54 if (git_refdb_backend_fs(&dir
, repo
) < 0) {
66 static void refdb_free_backend(git_refdb
*db
)
69 db
->backend
->free(db
->backend
);
72 int git_refdb_set_backend(git_refdb
*db
, git_refdb_backend
*backend
)
74 GIT_ERROR_CHECK_VERSION(backend
, GIT_REFDB_BACKEND_VERSION
, "git_refdb_backend");
76 if (!backend
->exists
|| !backend
->lookup
|| !backend
->iterator
||
77 !backend
->write
|| !backend
->rename
|| !backend
->del
||
78 !backend
->has_log
|| !backend
->ensure_log
|| !backend
->free
||
79 !backend
->reflog_read
|| !backend
->reflog_write
||
80 !backend
->reflog_rename
|| !backend
->reflog_delete
||
81 (backend
->lock
&& !backend
->unlock
)) {
82 git_error_set(GIT_ERROR_REFERENCE
, "incomplete refdb backend implementation");
86 refdb_free_backend(db
);
87 db
->backend
= backend
;
92 int git_refdb_compress(git_refdb
*db
)
96 if (db
->backend
->compress
)
97 return db
->backend
->compress(db
->backend
);
102 void git_refdb__free(git_refdb
*db
)
104 refdb_free_backend(db
);
105 git__memzero(db
, sizeof(*db
));
109 void git_refdb_free(git_refdb
*db
)
114 GIT_REFCOUNT_DEC(db
, git_refdb__free
);
117 int git_refdb_exists(int *exists
, git_refdb
*refdb
, const char *ref_name
)
119 GIT_ASSERT_ARG(exists
);
120 GIT_ASSERT_ARG(refdb
);
121 GIT_ASSERT_ARG(refdb
->backend
);
123 return refdb
->backend
->exists(exists
, refdb
->backend
, ref_name
);
126 int git_refdb_lookup(git_reference
**out
, git_refdb
*db
, const char *ref_name
)
132 GIT_ASSERT_ARG(db
->backend
);
134 GIT_ASSERT_ARG(ref_name
);
136 error
= db
->backend
->lookup(&ref
, db
->backend
, ref_name
);
140 GIT_REFCOUNT_INC(db
);
147 int git_refdb_resolve(
150 const char *ref_name
,
153 git_reference
*ref
= NULL
;
154 int error
= 0, nesting
;
158 if (max_nesting
> MAX_NESTING_LEVEL
)
159 max_nesting
= MAX_NESTING_LEVEL
;
160 else if (max_nesting
< 0)
161 max_nesting
= DEFAULT_NESTING_LEVEL
;
163 if ((error
= git_refdb_lookup(&ref
, db
, ref_name
)) < 0)
166 for (nesting
= 0; nesting
< max_nesting
; nesting
++) {
167 git_reference
*resolved
;
169 if (ref
->type
== GIT_REFERENCE_DIRECT
)
172 if ((error
= git_refdb_lookup(&resolved
, db
, git_reference_symbolic_target(ref
))) < 0) {
173 /* If we found a symbolic reference with a nonexistent target, return it. */
174 if (error
== GIT_ENOTFOUND
) {
182 git_reference_free(ref
);
186 if (ref
->type
!= GIT_REFERENCE_DIRECT
&& max_nesting
!= 0) {
187 git_error_set(GIT_ERROR_REFERENCE
,
188 "cannot resolve reference (>%u levels deep)", max_nesting
);
196 git_reference_free(ref
);
200 int git_refdb_iterator(git_reference_iterator
**out
, git_refdb
*db
, const char *glob
)
204 if (!db
->backend
|| !db
->backend
->iterator
) {
205 git_error_set(GIT_ERROR_REFERENCE
, "this backend doesn't support iterators");
209 if ((error
= db
->backend
->iterator(out
, db
->backend
, glob
)) < 0)
212 GIT_REFCOUNT_INC(db
);
218 int git_refdb_iterator_next(git_reference
**out
, git_reference_iterator
*iter
)
222 if ((error
= iter
->next(out
, iter
)) < 0)
225 GIT_REFCOUNT_INC(iter
->db
);
226 (*out
)->db
= iter
->db
;
231 int git_refdb_iterator_next_name(const char **out
, git_reference_iterator
*iter
)
233 return iter
->next_name(out
, iter
);
236 void git_refdb_iterator_free(git_reference_iterator
*iter
)
238 GIT_REFCOUNT_DEC(iter
->db
, git_refdb__free
);
242 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
)
245 GIT_ASSERT_ARG(db
->backend
);
247 GIT_REFCOUNT_INC(db
);
250 return db
->backend
->write(db
->backend
, ref
, force
, who
, message
, old_id
, old_target
);
253 int git_refdb_rename(
256 const char *old_name
,
257 const char *new_name
,
259 const git_signature
*who
,
265 GIT_ASSERT_ARG(db
->backend
);
267 error
= db
->backend
->rename(out
, db
->backend
, old_name
, new_name
, force
, who
, message
);
272 GIT_REFCOUNT_INC(db
);
279 int git_refdb_delete(struct git_refdb
*db
, const char *ref_name
, const git_oid
*old_id
, const char *old_target
)
282 GIT_ASSERT_ARG(db
->backend
);
284 return db
->backend
->del(db
->backend
, ref_name
, old_id
, old_target
);
287 int git_refdb_reflog_read(git_reflog
**out
, git_refdb
*db
, const char *name
)
292 GIT_ASSERT_ARG(db
->backend
);
294 if ((error
= db
->backend
->reflog_read(out
, db
->backend
, name
)) < 0)
297 GIT_REFCOUNT_INC(db
);
303 int git_refdb_should_write_reflog(int *out
, git_refdb
*db
, const git_reference
*ref
)
307 error
= git_repository__configmap_lookup(&logall
, db
->repo
, GIT_CONFIGMAP_LOGALLREFUPDATES
);
311 /* Defaults to the opposite of the repo being bare */
312 if (logall
== GIT_LOGALLREFUPDATES_UNSET
)
313 logall
= !git_repository_is_bare(db
->repo
);
317 case GIT_LOGALLREFUPDATES_FALSE
:
321 case GIT_LOGALLREFUPDATES_TRUE
:
322 /* Only write if it already has a log,
323 * or if it's under heads/, remotes/ or notes/
325 *out
= git_refdb_has_log(db
, ref
->name
) ||
326 !git__prefixcmp(ref
->name
, GIT_REFS_HEADS_DIR
) ||
327 !git__strcmp(ref
->name
, GIT_HEAD_FILE
) ||
328 !git__prefixcmp(ref
->name
, GIT_REFS_REMOTES_DIR
) ||
329 !git__prefixcmp(ref
->name
, GIT_REFS_NOTES_DIR
);
332 case GIT_LOGALLREFUPDATES_ALWAYS
:
340 int git_refdb_should_write_head_reflog(int *out
, git_refdb
*db
, const git_reference
*ref
)
342 git_reference
*head
= NULL
, *resolved
= NULL
;
348 if (ref
->type
== GIT_REFERENCE_SYMBOLIC
) {
353 if ((error
= git_refdb_lookup(&head
, db
, GIT_HEAD_FILE
)) < 0)
356 if (git_reference_type(head
) == GIT_REFERENCE_DIRECT
)
359 /* Go down the symref chain until we find the branch */
360 if ((error
= git_refdb_resolve(&resolved
, db
, git_reference_symbolic_target(head
), -1)) < 0) {
361 if (error
!= GIT_ENOTFOUND
)
364 name
= git_reference_symbolic_target(head
);
365 } else if (git_reference_type(resolved
) == GIT_REFERENCE_SYMBOLIC
) {
366 name
= git_reference_symbolic_target(resolved
);
368 name
= git_reference_name(resolved
);
371 if (strcmp(name
, ref
->name
))
377 git_reference_free(resolved
);
378 git_reference_free(head
);
382 int git_refdb_has_log(git_refdb
*db
, const char *refname
)
385 GIT_ASSERT_ARG(refname
);
387 return db
->backend
->has_log(db
->backend
, refname
);
390 int git_refdb_ensure_log(git_refdb
*db
, const char *refname
)
393 GIT_ASSERT_ARG(refname
);
395 return db
->backend
->ensure_log(db
->backend
, refname
);
398 int git_refdb_init_backend(git_refdb_backend
*backend
, unsigned int version
)
400 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
401 backend
, version
, git_refdb_backend
, GIT_REFDB_BACKEND_INIT
);
405 int git_refdb_lock(void **payload
, git_refdb
*db
, const char *refname
)
407 GIT_ASSERT_ARG(payload
);
409 GIT_ASSERT_ARG(refname
);
411 if (!db
->backend
->lock
) {
412 git_error_set(GIT_ERROR_REFERENCE
, "backend does not support locking");
416 return db
->backend
->lock(payload
, db
->backend
, refname
);
419 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
)
423 return db
->backend
->unlock(db
->backend
, payload
, success
, update_reflog
, ref
, sig
, message
);