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.
12 #include "repository.h"
19 #include "sortedcache.h"
20 #include "signature.h"
23 #include <git2/object.h>
24 #include <git2/refdb.h>
25 #include <git2/branch.h>
26 #include <git2/sys/refdb_backend.h>
27 #include <git2/sys/refs.h>
28 #include <git2/sys/reflog.h>
30 #define DEFAULT_NESTING_LEVEL 5
31 #define MAX_NESTING_LEVEL 10
35 PACKREF_WAS_LOOSE
= 2,
36 PACKREF_CANNOT_PEEL
= 4,
50 char name
[GIT_FLEX_ARRAY
];
53 typedef struct refdb_fs_backend
{
54 git_refdb_backend parent
;
57 /* path to git directory */
59 /* path to common objects' directory */
62 git_sortedcache
*refcache
;
64 git_iterator_flag_t iterator_flags
;
65 uint32_t direach_flags
;
69 static int refdb_reflog_fs__delete(git_refdb_backend
*_backend
, const char *name
);
71 static int packref_cmp(const void *a_
, const void *b_
)
73 const struct packref
*a
= a_
, *b
= b_
;
74 return strcmp(a
->name
, b
->name
);
77 static int packed_reload(refdb_fs_backend
*backend
)
80 git_buf packedrefs
= GIT_BUF_INIT
;
81 char *scan
, *eof
, *eol
;
83 if (!backend
->gitpath
)
86 error
= git_sortedcache_lockandload(backend
->refcache
, &packedrefs
);
89 * If we can't find the packed-refs, clear table and return.
90 * Any other error just gets passed through.
91 * If no error, and file wasn't changed, just return.
92 * Anything else means we need to refresh the packed refs.
95 if (error
== GIT_ENOTFOUND
) {
96 git_sortedcache_clear(backend
->refcache
, true);
103 /* At this point, refresh the packed refs from the loaded buffer. */
105 git_sortedcache_clear(backend
->refcache
, false);
107 scan
= (char *)packedrefs
.ptr
;
108 eof
= scan
+ packedrefs
.size
;
110 backend
->peeling_mode
= PEELING_NONE
;
113 static const char *traits_header
= "# pack-refs with: ";
115 if (git__prefixcmp(scan
, traits_header
) == 0) {
116 scan
+= strlen(traits_header
);
117 eol
= strchr(scan
, '\n');
123 if (strstr(scan
, " fully-peeled ") != NULL
) {
124 backend
->peeling_mode
= PEELING_FULL
;
125 } else if (strstr(scan
, " peeled ") != NULL
) {
126 backend
->peeling_mode
= PEELING_STANDARD
;
133 while (scan
< eof
&& *scan
== '#') {
134 if (!(eol
= strchr(scan
, '\n')))
143 /* parse "<OID> <refname>\n" */
145 if (git_oid_fromstr(&oid
, scan
) < 0)
147 scan
+= GIT_OID_HEXSZ
;
151 if (!(eol
= strchr(scan
, '\n')))
157 if (git_sortedcache_upsert((void **)&ref
, backend
->refcache
, scan
) < 0)
161 git_oid_cpy(&ref
->oid
, &oid
);
163 /* look for optional "^<OID>\n" */
166 if (git_oid_fromstr(&oid
, scan
+ 1) < 0)
168 scan
+= GIT_OID_HEXSZ
+ 1;
171 if (!(eol
= strchr(scan
, '\n')))
176 git_oid_cpy(&ref
->peel
, &oid
);
177 ref
->flags
|= PACKREF_HAS_PEEL
;
179 else if (backend
->peeling_mode
== PEELING_FULL
||
180 (backend
->peeling_mode
== PEELING_STANDARD
&&
181 git__prefixcmp(ref
->name
, GIT_REFS_TAGS_DIR
) == 0))
182 ref
->flags
|= PACKREF_CANNOT_PEEL
;
185 git_sortedcache_wunlock(backend
->refcache
);
186 git_buf_dispose(&packedrefs
);
191 git_error_set(GIT_ERROR_REFERENCE
, "corrupted packed references file");
193 git_sortedcache_clear(backend
->refcache
, false);
194 git_sortedcache_wunlock(backend
->refcache
);
195 git_buf_dispose(&packedrefs
);
200 static int loose_parse_oid(
201 git_oid
*oid
, const char *filename
, git_buf
*file_content
)
203 const char *str
= git_buf_cstr(file_content
);
205 if (git_buf_len(file_content
) < GIT_OID_HEXSZ
)
208 /* we need to get 40 OID characters from the file */
209 if (git_oid_fromstr(oid
, str
) < 0)
212 /* If the file is longer than 40 chars, the 41st must be a space */
213 str
+= GIT_OID_HEXSZ
;
214 if (*str
== '\0' || git__isspace(*str
))
218 git_error_set(GIT_ERROR_REFERENCE
, "corrupted loose reference file: %s", filename
);
222 static int loose_readbuffer(git_buf
*buf
, const char *base
, const char *path
)
226 /* build full path to file */
227 if ((error
= git_buf_joinpath(buf
, base
, path
)) < 0 ||
228 (error
= git_futils_readbuffer(buf
, buf
->ptr
)) < 0)
229 git_buf_dispose(buf
);
234 static int loose_lookup_to_packfile(refdb_fs_backend
*backend
, const char *name
)
237 git_buf ref_file
= GIT_BUF_INIT
;
238 struct packref
*ref
= NULL
;
241 /* if we fail to load the loose reference, assume someone changed
242 * the filesystem under us and skip it...
244 if (loose_readbuffer(&ref_file
, backend
->gitpath
, name
) < 0) {
249 /* skip symbolic refs */
250 if (!git__prefixcmp(git_buf_cstr(&ref_file
), GIT_SYMREF
))
253 /* parse OID from file */
254 if ((error
= loose_parse_oid(&oid
, name
, &ref_file
)) < 0)
257 git_sortedcache_wlock(backend
->refcache
);
259 if (!(error
= git_sortedcache_upsert(
260 (void **)&ref
, backend
->refcache
, name
))) {
262 git_oid_cpy(&ref
->oid
, &oid
);
263 ref
->flags
= PACKREF_WAS_LOOSE
;
266 git_sortedcache_wunlock(backend
->refcache
);
269 git_buf_dispose(&ref_file
);
273 static int _dirent_loose_load(void *payload
, git_buf
*full_path
)
275 refdb_fs_backend
*backend
= payload
;
276 const char *file_path
;
278 if (git__suffixcmp(full_path
->ptr
, ".lock") == 0)
281 if (git_path_isdir(full_path
->ptr
)) {
282 int error
= git_path_direach(
283 full_path
, backend
->direach_flags
, _dirent_loose_load
, backend
);
284 /* Race with the filesystem, ignore it */
285 if (error
== GIT_ENOTFOUND
) {
293 file_path
= full_path
->ptr
+ strlen(backend
->gitpath
);
295 return loose_lookup_to_packfile(backend
, file_path
);
299 * Load all the loose references from the repository
300 * into the in-memory Packfile, and build a vector with
301 * all the references so it can be written back to
304 static int packed_loadloose(refdb_fs_backend
*backend
)
307 git_buf refs_path
= GIT_BUF_INIT
;
309 if (git_buf_joinpath(&refs_path
, backend
->gitpath
, GIT_REFS_DIR
) < 0)
313 * Load all the loose files from disk into the Packfile table.
314 * This will overwrite any old packed entries with their
315 * updated loose versions
317 error
= git_path_direach(
318 &refs_path
, backend
->direach_flags
, _dirent_loose_load
, backend
);
320 git_buf_dispose(&refs_path
);
325 static int refdb_fs_backend__exists(
327 git_refdb_backend
*_backend
,
328 const char *ref_name
)
330 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
331 git_buf ref_path
= GIT_BUF_INIT
;
336 if ((error
= packed_reload(backend
)) < 0 ||
337 (error
= git_buf_joinpath(&ref_path
, backend
->gitpath
, ref_name
)) < 0)
340 *exists
= git_path_isfile(ref_path
.ptr
) ||
341 (git_sortedcache_lookup(backend
->refcache
, ref_name
) != NULL
);
343 git_buf_dispose(&ref_path
);
347 static const char *loose_parse_symbolic(git_buf
*file_content
)
349 const unsigned int header_len
= (unsigned int)strlen(GIT_SYMREF
);
350 const char *refname_start
;
352 refname_start
= (const char *)file_content
->ptr
;
354 if (git_buf_len(file_content
) < header_len
+ 1) {
355 git_error_set(GIT_ERROR_REFERENCE
, "corrupted loose reference file");
360 * Assume we have already checked for the header
361 * before calling this function
363 refname_start
+= header_len
;
365 return refname_start
;
369 * Returns whether a reference is stored per worktree or not.
370 * Per-worktree references are:
372 * - all pseudorefs, e.g. HEAD and MERGE_HEAD
373 * - all references stored inside of "refs/bisect/"
375 static bool is_per_worktree_ref(const char *ref_name
)
377 return git__prefixcmp(ref_name
, "refs/") != 0 ||
378 git__prefixcmp(ref_name
, "refs/bisect/") == 0;
381 static int loose_lookup(
383 refdb_fs_backend
*backend
,
384 const char *ref_name
)
386 git_buf ref_file
= GIT_BUF_INIT
;
393 if (is_per_worktree_ref(ref_name
))
394 ref_dir
= backend
->gitpath
;
396 ref_dir
= backend
->commonpath
;
398 if ((error
= loose_readbuffer(&ref_file
, ref_dir
, ref_name
)) < 0)
399 /* cannot read loose ref file - gah */;
400 else if (git__prefixcmp(git_buf_cstr(&ref_file
), GIT_SYMREF
) == 0) {
403 git_buf_rtrim(&ref_file
);
405 if (!(target
= loose_parse_symbolic(&ref_file
)))
407 else if (out
!= NULL
)
408 *out
= git_reference__alloc_symbolic(ref_name
, target
);
412 if (!(error
= loose_parse_oid(&oid
, ref_name
, &ref_file
)) &&
414 *out
= git_reference__alloc(ref_name
, &oid
, NULL
);
417 git_buf_dispose(&ref_file
);
421 static int ref_error_notfound(const char *name
)
423 git_error_set(GIT_ERROR_REFERENCE
, "reference '%s' not found", name
);
424 return GIT_ENOTFOUND
;
427 static int packed_lookup(
429 refdb_fs_backend
*backend
,
430 const char *ref_name
)
433 struct packref
*entry
;
435 if ((error
= packed_reload(backend
)) < 0)
438 if (git_sortedcache_rlock(backend
->refcache
) < 0)
441 entry
= git_sortedcache_lookup(backend
->refcache
, ref_name
);
443 error
= ref_error_notfound(ref_name
);
445 *out
= git_reference__alloc(ref_name
, &entry
->oid
, &entry
->peel
);
450 git_sortedcache_runlock(backend
->refcache
);
455 static int refdb_fs_backend__lookup(
457 git_refdb_backend
*_backend
,
458 const char *ref_name
)
460 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
465 if (!(error
= loose_lookup(out
, backend
, ref_name
)))
468 /* only try to lookup this reference on the packfile if it
469 * wasn't found on the loose refs; not if there was a critical error */
470 if (error
== GIT_ENOTFOUND
) {
472 error
= packed_lookup(out
, backend
, ref_name
);
479 git_reference_iterator parent
;
486 git_sortedcache
*cache
;
491 static void refdb_fs_backend__iterator_free(git_reference_iterator
*_iter
)
493 refdb_fs_iter
*iter
= (refdb_fs_iter
*) _iter
;
495 git_vector_free(&iter
->loose
);
496 git_pool_clear(&iter
->pool
);
497 git_sortedcache_free(iter
->cache
);
501 static int iter_load_loose_paths(refdb_fs_backend
*backend
, refdb_fs_iter
*iter
)
504 git_buf path
= GIT_BUF_INIT
;
505 git_iterator
*fsit
= NULL
;
506 git_iterator_options fsit_opts
= GIT_ITERATOR_OPTIONS_INIT
;
507 const git_index_entry
*entry
= NULL
;
508 const char *ref_prefix
= GIT_REFS_DIR
;
509 size_t ref_prefix_len
= strlen(ref_prefix
);
511 if (!backend
->commonpath
) /* do nothing if no commonpath for loose refs */
514 fsit_opts
.flags
= backend
->iterator_flags
;
517 const char *last_sep
= NULL
;
519 for (pos
= iter
->glob
; *pos
; ++pos
) {
535 ref_prefix
= iter
->glob
;
536 ref_prefix_len
= (last_sep
- ref_prefix
) + 1;
540 if ((error
= git_buf_printf(&path
, "%s/", backend
->commonpath
)) < 0 ||
541 (error
= git_buf_put(&path
, ref_prefix
, ref_prefix_len
)) < 0) {
542 git_buf_dispose(&path
);
546 if ((error
= git_iterator_for_filesystem(&fsit
, path
.ptr
, &fsit_opts
)) < 0) {
547 git_buf_dispose(&path
);
548 return (iter
->glob
&& error
== GIT_ENOTFOUND
)? 0 : error
;
551 error
= git_buf_sets(&path
, ref_prefix
);
553 while (!error
&& !git_iterator_advance(&entry
, fsit
)) {
554 const char *ref_name
;
558 git_buf_truncate(&path
, ref_prefix_len
);
559 git_buf_puts(&path
, entry
->path
);
560 ref_name
= git_buf_cstr(&path
);
562 if (git__suffixcmp(ref_name
, ".lock") == 0 ||
563 (iter
->glob
&& p_fnmatch(iter
->glob
, ref_name
, 0) != 0))
566 git_sortedcache_rlock(backend
->refcache
);
567 ref
= git_sortedcache_lookup(backend
->refcache
, ref_name
);
569 ref
->flags
|= PACKREF_SHADOWED
;
570 git_sortedcache_runlock(backend
->refcache
);
572 ref_dup
= git_pool_strdup(&iter
->pool
, ref_name
);
576 error
= git_vector_insert(&iter
->loose
, ref_dup
);
579 git_iterator_free(fsit
);
580 git_buf_dispose(&path
);
585 static int refdb_fs_backend__iterator_next(
586 git_reference
**out
, git_reference_iterator
*_iter
)
588 int error
= GIT_ITEROVER
;
589 refdb_fs_iter
*iter
= (refdb_fs_iter
*)_iter
;
590 refdb_fs_backend
*backend
= (refdb_fs_backend
*)iter
->parent
.db
->backend
;
593 while (iter
->loose_pos
< iter
->loose
.length
) {
594 const char *path
= git_vector_get(&iter
->loose
, iter
->loose_pos
++);
596 if (loose_lookup(out
, backend
, path
) == 0)
603 if ((error
= git_sortedcache_copy(&iter
->cache
, backend
->refcache
, 1, NULL
, NULL
)) < 0)
607 error
= GIT_ITEROVER
;
608 while (iter
->packed_pos
< git_sortedcache_entrycount(iter
->cache
)) {
609 ref
= git_sortedcache_entry(iter
->cache
, iter
->packed_pos
++);
610 if (!ref
) /* stop now if another thread deleted refs and we past end */
613 if (ref
->flags
& PACKREF_SHADOWED
)
615 if (iter
->glob
&& p_fnmatch(iter
->glob
, ref
->name
, 0) != 0)
618 *out
= git_reference__alloc(ref
->name
, &ref
->oid
, &ref
->peel
);
619 error
= (*out
!= NULL
) ? 0 : -1;
626 static int refdb_fs_backend__iterator_next_name(
627 const char **out
, git_reference_iterator
*_iter
)
629 int error
= GIT_ITEROVER
;
630 refdb_fs_iter
*iter
= (refdb_fs_iter
*)_iter
;
631 refdb_fs_backend
*backend
= (refdb_fs_backend
*)iter
->parent
.db
->backend
;
634 while (iter
->loose_pos
< iter
->loose
.length
) {
635 const char *path
= git_vector_get(&iter
->loose
, iter
->loose_pos
++);
637 if (loose_lookup(NULL
, backend
, path
) == 0) {
646 if ((error
= git_sortedcache_copy(&iter
->cache
, backend
->refcache
, 1, NULL
, NULL
)) < 0)
650 error
= GIT_ITEROVER
;
651 while (iter
->packed_pos
< git_sortedcache_entrycount(iter
->cache
)) {
652 ref
= git_sortedcache_entry(iter
->cache
, iter
->packed_pos
++);
653 if (!ref
) /* stop now if another thread deleted refs and we past end */
656 if (ref
->flags
& PACKREF_SHADOWED
)
658 if (iter
->glob
&& p_fnmatch(iter
->glob
, ref
->name
, 0) != 0)
669 static int refdb_fs_backend__iterator(
670 git_reference_iterator
**out
, git_refdb_backend
*_backend
, const char *glob
)
674 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
678 if ((error
= packed_reload(backend
)) < 0)
681 iter
= git__calloc(1, sizeof(refdb_fs_iter
));
682 GIT_ERROR_CHECK_ALLOC(iter
);
684 git_pool_init(&iter
->pool
, 1);
686 if (git_vector_init(&iter
->loose
, 8, NULL
) < 0)
690 (iter
->glob
= git_pool_strdup(&iter
->pool
, glob
)) == NULL
)
693 iter
->parent
.next
= refdb_fs_backend__iterator_next
;
694 iter
->parent
.next_name
= refdb_fs_backend__iterator_next_name
;
695 iter
->parent
.free
= refdb_fs_backend__iterator_free
;
697 if (iter_load_loose_paths(backend
, iter
) < 0)
700 *out
= (git_reference_iterator
*)iter
;
704 refdb_fs_backend__iterator_free((git_reference_iterator
*)iter
);
708 static bool ref_is_available(
709 const char *old_ref
, const char *new_ref
, const char *this_ref
)
711 if (old_ref
== NULL
|| strcmp(old_ref
, this_ref
)) {
712 size_t reflen
= strlen(this_ref
);
713 size_t newlen
= strlen(new_ref
);
714 size_t cmplen
= reflen
< newlen
? reflen
: newlen
;
715 const char *lead
= reflen
< newlen
? new_ref
: this_ref
;
717 if (!strncmp(new_ref
, this_ref
, cmplen
) && lead
[cmplen
] == '/') {
725 static int reference_path_available(
726 refdb_fs_backend
*backend
,
734 if ((error
= packed_reload(backend
)) < 0)
740 if ((error
= refdb_fs_backend__exists(
741 &exists
, (git_refdb_backend
*)backend
, new_ref
)) < 0) {
746 git_error_set(GIT_ERROR_REFERENCE
,
747 "failed to write reference '%s': a reference with "
748 "that name already exists.", new_ref
);
753 git_sortedcache_rlock(backend
->refcache
);
755 for (i
= 0; i
< git_sortedcache_entrycount(backend
->refcache
); ++i
) {
756 struct packref
*ref
= git_sortedcache_entry(backend
->refcache
, i
);
758 if (ref
&& !ref_is_available(old_ref
, new_ref
, ref
->name
)) {
759 git_sortedcache_runlock(backend
->refcache
);
760 git_error_set(GIT_ERROR_REFERENCE
,
761 "path to reference '%s' collides with existing one", new_ref
);
766 git_sortedcache_runlock(backend
->refcache
);
770 static int loose_lock(git_filebuf
*file
, refdb_fs_backend
*backend
, const char *name
)
772 int error
, filebuf_flags
;
773 git_buf ref_path
= GIT_BUF_INIT
;
776 assert(file
&& backend
&& name
);
778 if (!git_path_isvalid(backend
->repo
, name
, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS
)) {
779 git_error_set(GIT_ERROR_INVALID
, "invalid reference name '%s'", name
);
780 return GIT_EINVALIDSPEC
;
783 if (is_per_worktree_ref(name
))
784 basedir
= backend
->gitpath
;
786 basedir
= backend
->commonpath
;
788 /* Remove a possibly existing empty directory hierarchy
789 * which name would collide with the reference name
791 if ((error
= git_futils_rmdir_r(name
, basedir
, GIT_RMDIR_SKIP_NONEMPTY
)) < 0)
794 if (git_buf_joinpath(&ref_path
, basedir
, name
) < 0)
797 filebuf_flags
= GIT_FILEBUF_FORCE
;
799 filebuf_flags
|= GIT_FILEBUF_FSYNC
;
801 error
= git_filebuf_open(file
, ref_path
.ptr
, filebuf_flags
, GIT_REFS_FILE_MODE
);
803 if (error
== GIT_EDIRECTORY
)
804 git_error_set(GIT_ERROR_REFERENCE
, "cannot lock ref '%s', there are refs beneath that folder", name
);
806 git_buf_dispose(&ref_path
);
810 static int loose_commit(git_filebuf
*file
, const git_reference
*ref
)
814 if (ref
->type
== GIT_REFERENCE_DIRECT
) {
815 char oid
[GIT_OID_HEXSZ
+ 1];
816 git_oid_nfmt(oid
, sizeof(oid
), &ref
->target
.oid
);
818 git_filebuf_printf(file
, "%s\n", oid
);
819 } else if (ref
->type
== GIT_REFERENCE_SYMBOLIC
) {
820 git_filebuf_printf(file
, GIT_SYMREF
"%s\n", ref
->target
.symbolic
);
822 assert(0); /* don't let this happen */
825 return git_filebuf_commit(file
);
828 static int refdb_fs_backend__lock(void **out
, git_refdb_backend
*_backend
, const char *refname
)
832 refdb_fs_backend
*backend
= (refdb_fs_backend
*) _backend
;
834 lock
= git__calloc(1, sizeof(git_filebuf
));
835 GIT_ERROR_CHECK_ALLOC(lock
);
837 if ((error
= loose_lock(lock
, backend
, refname
)) < 0) {
846 static int refdb_fs_backend__write_tail(
847 git_refdb_backend
*_backend
,
848 const git_reference
*ref
,
851 const git_signature
*who
,
853 const git_oid
*old_id
,
854 const char *old_target
);
856 static int refdb_fs_backend__delete_tail(
857 git_refdb_backend
*_backend
,
859 const char *ref_name
,
860 const git_oid
*old_id
, const char *old_target
);
862 static int refdb_fs_backend__unlock(git_refdb_backend
*backend
, void *payload
, int success
, int update_reflog
,
863 const git_reference
*ref
, const git_signature
*sig
, const char *message
)
865 git_filebuf
*lock
= (git_filebuf
*) payload
;
869 error
= refdb_fs_backend__delete_tail(backend
, lock
, ref
->name
, NULL
, NULL
);
871 error
= refdb_fs_backend__write_tail(backend
, ref
, lock
, update_reflog
, sig
, message
, NULL
, NULL
);
873 git_filebuf_cleanup(lock
);
880 * Find out what object this reference resolves to.
882 * For references that point to a 'big' tag (e.g. an
883 * actual tag object on the repository), we need to
884 * cache on the packfile the OID of the object to
885 * which that 'big tag' is pointing to.
887 static int packed_find_peel(refdb_fs_backend
*backend
, struct packref
*ref
)
891 if (ref
->flags
& PACKREF_HAS_PEEL
|| ref
->flags
& PACKREF_CANNOT_PEEL
)
895 * Find the tagged object in the repository
897 if (git_object_lookup(&object
, backend
->repo
, &ref
->oid
, GIT_OBJECT_ANY
) < 0)
901 * If the tagged object is a Tag object, we need to resolve it;
902 * if the ref is actually a 'weak' ref, we don't need to resolve
905 if (git_object_type(object
) == GIT_OBJECT_TAG
) {
906 git_tag
*tag
= (git_tag
*)object
;
909 * Find the object pointed at by this tag
911 git_oid_cpy(&ref
->peel
, git_tag_target_id(tag
));
912 ref
->flags
|= PACKREF_HAS_PEEL
;
915 * The reference has now cached the resolved OID, and is
916 * marked at such. When written to the packfile, it'll be
917 * accompanied by this resolved oid
921 git_object_free(object
);
926 * Write a single reference into a packfile
928 static int packed_write_ref(struct packref
*ref
, git_filebuf
*file
)
930 char oid
[GIT_OID_HEXSZ
+ 1];
931 git_oid_nfmt(oid
, sizeof(oid
), &ref
->oid
);
934 * For references that peel to an object in the repo, we must
935 * write the resulting peel on a separate line, e.g.
937 * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4
938 * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100
940 * This obviously only applies to tags.
941 * The required peels have already been loaded into `ref->peel_target`.
943 if (ref
->flags
& PACKREF_HAS_PEEL
) {
944 char peel
[GIT_OID_HEXSZ
+ 1];
945 git_oid_nfmt(peel
, sizeof(peel
), &ref
->peel
);
947 if (git_filebuf_printf(file
, "%s %s\n^%s\n", oid
, ref
->name
, peel
) < 0)
950 if (git_filebuf_printf(file
, "%s %s\n", oid
, ref
->name
) < 0)
958 * Remove all loose references
960 * Once we have successfully written a packfile,
961 * all the loose references that were packed must be
964 * This is a dangerous method; make sure the packfile
965 * is well-written, because we are destructing references
968 static int packed_remove_loose(refdb_fs_backend
*backend
)
971 git_filebuf lock
= GIT_FILEBUF_INIT
;
972 git_buf ref_content
= GIT_BUF_INIT
;
975 /* backend->refcache is already locked when this is called */
977 for (i
= 0; i
< git_sortedcache_entrycount(backend
->refcache
); ++i
) {
978 struct packref
*ref
= git_sortedcache_entry(backend
->refcache
, i
);
981 if (!ref
|| !(ref
->flags
& PACKREF_WAS_LOOSE
))
984 git_filebuf_cleanup(&lock
);
986 /* We need to stop anybody from updating the ref while we try to do a safe delete */
987 error
= loose_lock(&lock
, backend
, ref
->name
);
988 /* If someone else is updating it, let them do it */
989 if (error
== GIT_EEXISTS
|| error
== GIT_ENOTFOUND
)
993 git_buf_dispose(&ref_content
);
994 git_error_set(GIT_ERROR_REFERENCE
, "failed to lock loose reference '%s'", ref
->name
);
998 error
= git_futils_readbuffer(&ref_content
, lock
.path_original
);
999 /* Someone else beat us to cleaning up the ref, let's simply continue */
1000 if (error
== GIT_ENOTFOUND
)
1003 /* This became a symref between us packing and trying to delete it, so ignore it */
1004 if (!git__prefixcmp(ref_content
.ptr
, GIT_SYMREF
))
1007 /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */
1008 if (loose_parse_oid(¤t_id
, lock
.path_original
, &ref_content
) < 0)
1011 /* If the ref moved since we packed it, we must not delete it */
1012 if (!git_oid_equal(¤t_id
, &ref
->oid
))
1016 * if we fail to remove a single file, this is *not* good,
1017 * but we should keep going and remove as many as possible.
1018 * If we fail to remove, the ref is still in the old state, so
1019 * we haven't lost information.
1021 p_unlink(lock
.path_original
);
1024 git_buf_dispose(&ref_content
);
1025 git_filebuf_cleanup(&lock
);
1030 * Write all the contents in the in-memory packfile to disk.
1032 static int packed_write(refdb_fs_backend
*backend
)
1034 git_sortedcache
*refcache
= backend
->refcache
;
1035 git_filebuf pack_file
= GIT_FILEBUF_INIT
;
1036 int error
, open_flags
= 0;
1039 /* lock the cache to updates while we do this */
1040 if ((error
= git_sortedcache_wlock(refcache
)) < 0)
1044 open_flags
= GIT_FILEBUF_FSYNC
;
1046 /* Open the file! */
1047 if ((error
= git_filebuf_open(&pack_file
, git_sortedcache_path(refcache
), open_flags
, GIT_PACKEDREFS_FILE_MODE
)) < 0)
1050 /* Packfiles have a header... apparently
1051 * This is in fact not required, but we might as well print it
1053 if ((error
= git_filebuf_printf(&pack_file
, "%s\n", GIT_PACKEDREFS_HEADER
)) < 0)
1056 for (i
= 0; i
< git_sortedcache_entrycount(refcache
); ++i
) {
1057 struct packref
*ref
= git_sortedcache_entry(refcache
, i
);
1060 if ((error
= packed_find_peel(backend
, ref
)) < 0)
1063 if ((error
= packed_write_ref(ref
, &pack_file
)) < 0)
1067 /* if we've written all the references properly, we can commit
1068 * the packfile to make the changes effective */
1069 if ((error
= git_filebuf_commit(&pack_file
)) < 0)
1072 /* when and only when the packfile has been properly written,
1073 * we can go ahead and remove the loose refs */
1074 if ((error
= packed_remove_loose(backend
)) < 0)
1077 git_sortedcache_updated(refcache
);
1078 git_sortedcache_wunlock(refcache
);
1080 /* we're good now */
1084 git_filebuf_cleanup(&pack_file
);
1085 git_sortedcache_wunlock(refcache
);
1090 static int reflog_append(refdb_fs_backend
*backend
, const git_reference
*ref
, const git_oid
*old
, const git_oid
*new, const git_signature
*author
, const char *message
);
1091 static int has_reflog(git_repository
*repo
, const char *name
);
1093 static int should_write_reflog(int *write
, git_repository
*repo
, const char *name
)
1097 error
= git_repository__cvar(&logall
, repo
, GIT_CVAR_LOGALLREFUPDATES
);
1101 /* Defaults to the opposite of the repo being bare */
1102 if (logall
== GIT_LOGALLREFUPDATES_UNSET
)
1103 logall
= !git_repository_is_bare(repo
);
1107 case GIT_LOGALLREFUPDATES_FALSE
:
1111 case GIT_LOGALLREFUPDATES_TRUE
:
1112 /* Only write if it already has a log,
1113 * or if it's under heads/, remotes/ or notes/
1115 *write
= has_reflog(repo
, name
) ||
1116 !git__prefixcmp(name
, GIT_REFS_HEADS_DIR
) ||
1117 !git__strcmp(name
, GIT_HEAD_FILE
) ||
1118 !git__prefixcmp(name
, GIT_REFS_REMOTES_DIR
) ||
1119 !git__prefixcmp(name
, GIT_REFS_NOTES_DIR
);
1122 case GIT_LOGALLREFUPDATES_ALWAYS
:
1130 static int cmp_old_ref(int *cmp
, git_refdb_backend
*backend
, const char *name
,
1131 const git_oid
*old_id
, const char *old_target
)
1134 git_reference
*old_ref
= NULL
;
1137 /* It "matches" if there is no old value to compare against */
1138 if (!old_id
&& !old_target
)
1141 if ((error
= refdb_fs_backend__lookup(&old_ref
, backend
, name
)) < 0)
1144 /* If the types don't match, there's no way the values do */
1145 if (old_id
&& old_ref
->type
!= GIT_REFERENCE_DIRECT
) {
1149 if (old_target
&& old_ref
->type
!= GIT_REFERENCE_SYMBOLIC
) {
1154 if (old_id
&& old_ref
->type
== GIT_REFERENCE_DIRECT
)
1155 *cmp
= git_oid_cmp(old_id
, &old_ref
->target
.oid
);
1157 if (old_target
&& old_ref
->type
== GIT_REFERENCE_SYMBOLIC
)
1158 *cmp
= git__strcmp(old_target
, old_ref
->target
.symbolic
);
1161 git_reference_free(old_ref
);
1167 * The git.git comment regarding this, for your viewing pleasure:
1169 * Special hack: If a branch is updated directly and HEAD
1170 * points to it (may happen on the remote side of a push
1171 * for example) then logically the HEAD reflog should be
1173 * A generic solution implies reverse symref information,
1174 * but finding all symrefs pointing to the given branch
1175 * would be rather costly for this rare event (the direct
1176 * update of a branch) to be worth it. So let's cheat and
1177 * check with HEAD only which should cover 99% of all usage
1178 * scenarios (even 100% of the default ones).
1180 static int maybe_append_head(refdb_fs_backend
*backend
, const git_reference
*ref
, const git_signature
*who
, const char *message
)
1184 git_reference
*tmp
= NULL
, *head
= NULL
, *peeled
= NULL
;
1187 if (ref
->type
== GIT_REFERENCE_SYMBOLIC
)
1190 /* if we can't resolve, we use {0}*40 as old id */
1191 if (git_reference_name_to_id(&old_id
, backend
->repo
, ref
->name
) < 0)
1192 memset(&old_id
, 0, sizeof(old_id
));
1194 if ((error
= git_reference_lookup(&head
, backend
->repo
, GIT_HEAD_FILE
)) < 0)
1197 if (git_reference_type(head
) == GIT_REFERENCE_DIRECT
)
1200 if ((error
= git_reference_lookup(&tmp
, backend
->repo
, GIT_HEAD_FILE
)) < 0)
1203 /* Go down the symref chain until we find the branch */
1204 while (git_reference_type(tmp
) == GIT_REFERENCE_SYMBOLIC
) {
1205 error
= git_reference_lookup(&peeled
, backend
->repo
, git_reference_symbolic_target(tmp
));
1209 git_reference_free(tmp
);
1213 if (error
== GIT_ENOTFOUND
) {
1215 name
= git_reference_symbolic_target(tmp
);
1216 } else if (error
< 0) {
1219 name
= git_reference_name(tmp
);
1222 if (strcmp(name
, ref
->name
))
1225 error
= reflog_append(backend
, head
, &old_id
, git_reference_target(ref
), who
, message
);
1228 git_reference_free(tmp
);
1229 git_reference_free(head
);
1233 static int refdb_fs_backend__write(
1234 git_refdb_backend
*_backend
,
1235 const git_reference
*ref
,
1237 const git_signature
*who
,
1238 const char *message
,
1239 const git_oid
*old_id
,
1240 const char *old_target
)
1242 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1243 git_filebuf file
= GIT_FILEBUF_INIT
;
1248 if ((error
= reference_path_available(backend
, ref
->name
, NULL
, force
)) < 0)
1251 /* We need to perform the reflog append and old value check under the ref's lock */
1252 if ((error
= loose_lock(&file
, backend
, ref
->name
)) < 0)
1255 return refdb_fs_backend__write_tail(_backend
, ref
, &file
, true, who
, message
, old_id
, old_target
);
1258 static int refdb_fs_backend__write_tail(
1259 git_refdb_backend
*_backend
,
1260 const git_reference
*ref
,
1263 const git_signature
*who
,
1264 const char *message
,
1265 const git_oid
*old_id
,
1266 const char *old_target
)
1268 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1269 int error
= 0, cmp
= 0, should_write
;
1270 const char *new_target
= NULL
;
1271 const git_oid
*new_id
= NULL
;
1273 if ((error
= cmp_old_ref(&cmp
, _backend
, ref
->name
, old_id
, old_target
)) < 0)
1277 git_error_set(GIT_ERROR_REFERENCE
, "old reference value does not match");
1278 error
= GIT_EMODIFIED
;
1282 if (ref
->type
== GIT_REFERENCE_SYMBOLIC
)
1283 new_target
= ref
->target
.symbolic
;
1285 new_id
= &ref
->target
.oid
;
1287 error
= cmp_old_ref(&cmp
, _backend
, ref
->name
, new_id
, new_target
);
1288 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1291 /* Don't update if we have the same value */
1292 if (!error
&& !cmp
) {
1294 goto on_error
; /* not really error */
1297 if (update_reflog
) {
1298 if ((error
= should_write_reflog(&should_write
, backend
->repo
, ref
->name
)) < 0)
1302 if ((error
= reflog_append(backend
, ref
, NULL
, NULL
, who
, message
)) < 0)
1304 if ((error
= maybe_append_head(backend
, ref
, who
, message
)) < 0)
1309 return loose_commit(file
, ref
);
1312 git_filebuf_cleanup(file
);
1316 static void refdb_fs_backend__try_delete_empty_ref_hierarchie(
1317 refdb_fs_backend
*backend
,
1318 const char *ref_name
,
1321 git_buf relative_path
= GIT_BUF_INIT
;
1322 git_buf base_path
= GIT_BUF_INIT
;
1325 assert(backend
&& ref_name
);
1327 if (git_buf_sets(&relative_path
, ref_name
) < 0)
1330 git_path_squash_slashes(&relative_path
);
1331 if ((commonlen
= git_path_common_dirlen("refs/heads/", git_buf_cstr(&relative_path
))) == strlen("refs/heads/") ||
1332 (commonlen
= git_path_common_dirlen("refs/tags/", git_buf_cstr(&relative_path
))) == strlen("refs/tags/") ||
1333 (commonlen
= git_path_common_dirlen("refs/remotes/", git_buf_cstr(&relative_path
))) == strlen("refs/remotes/")) {
1335 git_buf_truncate(&relative_path
, commonlen
);
1338 if (git_buf_join3(&base_path
, '/', backend
->commonpath
, GIT_REFLOG_DIR
, git_buf_cstr(&relative_path
)) < 0)
1341 if (git_buf_joinpath(&base_path
, backend
->commonpath
, git_buf_cstr(&relative_path
)) < 0)
1345 git_futils_rmdir_r(ref_name
+ commonlen
, git_buf_cstr(&base_path
), GIT_RMDIR_EMPTY_PARENTS
| GIT_RMDIR_SKIP_ROOT
);
1349 git_buf_dispose(&relative_path
);
1350 git_buf_dispose(&base_path
);
1353 static int refdb_fs_backend__delete(
1354 git_refdb_backend
*_backend
,
1355 const char *ref_name
,
1356 const git_oid
*old_id
, const char *old_target
)
1358 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1359 git_filebuf file
= GIT_FILEBUF_INIT
;
1362 assert(backend
&& ref_name
);
1364 if ((error
= loose_lock(&file
, backend
, ref_name
)) < 0)
1367 if ((error
= refdb_reflog_fs__delete(_backend
, ref_name
)) < 0) {
1368 git_filebuf_cleanup(&file
);
1372 return refdb_fs_backend__delete_tail(_backend
, &file
, ref_name
, old_id
, old_target
);
1375 static int refdb_fs_backend__delete_tail(
1376 git_refdb_backend
*_backend
,
1378 const char *ref_name
,
1379 const git_oid
*old_id
, const char *old_target
)
1381 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1382 git_buf loose_path
= GIT_BUF_INIT
;
1384 int error
= 0, cmp
= 0;
1385 bool loose_deleted
= 0;
1387 error
= cmp_old_ref(&cmp
, _backend
, ref_name
, old_id
, old_target
);
1392 git_error_set(GIT_ERROR_REFERENCE
, "old reference value does not match");
1393 error
= GIT_EMODIFIED
;
1397 /* If a loose reference exists, remove it from the filesystem */
1398 if (git_buf_joinpath(&loose_path
, backend
->commonpath
, ref_name
) < 0)
1402 error
= p_unlink(loose_path
.ptr
);
1403 if (error
< 0 && errno
== ENOENT
)
1407 else if (error
== 0)
1410 if ((error
= packed_reload(backend
)) < 0)
1413 /* If a packed reference exists, remove it from the packfile and repack */
1414 if ((error
= git_sortedcache_wlock(backend
->refcache
)) < 0)
1417 if (!(error
= git_sortedcache_lookup_index(
1418 &pack_pos
, backend
->refcache
, ref_name
)))
1419 error
= git_sortedcache_remove(backend
->refcache
, pack_pos
);
1421 git_sortedcache_wunlock(backend
->refcache
);
1423 if (error
== GIT_ENOTFOUND
) {
1424 error
= loose_deleted
? 0 : ref_error_notfound(ref_name
);
1428 error
= packed_write(backend
);
1431 git_buf_dispose(&loose_path
);
1432 git_filebuf_cleanup(file
);
1434 refdb_fs_backend__try_delete_empty_ref_hierarchie(backend
, ref_name
, false);
1438 static int refdb_reflog_fs__rename(git_refdb_backend
*_backend
, const char *old_name
, const char *new_name
);
1440 static int refdb_fs_backend__rename(
1441 git_reference
**out
,
1442 git_refdb_backend
*_backend
,
1443 const char *old_name
,
1444 const char *new_name
,
1446 const git_signature
*who
,
1447 const char *message
)
1449 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1450 git_reference
*old
, *new;
1451 git_filebuf file
= GIT_FILEBUF_INIT
;
1456 if ((error
= reference_path_available(
1457 backend
, new_name
, old_name
, force
)) < 0 ||
1458 (error
= refdb_fs_backend__lookup(&old
, _backend
, old_name
)) < 0)
1461 if ((error
= refdb_fs_backend__delete(_backend
, old_name
, NULL
, NULL
)) < 0) {
1462 git_reference_free(old
);
1466 new = git_reference__set_name(old
, new_name
);
1468 git_reference_free(old
);
1472 if ((error
= loose_lock(&file
, backend
, new->name
)) < 0) {
1473 git_reference_free(new);
1477 /* Try to rename the refog; it's ok if the old doesn't exist */
1478 error
= refdb_reflog_fs__rename(_backend
, old_name
, new_name
);
1479 if (((error
== 0) || (error
== GIT_ENOTFOUND
)) &&
1480 ((error
= reflog_append(backend
, new, git_reference_target(new), NULL
, who
, message
)) < 0)) {
1481 git_reference_free(new);
1482 git_filebuf_cleanup(&file
);
1487 git_reference_free(new);
1488 git_filebuf_cleanup(&file
);
1493 if ((error
= loose_commit(&file
, new)) < 0 || out
== NULL
) {
1494 git_reference_free(new);
1502 static int refdb_fs_backend__compress(git_refdb_backend
*_backend
)
1505 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1509 if ((error
= packed_reload(backend
)) < 0 || /* load the existing packfile */
1510 (error
= packed_loadloose(backend
)) < 0 || /* add all the loose refs */
1511 (error
= packed_write(backend
)) < 0) /* write back to disk */
1517 static void refdb_fs_backend__free(git_refdb_backend
*_backend
)
1519 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1523 git_sortedcache_free(backend
->refcache
);
1524 git__free(backend
->gitpath
);
1525 git__free(backend
->commonpath
);
1529 static char *setup_namespace(git_repository
*repo
, const char *in
)
1531 git_buf path
= GIT_BUF_INIT
;
1532 char *parts
, *start
, *end
, *out
= NULL
;
1537 git_buf_puts(&path
, in
);
1539 /* if the repo is not namespaced, nothing else to do */
1540 if (repo
->namespace == NULL
) {
1541 out
= git_buf_detach(&path
);
1545 parts
= end
= git__strdup(repo
->namespace);
1550 * From `man gitnamespaces`:
1551 * namespaces which include a / will expand to a hierarchy
1552 * of namespaces; for example, GIT_NAMESPACE=foo/bar will store
1553 * refs under refs/namespaces/foo/refs/namespaces/bar/
1555 while ((start
= git__strsep(&end
, "/")) != NULL
)
1556 git_buf_printf(&path
, "refs/namespaces/%s/", start
);
1558 git_buf_printf(&path
, "refs/namespaces/%s/refs", end
);
1561 /* Make sure that the folder with the namespace exists */
1562 if (git_futils_mkdir_relative(git_buf_cstr(&path
), in
, 0777,
1563 GIT_MKDIR_PATH
, NULL
) < 0)
1566 /* Return root of the namespaced gitpath, i.e. without the trailing '/refs' */
1567 git_buf_rtruncate_at_char(&path
, '/');
1568 out
= git_buf_detach(&path
);
1571 git_buf_dispose(&path
);
1575 static int reflog_alloc(git_reflog
**reflog
, const char *name
)
1581 log
= git__calloc(1, sizeof(git_reflog
));
1582 GIT_ERROR_CHECK_ALLOC(log
);
1584 log
->ref_name
= git__strdup(name
);
1585 GIT_ERROR_CHECK_ALLOC(log
->ref_name
);
1587 if (git_vector_init(&log
->entries
, 0, NULL
) < 0) {
1588 git__free(log
->ref_name
);
1598 static int reflog_parse(git_reflog
*log
, const char *buf
, size_t buf_size
)
1601 git_reflog_entry
*entry
;
1603 #define seek_forward(_increase) do { \
1604 if (_increase >= buf_size) { \
1605 git_error_set(GIT_ERROR_INVALID, "ran out of data while parsing reflog"); \
1609 buf_size -= _increase; \
1612 while (buf_size
> GIT_REFLOG_SIZE_MIN
) {
1613 entry
= git__calloc(1, sizeof(git_reflog_entry
));
1614 GIT_ERROR_CHECK_ALLOC(entry
);
1616 entry
->committer
= git__calloc(1, sizeof(git_signature
));
1617 GIT_ERROR_CHECK_ALLOC(entry
->committer
);
1619 if (git_oid_fromstrn(&entry
->oid_old
, buf
, GIT_OID_HEXSZ
) < 0)
1621 seek_forward(GIT_OID_HEXSZ
+ 1);
1623 if (git_oid_fromstrn(&entry
->oid_cur
, buf
, GIT_OID_HEXSZ
) < 0)
1625 seek_forward(GIT_OID_HEXSZ
+ 1);
1629 /* Seek forward to the end of the signature. */
1630 while (*buf
&& *buf
!= '\t' && *buf
!= '\n')
1633 if (git_signature__parse(entry
->committer
, &ptr
, buf
+ 1, NULL
, *buf
) < 0)
1637 /* We got a message. Read everything till we reach LF. */
1641 while (*buf
&& *buf
!= '\n')
1644 entry
->msg
= git__strndup(ptr
, buf
- ptr
);
1645 GIT_ERROR_CHECK_ALLOC(entry
->msg
);
1649 while (*buf
&& *buf
== '\n' && buf_size
> 1)
1652 if (git_vector_insert(&log
->entries
, entry
) < 0)
1661 git_reflog_entry__free(entry
);
1666 static int create_new_reflog_file(const char *filepath
)
1670 if ((error
= git_futils_mkpath2file(filepath
, GIT_REFLOG_DIR_MODE
)) < 0)
1673 if ((fd
= p_open(filepath
,
1675 GIT_REFLOG_FILE_MODE
)) < 0)
1681 GIT_INLINE(int) retrieve_reflog_path(git_buf
*path
, git_repository
*repo
, const char *name
)
1683 if (strcmp(name
, GIT_HEAD_FILE
) == 0)
1684 return git_buf_join3(path
, '/', repo
->gitdir
, GIT_REFLOG_DIR
, name
);
1685 return git_buf_join3(path
, '/', repo
->commondir
, GIT_REFLOG_DIR
, name
);
1688 static int refdb_reflog_fs__ensure_log(git_refdb_backend
*_backend
, const char *name
)
1690 refdb_fs_backend
*backend
;
1691 git_repository
*repo
;
1692 git_buf path
= GIT_BUF_INIT
;
1695 assert(_backend
&& name
);
1697 backend
= (refdb_fs_backend
*) _backend
;
1698 repo
= backend
->repo
;
1700 if ((error
= retrieve_reflog_path(&path
, repo
, name
)) < 0)
1703 error
= create_new_reflog_file(git_buf_cstr(&path
));
1704 git_buf_dispose(&path
);
1709 static int has_reflog(git_repository
*repo
, const char *name
)
1712 git_buf path
= GIT_BUF_INIT
;
1714 if (retrieve_reflog_path(&path
, repo
, name
) < 0)
1717 ret
= git_path_isfile(git_buf_cstr(&path
));
1720 git_buf_dispose(&path
);
1724 static int refdb_reflog_fs__has_log(git_refdb_backend
*_backend
, const char *name
)
1726 refdb_fs_backend
*backend
;
1728 assert(_backend
&& name
);
1730 backend
= (refdb_fs_backend
*) _backend
;
1732 return has_reflog(backend
->repo
, name
);
1735 static int refdb_reflog_fs__read(git_reflog
**out
, git_refdb_backend
*_backend
, const char *name
)
1738 git_buf log_path
= GIT_BUF_INIT
;
1739 git_buf log_file
= GIT_BUF_INIT
;
1740 git_reflog
*log
= NULL
;
1741 git_repository
*repo
;
1742 refdb_fs_backend
*backend
;
1744 assert(out
&& _backend
&& name
);
1746 backend
= (refdb_fs_backend
*) _backend
;
1747 repo
= backend
->repo
;
1749 if (reflog_alloc(&log
, name
) < 0)
1752 if (retrieve_reflog_path(&log_path
, repo
, name
) < 0)
1755 error
= git_futils_readbuffer(&log_file
, git_buf_cstr(&log_path
));
1756 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1759 if ((error
== GIT_ENOTFOUND
) &&
1760 ((error
= create_new_reflog_file(git_buf_cstr(&log_path
))) < 0))
1763 if ((error
= reflog_parse(log
,
1764 git_buf_cstr(&log_file
), git_buf_len(&log_file
))) < 0)
1771 git_reflog_free(log
);
1774 git_buf_dispose(&log_file
);
1775 git_buf_dispose(&log_path
);
1780 static int serialize_reflog_entry(
1782 const git_oid
*oid_old
,
1783 const git_oid
*oid_new
,
1784 const git_signature
*committer
,
1787 char raw_old
[GIT_OID_HEXSZ
+1];
1788 char raw_new
[GIT_OID_HEXSZ
+1];
1790 git_oid_tostr(raw_old
, GIT_OID_HEXSZ
+1, oid_old
);
1791 git_oid_tostr(raw_new
, GIT_OID_HEXSZ
+1, oid_new
);
1795 git_buf_puts(buf
, raw_old
);
1796 git_buf_putc(buf
, ' ');
1797 git_buf_puts(buf
, raw_new
);
1799 git_signature__writebuf(buf
, " ", committer
);
1801 /* drop trailing LF */
1805 git_buf_putc(buf
, '\t');
1806 git_buf_puts(buf
, msg
);
1809 git_buf_putc(buf
, '\n');
1811 return git_buf_oom(buf
);
1814 static int lock_reflog(git_filebuf
*file
, refdb_fs_backend
*backend
, const char *refname
)
1816 git_repository
*repo
;
1817 git_buf log_path
= GIT_BUF_INIT
;
1820 repo
= backend
->repo
;
1822 if (!git_path_isvalid(backend
->repo
, refname
, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS
)) {
1823 git_error_set(GIT_ERROR_INVALID
, "invalid reference name '%s'", refname
);
1824 return GIT_EINVALIDSPEC
;
1827 if (retrieve_reflog_path(&log_path
, repo
, refname
) < 0)
1830 if (!git_path_isfile(git_buf_cstr(&log_path
))) {
1831 git_error_set(GIT_ERROR_INVALID
,
1832 "log file for reference '%s' doesn't exist", refname
);
1837 error
= git_filebuf_open(file
, git_buf_cstr(&log_path
), 0, GIT_REFLOG_FILE_MODE
);
1840 git_buf_dispose(&log_path
);
1845 static int refdb_reflog_fs__write(git_refdb_backend
*_backend
, git_reflog
*reflog
)
1849 git_reflog_entry
*entry
;
1850 refdb_fs_backend
*backend
;
1851 git_buf log
= GIT_BUF_INIT
;
1852 git_filebuf fbuf
= GIT_FILEBUF_INIT
;
1854 assert(_backend
&& reflog
);
1856 backend
= (refdb_fs_backend
*) _backend
;
1858 if ((error
= lock_reflog(&fbuf
, backend
, reflog
->ref_name
)) < 0)
1861 git_vector_foreach(&reflog
->entries
, i
, entry
) {
1862 if (serialize_reflog_entry(&log
, &(entry
->oid_old
), &(entry
->oid_cur
), entry
->committer
, entry
->msg
) < 0)
1865 if ((error
= git_filebuf_write(&fbuf
, log
.ptr
, log
.size
)) < 0)
1869 error
= git_filebuf_commit(&fbuf
);
1873 git_filebuf_cleanup(&fbuf
);
1876 git_buf_dispose(&log
);
1881 /* Append to the reflog, must be called under reference lock */
1882 static int reflog_append(refdb_fs_backend
*backend
, const git_reference
*ref
, const git_oid
*old
, const git_oid
*new, const git_signature
*who
, const char *message
)
1884 int error
, is_symbolic
, open_flags
;
1885 git_oid old_id
= {{0}}, new_id
= {{0}};
1886 git_buf buf
= GIT_BUF_INIT
, path
= GIT_BUF_INIT
;
1887 git_repository
*repo
= backend
->repo
;
1889 is_symbolic
= ref
->type
== GIT_REFERENCE_SYMBOLIC
;
1891 /* "normal" symbolic updates do not write */
1893 strcmp(ref
->name
, GIT_HEAD_FILE
) &&
1897 /* From here on is_symoblic also means that it's HEAD */
1900 git_oid_cpy(&old_id
, old
);
1902 error
= git_reference_name_to_id(&old_id
, repo
, ref
->name
);
1903 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1908 git_oid_cpy(&new_id
, new);
1911 git_oid_cpy(&new_id
, git_reference_target(ref
));
1913 error
= git_reference_name_to_id(&new_id
, repo
, git_reference_symbolic_target(ref
));
1914 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1916 /* detaching HEAD does not create an entry */
1917 if (error
== GIT_ENOTFOUND
)
1924 if ((error
= serialize_reflog_entry(&buf
, &old_id
, &new_id
, who
, message
)) < 0)
1927 if ((error
= retrieve_reflog_path(&path
, repo
, ref
->name
)) < 0)
1930 if (((error
= git_futils_mkpath2file(git_buf_cstr(&path
), 0777)) < 0) &&
1931 (error
!= GIT_EEXISTS
)) {
1935 /* If the new branch matches part of the namespace of a previously deleted branch,
1936 * there maybe an obsolete/unused directory (or directory hierarchy) in the way.
1938 if (git_path_isdir(git_buf_cstr(&path
))) {
1939 if ((error
= git_futils_rmdir_r(git_buf_cstr(&path
), NULL
, GIT_RMDIR_SKIP_NONEMPTY
)) < 0) {
1940 if (error
== GIT_ENOTFOUND
)
1942 } else if (git_path_isdir(git_buf_cstr(&path
))) {
1943 git_error_set(GIT_ERROR_REFERENCE
, "cannot create reflog at '%s', there are reflogs beneath that folder",
1945 error
= GIT_EDIRECTORY
;
1952 open_flags
= O_WRONLY
| O_CREAT
| O_APPEND
;
1955 open_flags
|= O_FSYNC
;
1957 error
= git_futils_writebuffer(&buf
, git_buf_cstr(&path
), open_flags
, GIT_REFLOG_FILE_MODE
);
1960 git_buf_dispose(&buf
);
1961 git_buf_dispose(&path
);
1966 static int refdb_reflog_fs__rename(git_refdb_backend
*_backend
, const char *old_name
, const char *new_name
)
1969 git_buf old_path
= GIT_BUF_INIT
;
1970 git_buf new_path
= GIT_BUF_INIT
;
1971 git_buf temp_path
= GIT_BUF_INIT
;
1972 git_buf normalized
= GIT_BUF_INIT
;
1973 git_repository
*repo
;
1974 refdb_fs_backend
*backend
;
1976 assert(_backend
&& old_name
&& new_name
);
1978 backend
= (refdb_fs_backend
*) _backend
;
1979 repo
= backend
->repo
;
1981 if ((error
= git_reference__normalize_name(
1982 &normalized
, new_name
, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL
)) < 0)
1985 if (git_buf_joinpath(&temp_path
, repo
->gitdir
, GIT_REFLOG_DIR
) < 0)
1988 if (git_buf_joinpath(&old_path
, git_buf_cstr(&temp_path
), old_name
) < 0)
1991 if (git_buf_joinpath(&new_path
, git_buf_cstr(&temp_path
), git_buf_cstr(&normalized
)) < 0)
1994 if (!git_path_exists(git_buf_cstr(&old_path
))) {
1995 error
= GIT_ENOTFOUND
;
2000 * Move the reflog to a temporary place. This two-phase renaming is required
2001 * in order to cope with funny renaming use cases when one tries to move a reference
2002 * to a partially colliding namespace:
2004 * - a/b/c/d -> a/b/c
2006 if (git_buf_joinpath(&temp_path
, git_buf_cstr(&temp_path
), "temp_reflog") < 0)
2009 if ((fd
= git_futils_mktmp(&temp_path
, git_buf_cstr(&temp_path
), GIT_REFLOG_FILE_MODE
)) < 0) {
2016 if (p_rename(git_buf_cstr(&old_path
), git_buf_cstr(&temp_path
)) < 0) {
2017 git_error_set(GIT_ERROR_OS
, "failed to rename reflog for %s", new_name
);
2022 if (git_path_isdir(git_buf_cstr(&new_path
)) &&
2023 (git_futils_rmdir_r(git_buf_cstr(&new_path
), NULL
, GIT_RMDIR_SKIP_NONEMPTY
) < 0)) {
2028 if (git_futils_mkpath2file(git_buf_cstr(&new_path
), GIT_REFLOG_DIR_MODE
) < 0) {
2033 if (p_rename(git_buf_cstr(&temp_path
), git_buf_cstr(&new_path
)) < 0) {
2034 git_error_set(GIT_ERROR_OS
, "failed to rename reflog for %s", new_name
);
2039 git_buf_dispose(&temp_path
);
2040 git_buf_dispose(&old_path
);
2041 git_buf_dispose(&new_path
);
2042 git_buf_dispose(&normalized
);
2047 static int refdb_reflog_fs__delete(git_refdb_backend
*_backend
, const char *name
)
2049 refdb_fs_backend
*backend
= (refdb_fs_backend
*) _backend
;
2050 git_buf path
= GIT_BUF_INIT
;
2053 assert(_backend
&& name
);
2055 if ((error
= retrieve_reflog_path(&path
, backend
->repo
, name
)) < 0)
2058 if (!git_path_exists(path
.ptr
))
2061 if ((error
= p_unlink(path
.ptr
)) < 0)
2064 refdb_fs_backend__try_delete_empty_ref_hierarchie(backend
, name
, true);
2067 git_buf_dispose(&path
);
2072 int git_refdb_backend_fs(
2073 git_refdb_backend
**backend_out
,
2074 git_repository
*repository
)
2077 git_buf gitpath
= GIT_BUF_INIT
;
2078 refdb_fs_backend
*backend
;
2080 backend
= git__calloc(1, sizeof(refdb_fs_backend
));
2081 GIT_ERROR_CHECK_ALLOC(backend
);
2083 backend
->repo
= repository
;
2085 if (repository
->gitdir
) {
2086 backend
->gitpath
= setup_namespace(repository
, repository
->gitdir
);
2088 if (backend
->gitpath
== NULL
)
2092 if (repository
->commondir
) {
2093 backend
->commonpath
= setup_namespace(repository
, repository
->commondir
);
2095 if (backend
->commonpath
== NULL
)
2099 if (git_buf_joinpath(&gitpath
, backend
->commonpath
, GIT_PACKEDREFS_FILE
) < 0 ||
2100 git_sortedcache_new(
2101 &backend
->refcache
, offsetof(struct packref
, name
),
2102 NULL
, NULL
, packref_cmp
, git_buf_cstr(&gitpath
)) < 0)
2105 git_buf_dispose(&gitpath
);
2107 if (!git_repository__cvar(&t
, backend
->repo
, GIT_CVAR_IGNORECASE
) && t
) {
2108 backend
->iterator_flags
|= GIT_ITERATOR_IGNORE_CASE
;
2109 backend
->direach_flags
|= GIT_PATH_DIR_IGNORE_CASE
;
2111 if (!git_repository__cvar(&t
, backend
->repo
, GIT_CVAR_PRECOMPOSE
) && t
) {
2112 backend
->iterator_flags
|= GIT_ITERATOR_PRECOMPOSE_UNICODE
;
2113 backend
->direach_flags
|= GIT_PATH_DIR_PRECOMPOSE_UNICODE
;
2115 if ((!git_repository__cvar(&t
, backend
->repo
, GIT_CVAR_FSYNCOBJECTFILES
) && t
) ||
2116 git_repository__fsync_gitdir
)
2118 backend
->iterator_flags
|= GIT_ITERATOR_DESCEND_SYMLINKS
;
2120 backend
->parent
.exists
= &refdb_fs_backend__exists
;
2121 backend
->parent
.lookup
= &refdb_fs_backend__lookup
;
2122 backend
->parent
.iterator
= &refdb_fs_backend__iterator
;
2123 backend
->parent
.write
= &refdb_fs_backend__write
;
2124 backend
->parent
.del
= &refdb_fs_backend__delete
;
2125 backend
->parent
.rename
= &refdb_fs_backend__rename
;
2126 backend
->parent
.compress
= &refdb_fs_backend__compress
;
2127 backend
->parent
.lock
= &refdb_fs_backend__lock
;
2128 backend
->parent
.unlock
= &refdb_fs_backend__unlock
;
2129 backend
->parent
.has_log
= &refdb_reflog_fs__has_log
;
2130 backend
->parent
.ensure_log
= &refdb_reflog_fs__ensure_log
;
2131 backend
->parent
.free
= &refdb_fs_backend__free
;
2132 backend
->parent
.reflog_read
= &refdb_reflog_fs__read
;
2133 backend
->parent
.reflog_write
= &refdb_reflog_fs__write
;
2134 backend
->parent
.reflog_rename
= &refdb_reflog_fs__rename
;
2135 backend
->parent
.reflog_delete
= &refdb_reflog_fs__delete
;
2137 *backend_out
= (git_refdb_backend
*)backend
;
2141 git_buf_dispose(&gitpath
);
2142 git__free(backend
->gitpath
);
2143 git__free(backend
->commonpath
);