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"
20 #include "sortedcache.h"
21 #include "signature.h"
22 #include "wildmatch.h"
25 #include <git2/object.h>
26 #include <git2/refdb.h>
27 #include <git2/branch.h>
28 #include <git2/sys/refdb_backend.h>
29 #include <git2/sys/refs.h>
30 #include <git2/sys/reflog.h>
32 #define DEFAULT_NESTING_LEVEL 5
33 #define MAX_NESTING_LEVEL 10
37 PACKREF_WAS_LOOSE
= 2,
38 PACKREF_CANNOT_PEEL
= 4,
52 char name
[GIT_FLEX_ARRAY
];
55 typedef struct refdb_fs_backend
{
56 git_refdb_backend parent
;
59 /* path to git directory */
61 /* path to common objects' directory */
64 git_sortedcache
*refcache
;
66 git_iterator_flag_t iterator_flags
;
67 uint32_t direach_flags
;
71 static int refdb_reflog_fs__delete(git_refdb_backend
*_backend
, const char *name
);
73 static int packref_cmp(const void *a_
, const void *b_
)
75 const struct packref
*a
= a_
, *b
= b_
;
76 return strcmp(a
->name
, b
->name
);
79 static int packed_reload(refdb_fs_backend
*backend
)
82 git_buf packedrefs
= GIT_BUF_INIT
;
83 char *scan
, *eof
, *eol
;
85 if (!backend
->gitpath
)
88 error
= git_sortedcache_lockandload(backend
->refcache
, &packedrefs
);
91 * If we can't find the packed-refs, clear table and return.
92 * Any other error just gets passed through.
93 * If no error, and file wasn't changed, just return.
94 * Anything else means we need to refresh the packed refs.
97 if (error
== GIT_ENOTFOUND
) {
98 git_sortedcache_clear(backend
->refcache
, true);
105 /* At this point, refresh the packed refs from the loaded buffer. */
107 git_sortedcache_clear(backend
->refcache
, false);
109 scan
= (char *)packedrefs
.ptr
;
110 eof
= scan
+ packedrefs
.size
;
112 backend
->peeling_mode
= PEELING_NONE
;
115 static const char *traits_header
= "# pack-refs with: ";
117 if (git__prefixcmp(scan
, traits_header
) == 0) {
118 scan
+= strlen(traits_header
);
119 eol
= strchr(scan
, '\n');
125 if (strstr(scan
, " fully-peeled ") != NULL
) {
126 backend
->peeling_mode
= PEELING_FULL
;
127 } else if (strstr(scan
, " peeled ") != NULL
) {
128 backend
->peeling_mode
= PEELING_STANDARD
;
135 while (scan
< eof
&& *scan
== '#') {
136 if (!(eol
= strchr(scan
, '\n')))
145 /* parse "<OID> <refname>\n" */
147 if (git_oid_fromstr(&oid
, scan
) < 0)
149 scan
+= GIT_OID_HEXSZ
;
153 if (!(eol
= strchr(scan
, '\n')))
159 if (git_sortedcache_upsert((void **)&ref
, backend
->refcache
, scan
) < 0)
163 git_oid_cpy(&ref
->oid
, &oid
);
165 /* look for optional "^<OID>\n" */
168 if (git_oid_fromstr(&oid
, scan
+ 1) < 0)
170 scan
+= GIT_OID_HEXSZ
+ 1;
173 if (!(eol
= strchr(scan
, '\n')))
178 git_oid_cpy(&ref
->peel
, &oid
);
179 ref
->flags
|= PACKREF_HAS_PEEL
;
181 else if (backend
->peeling_mode
== PEELING_FULL
||
182 (backend
->peeling_mode
== PEELING_STANDARD
&&
183 git__prefixcmp(ref
->name
, GIT_REFS_TAGS_DIR
) == 0))
184 ref
->flags
|= PACKREF_CANNOT_PEEL
;
187 git_sortedcache_wunlock(backend
->refcache
);
188 git_buf_dispose(&packedrefs
);
193 git_error_set(GIT_ERROR_REFERENCE
, "corrupted packed references file");
195 git_sortedcache_clear(backend
->refcache
, false);
196 git_sortedcache_wunlock(backend
->refcache
);
197 git_buf_dispose(&packedrefs
);
202 static int loose_parse_oid(
203 git_oid
*oid
, const char *filename
, git_buf
*file_content
)
205 const char *str
= git_buf_cstr(file_content
);
207 if (git_buf_len(file_content
) < GIT_OID_HEXSZ
)
210 /* we need to get 40 OID characters from the file */
211 if (git_oid_fromstr(oid
, str
) < 0)
214 /* If the file is longer than 40 chars, the 41st must be a space */
215 str
+= GIT_OID_HEXSZ
;
216 if (*str
== '\0' || git__isspace(*str
))
220 git_error_set(GIT_ERROR_REFERENCE
, "corrupted loose reference file: %s", filename
);
224 static int loose_readbuffer(git_buf
*buf
, const char *base
, const char *path
)
228 /* build full path to file */
229 if ((error
= git_buf_joinpath(buf
, base
, path
)) < 0 ||
230 (error
= git_futils_readbuffer(buf
, buf
->ptr
)) < 0)
231 git_buf_dispose(buf
);
236 static int loose_lookup_to_packfile(refdb_fs_backend
*backend
, const char *name
)
239 git_buf ref_file
= GIT_BUF_INIT
;
240 struct packref
*ref
= NULL
;
243 /* if we fail to load the loose reference, assume someone changed
244 * the filesystem under us and skip it...
246 if (loose_readbuffer(&ref_file
, backend
->gitpath
, name
) < 0) {
251 /* skip symbolic refs */
252 if (!git__prefixcmp(git_buf_cstr(&ref_file
), GIT_SYMREF
))
255 /* parse OID from file */
256 if ((error
= loose_parse_oid(&oid
, name
, &ref_file
)) < 0)
259 git_sortedcache_wlock(backend
->refcache
);
261 if (!(error
= git_sortedcache_upsert(
262 (void **)&ref
, backend
->refcache
, name
))) {
264 git_oid_cpy(&ref
->oid
, &oid
);
265 ref
->flags
= PACKREF_WAS_LOOSE
;
268 git_sortedcache_wunlock(backend
->refcache
);
271 git_buf_dispose(&ref_file
);
275 static int _dirent_loose_load(void *payload
, git_buf
*full_path
)
277 refdb_fs_backend
*backend
= payload
;
278 const char *file_path
;
280 if (git__suffixcmp(full_path
->ptr
, ".lock") == 0)
283 if (git_path_isdir(full_path
->ptr
)) {
284 int error
= git_path_direach(
285 full_path
, backend
->direach_flags
, _dirent_loose_load
, backend
);
286 /* Race with the filesystem, ignore it */
287 if (error
== GIT_ENOTFOUND
) {
295 file_path
= full_path
->ptr
+ strlen(backend
->gitpath
);
297 return loose_lookup_to_packfile(backend
, file_path
);
301 * Load all the loose references from the repository
302 * into the in-memory Packfile, and build a vector with
303 * all the references so it can be written back to
306 static int packed_loadloose(refdb_fs_backend
*backend
)
309 git_buf refs_path
= GIT_BUF_INIT
;
311 if (git_buf_joinpath(&refs_path
, backend
->gitpath
, GIT_REFS_DIR
) < 0)
315 * Load all the loose files from disk into the Packfile table.
316 * This will overwrite any old packed entries with their
317 * updated loose versions
319 error
= git_path_direach(
320 &refs_path
, backend
->direach_flags
, _dirent_loose_load
, backend
);
322 git_buf_dispose(&refs_path
);
327 static int refdb_fs_backend__exists(
329 git_refdb_backend
*_backend
,
330 const char *ref_name
)
332 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
333 git_buf ref_path
= GIT_BUF_INIT
;
340 if ((error
= git_buf_joinpath(&ref_path
, backend
->gitpath
, ref_name
)) < 0)
343 if (git_path_isfile(ref_path
.ptr
)) {
348 if ((error
= packed_reload(backend
)) < 0)
351 if (git_sortedcache_lookup(backend
->refcache
, ref_name
) != NULL
) {
357 git_buf_dispose(&ref_path
);
361 static const char *loose_parse_symbolic(git_buf
*file_content
)
363 const unsigned int header_len
= (unsigned int)strlen(GIT_SYMREF
);
364 const char *refname_start
;
366 refname_start
= (const char *)file_content
->ptr
;
368 if (git_buf_len(file_content
) < header_len
+ 1) {
369 git_error_set(GIT_ERROR_REFERENCE
, "corrupted loose reference file");
374 * Assume we have already checked for the header
375 * before calling this function
377 refname_start
+= header_len
;
379 return refname_start
;
383 * Returns whether a reference is stored per worktree or not.
384 * Per-worktree references are:
386 * - all pseudorefs, e.g. HEAD and MERGE_HEAD
387 * - all references stored inside of "refs/bisect/"
389 static bool is_per_worktree_ref(const char *ref_name
)
391 return git__prefixcmp(ref_name
, "refs/") != 0 ||
392 git__prefixcmp(ref_name
, "refs/bisect/") == 0;
395 static int loose_lookup(
397 refdb_fs_backend
*backend
,
398 const char *ref_name
)
400 git_buf ref_file
= GIT_BUF_INIT
;
407 if (is_per_worktree_ref(ref_name
))
408 ref_dir
= backend
->gitpath
;
410 ref_dir
= backend
->commonpath
;
412 if ((error
= loose_readbuffer(&ref_file
, ref_dir
, ref_name
)) < 0)
413 /* cannot read loose ref file - gah */;
414 else if (git__prefixcmp(git_buf_cstr(&ref_file
), GIT_SYMREF
) == 0) {
417 git_buf_rtrim(&ref_file
);
419 if (!(target
= loose_parse_symbolic(&ref_file
)))
421 else if (out
!= NULL
)
422 *out
= git_reference__alloc_symbolic(ref_name
, target
);
426 if (!(error
= loose_parse_oid(&oid
, ref_name
, &ref_file
)) &&
428 *out
= git_reference__alloc(ref_name
, &oid
, NULL
);
431 git_buf_dispose(&ref_file
);
435 static int ref_error_notfound(const char *name
)
437 git_error_set(GIT_ERROR_REFERENCE
, "reference '%s' not found", name
);
438 return GIT_ENOTFOUND
;
441 static int packed_lookup(
443 refdb_fs_backend
*backend
,
444 const char *ref_name
)
447 struct packref
*entry
;
449 if ((error
= packed_reload(backend
)) < 0)
452 if (git_sortedcache_rlock(backend
->refcache
) < 0)
455 entry
= git_sortedcache_lookup(backend
->refcache
, ref_name
);
457 error
= ref_error_notfound(ref_name
);
459 *out
= git_reference__alloc(ref_name
, &entry
->oid
, &entry
->peel
);
464 git_sortedcache_runlock(backend
->refcache
);
469 static int refdb_fs_backend__lookup(
471 git_refdb_backend
*_backend
,
472 const char *ref_name
)
474 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
479 if (!(error
= loose_lookup(out
, backend
, ref_name
)))
482 /* only try to lookup this reference on the packfile if it
483 * wasn't found on the loose refs; not if there was a critical error */
484 if (error
== GIT_ENOTFOUND
) {
486 error
= packed_lookup(out
, backend
, ref_name
);
493 git_reference_iterator parent
;
500 git_sortedcache
*cache
;
505 static void refdb_fs_backend__iterator_free(git_reference_iterator
*_iter
)
507 refdb_fs_iter
*iter
= GIT_CONTAINER_OF(_iter
, refdb_fs_iter
, parent
);
509 git_vector_free(&iter
->loose
);
510 git_pool_clear(&iter
->pool
);
511 git_sortedcache_free(iter
->cache
);
515 static int iter_load_loose_paths(refdb_fs_backend
*backend
, refdb_fs_iter
*iter
)
518 git_buf path
= GIT_BUF_INIT
;
519 git_iterator
*fsit
= NULL
;
520 git_iterator_options fsit_opts
= GIT_ITERATOR_OPTIONS_INIT
;
521 const git_index_entry
*entry
= NULL
;
522 const char *ref_prefix
= GIT_REFS_DIR
;
523 size_t ref_prefix_len
= strlen(ref_prefix
);
525 if (!backend
->commonpath
) /* do nothing if no commonpath for loose refs */
528 fsit_opts
.flags
= backend
->iterator_flags
;
531 const char *last_sep
= NULL
;
533 for (pos
= iter
->glob
; *pos
; ++pos
) {
549 ref_prefix
= iter
->glob
;
550 ref_prefix_len
= (last_sep
- ref_prefix
) + 1;
554 if ((error
= git_buf_printf(&path
, "%s/", backend
->commonpath
)) < 0 ||
555 (error
= git_buf_put(&path
, ref_prefix
, ref_prefix_len
)) < 0) {
556 git_buf_dispose(&path
);
560 if ((error
= git_iterator_for_filesystem(&fsit
, path
.ptr
, &fsit_opts
)) < 0) {
561 git_buf_dispose(&path
);
562 return (iter
->glob
&& error
== GIT_ENOTFOUND
)? 0 : error
;
565 error
= git_buf_sets(&path
, ref_prefix
);
567 while (!error
&& !git_iterator_advance(&entry
, fsit
)) {
568 const char *ref_name
;
571 git_buf_truncate(&path
, ref_prefix_len
);
572 git_buf_puts(&path
, entry
->path
);
573 ref_name
= git_buf_cstr(&path
);
575 if (git__suffixcmp(ref_name
, ".lock") == 0 ||
576 (iter
->glob
&& wildmatch(iter
->glob
, ref_name
, 0) != 0))
579 ref_dup
= git_pool_strdup(&iter
->pool
, ref_name
);
583 error
= git_vector_insert(&iter
->loose
, ref_dup
);
586 git_iterator_free(fsit
);
587 git_buf_dispose(&path
);
592 static int refdb_fs_backend__iterator_next(
593 git_reference
**out
, git_reference_iterator
*_iter
)
595 int error
= GIT_ITEROVER
;
596 refdb_fs_iter
*iter
= GIT_CONTAINER_OF(_iter
, refdb_fs_iter
, parent
);
597 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(iter
->parent
.db
->backend
, refdb_fs_backend
, parent
);
600 while (iter
->loose_pos
< iter
->loose
.length
) {
601 const char *path
= git_vector_get(&iter
->loose
, iter
->loose_pos
++);
603 if (loose_lookup(out
, backend
, path
) == 0) {
604 ref
= git_sortedcache_lookup(iter
->cache
, path
);
606 ref
->flags
|= PACKREF_SHADOWED
;
614 error
= GIT_ITEROVER
;
615 while (iter
->packed_pos
< git_sortedcache_entrycount(iter
->cache
)) {
616 ref
= git_sortedcache_entry(iter
->cache
, iter
->packed_pos
++);
617 if (!ref
) /* stop now if another thread deleted refs and we past end */
620 if (ref
->flags
& PACKREF_SHADOWED
)
622 if (iter
->glob
&& wildmatch(iter
->glob
, ref
->name
, 0) != 0)
625 *out
= git_reference__alloc(ref
->name
, &ref
->oid
, &ref
->peel
);
626 error
= (*out
!= NULL
) ? 0 : -1;
633 static int refdb_fs_backend__iterator_next_name(
634 const char **out
, git_reference_iterator
*_iter
)
636 int error
= GIT_ITEROVER
;
637 refdb_fs_iter
*iter
= GIT_CONTAINER_OF(_iter
, refdb_fs_iter
, parent
);
638 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(iter
->parent
.db
->backend
, refdb_fs_backend
, parent
);
641 while (iter
->loose_pos
< iter
->loose
.length
) {
642 const char *path
= git_vector_get(&iter
->loose
, iter
->loose_pos
++);
645 if (loose_lookup(NULL
, backend
, path
) == 0) {
646 ref
= git_sortedcache_lookup(iter
->cache
, path
);
648 ref
->flags
|= PACKREF_SHADOWED
;
657 error
= GIT_ITEROVER
;
658 while (iter
->packed_pos
< git_sortedcache_entrycount(iter
->cache
)) {
659 ref
= git_sortedcache_entry(iter
->cache
, iter
->packed_pos
++);
660 if (!ref
) /* stop now if another thread deleted refs and we past end */
663 if (ref
->flags
& PACKREF_SHADOWED
)
665 if (iter
->glob
&& wildmatch(iter
->glob
, ref
->name
, 0) != 0)
676 static int refdb_fs_backend__iterator(
677 git_reference_iterator
**out
, git_refdb_backend
*_backend
, const char *glob
)
679 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
680 refdb_fs_iter
*iter
= NULL
;
685 iter
= git__calloc(1, sizeof(refdb_fs_iter
));
686 GIT_ERROR_CHECK_ALLOC(iter
);
688 git_pool_init(&iter
->pool
, 1);
690 if ((error
= git_vector_init(&iter
->loose
, 8, NULL
)) < 0)
694 (iter
->glob
= git_pool_strdup(&iter
->pool
, glob
)) == NULL
) {
695 error
= GIT_ERROR_NOMEMORY
;
699 if ((error
= iter_load_loose_paths(backend
, iter
)) < 0)
702 if ((error
= packed_reload(backend
)) < 0)
705 if ((error
= git_sortedcache_copy(&iter
->cache
, backend
->refcache
, 1, NULL
, NULL
)) < 0)
708 iter
->parent
.next
= refdb_fs_backend__iterator_next
;
709 iter
->parent
.next_name
= refdb_fs_backend__iterator_next_name
;
710 iter
->parent
.free
= refdb_fs_backend__iterator_free
;
712 *out
= (git_reference_iterator
*)iter
;
715 refdb_fs_backend__iterator_free((git_reference_iterator
*)iter
);
719 static bool ref_is_available(
720 const char *old_ref
, const char *new_ref
, const char *this_ref
)
722 if (old_ref
== NULL
|| strcmp(old_ref
, this_ref
)) {
723 size_t reflen
= strlen(this_ref
);
724 size_t newlen
= strlen(new_ref
);
725 size_t cmplen
= reflen
< newlen
? reflen
: newlen
;
726 const char *lead
= reflen
< newlen
? new_ref
: this_ref
;
728 if (!strncmp(new_ref
, this_ref
, cmplen
) && lead
[cmplen
] == '/') {
736 static int reference_path_available(
737 refdb_fs_backend
*backend
,
745 if ((error
= packed_reload(backend
)) < 0)
751 if ((error
= refdb_fs_backend__exists(
752 &exists
, (git_refdb_backend
*)backend
, new_ref
)) < 0) {
757 git_error_set(GIT_ERROR_REFERENCE
,
758 "failed to write reference '%s': a reference with "
759 "that name already exists.", new_ref
);
764 git_sortedcache_rlock(backend
->refcache
);
766 for (i
= 0; i
< git_sortedcache_entrycount(backend
->refcache
); ++i
) {
767 struct packref
*ref
= git_sortedcache_entry(backend
->refcache
, i
);
769 if (ref
&& !ref_is_available(old_ref
, new_ref
, ref
->name
)) {
770 git_sortedcache_runlock(backend
->refcache
);
771 git_error_set(GIT_ERROR_REFERENCE
,
772 "path to reference '%s' collides with existing one", new_ref
);
777 git_sortedcache_runlock(backend
->refcache
);
781 static int loose_lock(git_filebuf
*file
, refdb_fs_backend
*backend
, const char *name
)
783 int error
, filebuf_flags
;
784 git_buf ref_path
= GIT_BUF_INIT
;
787 assert(file
&& backend
&& name
);
789 if (!git_path_isvalid(backend
->repo
, name
, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS
)) {
790 git_error_set(GIT_ERROR_INVALID
, "invalid reference name '%s'", name
);
791 return GIT_EINVALIDSPEC
;
794 if (is_per_worktree_ref(name
))
795 basedir
= backend
->gitpath
;
797 basedir
= backend
->commonpath
;
799 /* Remove a possibly existing empty directory hierarchy
800 * which name would collide with the reference name
802 if ((error
= git_futils_rmdir_r(name
, basedir
, GIT_RMDIR_SKIP_NONEMPTY
)) < 0)
805 if (git_buf_joinpath(&ref_path
, basedir
, name
) < 0)
808 filebuf_flags
= GIT_FILEBUF_CREATE_LEADING_DIRS
;
810 filebuf_flags
|= GIT_FILEBUF_FSYNC
;
812 error
= git_filebuf_open(file
, ref_path
.ptr
, filebuf_flags
, GIT_REFS_FILE_MODE
);
814 if (error
== GIT_EDIRECTORY
)
815 git_error_set(GIT_ERROR_REFERENCE
, "cannot lock ref '%s', there are refs beneath that folder", name
);
817 git_buf_dispose(&ref_path
);
821 static int loose_commit(git_filebuf
*file
, const git_reference
*ref
)
825 if (ref
->type
== GIT_REFERENCE_DIRECT
) {
826 char oid
[GIT_OID_HEXSZ
+ 1];
827 git_oid_nfmt(oid
, sizeof(oid
), &ref
->target
.oid
);
829 git_filebuf_printf(file
, "%s\n", oid
);
830 } else if (ref
->type
== GIT_REFERENCE_SYMBOLIC
) {
831 git_filebuf_printf(file
, GIT_SYMREF
"%s\n", ref
->target
.symbolic
);
833 assert(0); /* don't let this happen */
836 return git_filebuf_commit(file
);
839 static int refdb_fs_backend__lock(void **out
, git_refdb_backend
*_backend
, const char *refname
)
843 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
845 lock
= git__calloc(1, sizeof(git_filebuf
));
846 GIT_ERROR_CHECK_ALLOC(lock
);
848 if ((error
= loose_lock(lock
, backend
, refname
)) < 0) {
857 static int refdb_fs_backend__write_tail(
858 git_refdb_backend
*_backend
,
859 const git_reference
*ref
,
862 const git_oid
*old_id
,
863 const char *old_target
,
864 const git_signature
*who
,
865 const char *message
);
867 static int refdb_fs_backend__delete_tail(
868 git_refdb_backend
*_backend
,
870 const char *ref_name
,
871 const git_oid
*old_id
,
872 const char *old_target
);
874 static int refdb_fs_backend__unlock(git_refdb_backend
*backend
, void *payload
, int success
, int update_reflog
,
875 const git_reference
*ref
, const git_signature
*sig
, const char *message
)
877 git_filebuf
*lock
= (git_filebuf
*) payload
;
881 error
= refdb_fs_backend__delete_tail(backend
, lock
, ref
->name
, NULL
, NULL
);
883 error
= refdb_fs_backend__write_tail(backend
, ref
, lock
, update_reflog
, NULL
, NULL
, sig
, message
);
885 git_filebuf_cleanup(lock
);
892 * Find out what object this reference resolves to.
894 * For references that point to a 'big' tag (e.g. an
895 * actual tag object on the repository), we need to
896 * cache on the packfile the OID of the object to
897 * which that 'big tag' is pointing to.
899 static int packed_find_peel(refdb_fs_backend
*backend
, struct packref
*ref
)
903 if (ref
->flags
& PACKREF_HAS_PEEL
|| ref
->flags
& PACKREF_CANNOT_PEEL
)
907 * Find the tagged object in the repository
909 if (git_object_lookup(&object
, backend
->repo
, &ref
->oid
, GIT_OBJECT_ANY
) < 0)
913 * If the tagged object is a Tag object, we need to resolve it;
914 * if the ref is actually a 'weak' ref, we don't need to resolve
917 if (git_object_type(object
) == GIT_OBJECT_TAG
) {
918 git_tag
*tag
= (git_tag
*)object
;
921 * Find the object pointed at by this tag
923 git_oid_cpy(&ref
->peel
, git_tag_target_id(tag
));
924 ref
->flags
|= PACKREF_HAS_PEEL
;
927 * The reference has now cached the resolved OID, and is
928 * marked at such. When written to the packfile, it'll be
929 * accompanied by this resolved oid
933 git_object_free(object
);
938 * Write a single reference into a packfile
940 static int packed_write_ref(struct packref
*ref
, git_filebuf
*file
)
942 char oid
[GIT_OID_HEXSZ
+ 1];
943 git_oid_nfmt(oid
, sizeof(oid
), &ref
->oid
);
946 * For references that peel to an object in the repo, we must
947 * write the resulting peel on a separate line, e.g.
949 * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4
950 * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100
952 * This obviously only applies to tags.
953 * The required peels have already been loaded into `ref->peel_target`.
955 if (ref
->flags
& PACKREF_HAS_PEEL
) {
956 char peel
[GIT_OID_HEXSZ
+ 1];
957 git_oid_nfmt(peel
, sizeof(peel
), &ref
->peel
);
959 if (git_filebuf_printf(file
, "%s %s\n^%s\n", oid
, ref
->name
, peel
) < 0)
962 if (git_filebuf_printf(file
, "%s %s\n", oid
, ref
->name
) < 0)
970 * Remove all loose references
972 * Once we have successfully written a packfile,
973 * all the loose references that were packed must be
976 * This is a dangerous method; make sure the packfile
977 * is well-written, because we are destructing references
980 static int packed_remove_loose(refdb_fs_backend
*backend
)
983 git_filebuf lock
= GIT_FILEBUF_INIT
;
984 git_buf ref_content
= GIT_BUF_INIT
;
987 /* backend->refcache is already locked when this is called */
989 for (i
= 0; i
< git_sortedcache_entrycount(backend
->refcache
); ++i
) {
990 struct packref
*ref
= git_sortedcache_entry(backend
->refcache
, i
);
993 if (!ref
|| !(ref
->flags
& PACKREF_WAS_LOOSE
))
996 git_filebuf_cleanup(&lock
);
998 /* We need to stop anybody from updating the ref while we try to do a safe delete */
999 error
= loose_lock(&lock
, backend
, ref
->name
);
1000 /* If someone else is updating it, let them do it */
1001 if (error
== GIT_EEXISTS
|| error
== GIT_ENOTFOUND
)
1005 git_buf_dispose(&ref_content
);
1006 git_error_set(GIT_ERROR_REFERENCE
, "failed to lock loose reference '%s'", ref
->name
);
1010 error
= git_futils_readbuffer(&ref_content
, lock
.path_original
);
1011 /* Someone else beat us to cleaning up the ref, let's simply continue */
1012 if (error
== GIT_ENOTFOUND
)
1015 /* This became a symref between us packing and trying to delete it, so ignore it */
1016 if (!git__prefixcmp(ref_content
.ptr
, GIT_SYMREF
))
1019 /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */
1020 if (loose_parse_oid(¤t_id
, lock
.path_original
, &ref_content
) < 0)
1023 /* If the ref moved since we packed it, we must not delete it */
1024 if (!git_oid_equal(¤t_id
, &ref
->oid
))
1028 * if we fail to remove a single file, this is *not* good,
1029 * but we should keep going and remove as many as possible.
1030 * If we fail to remove, the ref is still in the old state, so
1031 * we haven't lost information.
1033 p_unlink(lock
.path_original
);
1036 git_buf_dispose(&ref_content
);
1037 git_filebuf_cleanup(&lock
);
1042 * Write all the contents in the in-memory packfile to disk.
1044 static int packed_write(refdb_fs_backend
*backend
)
1046 git_sortedcache
*refcache
= backend
->refcache
;
1047 git_filebuf pack_file
= GIT_FILEBUF_INIT
;
1048 int error
, open_flags
= 0;
1051 /* lock the cache to updates while we do this */
1052 if ((error
= git_sortedcache_wlock(refcache
)) < 0)
1056 open_flags
= GIT_FILEBUF_FSYNC
;
1058 /* Open the file! */
1059 if ((error
= git_filebuf_open(&pack_file
, git_sortedcache_path(refcache
), open_flags
, GIT_PACKEDREFS_FILE_MODE
)) < 0)
1062 /* Packfiles have a header... apparently
1063 * This is in fact not required, but we might as well print it
1065 if ((error
= git_filebuf_printf(&pack_file
, "%s\n", GIT_PACKEDREFS_HEADER
)) < 0)
1068 for (i
= 0; i
< git_sortedcache_entrycount(refcache
); ++i
) {
1069 struct packref
*ref
= git_sortedcache_entry(refcache
, i
);
1072 if ((error
= packed_find_peel(backend
, ref
)) < 0)
1075 if ((error
= packed_write_ref(ref
, &pack_file
)) < 0)
1079 /* if we've written all the references properly, we can commit
1080 * the packfile to make the changes effective */
1081 if ((error
= git_filebuf_commit(&pack_file
)) < 0)
1084 /* when and only when the packfile has been properly written,
1085 * we can go ahead and remove the loose refs */
1086 if ((error
= packed_remove_loose(backend
)) < 0)
1089 git_sortedcache_updated(refcache
);
1090 git_sortedcache_wunlock(refcache
);
1092 /* we're good now */
1096 git_filebuf_cleanup(&pack_file
);
1097 git_sortedcache_wunlock(refcache
);
1102 static int packed_delete(refdb_fs_backend
*backend
, const char *ref_name
)
1105 int error
, found
= 0;
1107 if ((error
= packed_reload(backend
)) < 0)
1110 if ((error
= git_sortedcache_wlock(backend
->refcache
)) < 0)
1113 /* If a packed reference exists, remove it from the packfile and repack if necessary */
1114 error
= git_sortedcache_lookup_index(&pack_pos
, backend
->refcache
, ref_name
);
1116 error
= git_sortedcache_remove(backend
->refcache
, pack_pos
);
1119 if (error
== GIT_ENOTFOUND
)
1122 git_sortedcache_wunlock(backend
->refcache
);
1125 error
= packed_write(backend
);
1131 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
);
1132 static int has_reflog(git_repository
*repo
, const char *name
);
1134 static int should_write_reflog(int *write
, git_repository
*repo
, const char *name
)
1138 error
= git_repository__configmap_lookup(&logall
, repo
, GIT_CONFIGMAP_LOGALLREFUPDATES
);
1142 /* Defaults to the opposite of the repo being bare */
1143 if (logall
== GIT_LOGALLREFUPDATES_UNSET
)
1144 logall
= !git_repository_is_bare(repo
);
1148 case GIT_LOGALLREFUPDATES_FALSE
:
1152 case GIT_LOGALLREFUPDATES_TRUE
:
1153 /* Only write if it already has a log,
1154 * or if it's under heads/, remotes/ or notes/
1156 *write
= has_reflog(repo
, name
) ||
1157 !git__prefixcmp(name
, GIT_REFS_HEADS_DIR
) ||
1158 !git__strcmp(name
, GIT_HEAD_FILE
) ||
1159 !git__prefixcmp(name
, GIT_REFS_REMOTES_DIR
) ||
1160 !git__prefixcmp(name
, GIT_REFS_NOTES_DIR
);
1163 case GIT_LOGALLREFUPDATES_ALWAYS
:
1171 static int cmp_old_ref(int *cmp
, git_refdb_backend
*backend
, const char *name
,
1172 const git_oid
*old_id
, const char *old_target
)
1175 git_reference
*old_ref
= NULL
;
1178 /* It "matches" if there is no old value to compare against */
1179 if (!old_id
&& !old_target
)
1182 if ((error
= refdb_fs_backend__lookup(&old_ref
, backend
, name
)) < 0)
1185 /* If the types don't match, there's no way the values do */
1186 if (old_id
&& old_ref
->type
!= GIT_REFERENCE_DIRECT
) {
1190 if (old_target
&& old_ref
->type
!= GIT_REFERENCE_SYMBOLIC
) {
1195 if (old_id
&& old_ref
->type
== GIT_REFERENCE_DIRECT
)
1196 *cmp
= git_oid_cmp(old_id
, &old_ref
->target
.oid
);
1198 if (old_target
&& old_ref
->type
== GIT_REFERENCE_SYMBOLIC
)
1199 *cmp
= git__strcmp(old_target
, old_ref
->target
.symbolic
);
1202 git_reference_free(old_ref
);
1208 * The git.git comment regarding this, for your viewing pleasure:
1210 * Special hack: If a branch is updated directly and HEAD
1211 * points to it (may happen on the remote side of a push
1212 * for example) then logically the HEAD reflog should be
1214 * A generic solution implies reverse symref information,
1215 * but finding all symrefs pointing to the given branch
1216 * would be rather costly for this rare event (the direct
1217 * update of a branch) to be worth it. So let's cheat and
1218 * check with HEAD only which should cover 99% of all usage
1219 * scenarios (even 100% of the default ones).
1221 static int maybe_append_head(refdb_fs_backend
*backend
, const git_reference
*ref
, const git_signature
*who
, const char *message
)
1225 git_reference
*tmp
= NULL
, *head
= NULL
, *peeled
= NULL
;
1228 if (ref
->type
== GIT_REFERENCE_SYMBOLIC
)
1231 /* if we can't resolve, we use {0}*40 as old id */
1232 if (git_reference_name_to_id(&old_id
, backend
->repo
, ref
->name
) < 0)
1233 memset(&old_id
, 0, sizeof(old_id
));
1235 if ((error
= git_reference_lookup(&head
, backend
->repo
, GIT_HEAD_FILE
)) < 0)
1238 if (git_reference_type(head
) == GIT_REFERENCE_DIRECT
)
1241 if ((error
= git_reference_lookup(&tmp
, backend
->repo
, GIT_HEAD_FILE
)) < 0)
1244 /* Go down the symref chain until we find the branch */
1245 while (git_reference_type(tmp
) == GIT_REFERENCE_SYMBOLIC
) {
1246 error
= git_reference_lookup(&peeled
, backend
->repo
, git_reference_symbolic_target(tmp
));
1250 git_reference_free(tmp
);
1254 if (error
== GIT_ENOTFOUND
) {
1256 name
= git_reference_symbolic_target(tmp
);
1257 } else if (error
< 0) {
1260 name
= git_reference_name(tmp
);
1263 if (strcmp(name
, ref
->name
))
1266 error
= reflog_append(backend
, head
, &old_id
, git_reference_target(ref
), who
, message
);
1269 git_reference_free(tmp
);
1270 git_reference_free(head
);
1274 static int refdb_fs_backend__write(
1275 git_refdb_backend
*_backend
,
1276 const git_reference
*ref
,
1278 const git_signature
*who
,
1279 const char *message
,
1280 const git_oid
*old_id
,
1281 const char *old_target
)
1283 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1284 git_filebuf file
= GIT_FILEBUF_INIT
;
1289 if ((error
= reference_path_available(backend
, ref
->name
, NULL
, force
)) < 0)
1292 /* We need to perform the reflog append and old value check under the ref's lock */
1293 if ((error
= loose_lock(&file
, backend
, ref
->name
)) < 0)
1296 return refdb_fs_backend__write_tail(_backend
, ref
, &file
, true, old_id
, old_target
, who
, message
);
1299 static int refdb_fs_backend__write_tail(
1300 git_refdb_backend
*_backend
,
1301 const git_reference
*ref
,
1304 const git_oid
*old_id
,
1305 const char *old_target
,
1306 const git_signature
*who
,
1307 const char *message
)
1309 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1310 int error
= 0, cmp
= 0, should_write
;
1311 const char *new_target
= NULL
;
1312 const git_oid
*new_id
= NULL
;
1314 if ((error
= cmp_old_ref(&cmp
, _backend
, ref
->name
, old_id
, old_target
)) < 0)
1318 git_error_set(GIT_ERROR_REFERENCE
, "old reference value does not match");
1319 error
= GIT_EMODIFIED
;
1323 if (ref
->type
== GIT_REFERENCE_SYMBOLIC
)
1324 new_target
= ref
->target
.symbolic
;
1326 new_id
= &ref
->target
.oid
;
1328 error
= cmp_old_ref(&cmp
, _backend
, ref
->name
, new_id
, new_target
);
1329 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1332 /* Don't update if we have the same value */
1333 if (!error
&& !cmp
) {
1335 goto on_error
; /* not really error */
1338 if (update_reflog
) {
1339 if ((error
= should_write_reflog(&should_write
, backend
->repo
, ref
->name
)) < 0)
1343 if ((error
= reflog_append(backend
, ref
, NULL
, NULL
, who
, message
)) < 0)
1345 if ((error
= maybe_append_head(backend
, ref
, who
, message
)) < 0)
1350 return loose_commit(file
, ref
);
1353 git_filebuf_cleanup(file
);
1357 static void refdb_fs_backend__prune_refs(
1358 refdb_fs_backend
*backend
,
1359 const char *ref_name
,
1362 git_buf relative_path
= GIT_BUF_INIT
;
1363 git_buf base_path
= GIT_BUF_INIT
;
1366 assert(backend
&& ref_name
);
1368 if (git_buf_sets(&relative_path
, ref_name
) < 0)
1371 git_path_squash_slashes(&relative_path
);
1372 if ((commonlen
= git_path_common_dirlen("refs/heads/", git_buf_cstr(&relative_path
))) == strlen("refs/heads/") ||
1373 (commonlen
= git_path_common_dirlen("refs/tags/", git_buf_cstr(&relative_path
))) == strlen("refs/tags/") ||
1374 (commonlen
= git_path_common_dirlen("refs/remotes/", git_buf_cstr(&relative_path
))) == strlen("refs/remotes/")) {
1376 git_buf_truncate(&relative_path
, commonlen
);
1379 if (git_buf_join3(&base_path
, '/', backend
->commonpath
, prefix
, git_buf_cstr(&relative_path
)) < 0)
1382 if (git_buf_joinpath(&base_path
, backend
->commonpath
, git_buf_cstr(&relative_path
)) < 0)
1386 git_futils_rmdir_r(ref_name
+ commonlen
, git_buf_cstr(&base_path
), GIT_RMDIR_EMPTY_PARENTS
| GIT_RMDIR_SKIP_ROOT
);
1390 git_buf_dispose(&relative_path
);
1391 git_buf_dispose(&base_path
);
1394 static int refdb_fs_backend__delete(
1395 git_refdb_backend
*_backend
,
1396 const char *ref_name
,
1397 const git_oid
*old_id
, const char *old_target
)
1399 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1400 git_filebuf file
= GIT_FILEBUF_INIT
;
1403 assert(backend
&& ref_name
);
1405 if ((error
= loose_lock(&file
, backend
, ref_name
)) < 0)
1408 if ((error
= refdb_reflog_fs__delete(_backend
, ref_name
)) < 0) {
1409 git_filebuf_cleanup(&file
);
1413 return refdb_fs_backend__delete_tail(_backend
, &file
, ref_name
, old_id
, old_target
);
1416 static int loose_delete(refdb_fs_backend
*backend
, const char *ref_name
)
1418 git_buf loose_path
= GIT_BUF_INIT
;
1421 if (git_buf_joinpath(&loose_path
, backend
->commonpath
, ref_name
) < 0)
1424 error
= p_unlink(loose_path
.ptr
);
1425 if (error
< 0 && errno
== ENOENT
)
1426 error
= GIT_ENOTFOUND
;
1427 else if (error
!= 0)
1430 git_buf_dispose(&loose_path
);
1435 static int refdb_fs_backend__delete_tail(
1436 git_refdb_backend
*_backend
,
1438 const char *ref_name
,
1439 const git_oid
*old_id
, const char *old_target
)
1441 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1442 int error
= 0, cmp
= 0;
1443 bool packed_deleted
= 0;
1445 error
= cmp_old_ref(&cmp
, _backend
, ref_name
, old_id
, old_target
);
1450 git_error_set(GIT_ERROR_REFERENCE
, "old reference value does not match");
1451 error
= GIT_EMODIFIED
;
1456 * To ensure that an external observer will see either the current ref value
1457 * (because the loose ref still exists), or a missing ref (after the packed-file is
1458 * unlocked, there will be nothing left), we must ensure things happen in the
1461 * - the packed-ref file is locked and loaded, as well as a loose one, if it exists
1462 * - we optimistically delete a packed ref, keeping track of whether it existed
1463 * - we delete the loose ref, note that we have its .lock
1464 * - the loose ref is "unlocked", then the packed-ref file is rewritten and unlocked
1465 * - we should prune the path components if a loose ref was deleted
1467 * Note that, because our packed backend doesn't expose its filesystem lock,
1468 * we might not be able to guarantee that this is what actually happens (ie.
1469 * as our current code never write packed-refs.lock, nothing stops observers
1470 * from grabbing a "stale" value from there).
1472 if ((error
= packed_delete(backend
, ref_name
)) < 0 && error
!= GIT_ENOTFOUND
)
1478 if ((error
= loose_delete(backend
, ref_name
)) < 0 && error
!= GIT_ENOTFOUND
)
1481 if (error
== GIT_ENOTFOUND
) {
1482 error
= packed_deleted
? 0 : ref_error_notfound(ref_name
);
1487 git_filebuf_cleanup(file
);
1489 refdb_fs_backend__prune_refs(backend
, ref_name
, "");
1493 static int refdb_reflog_fs__rename(git_refdb_backend
*_backend
, const char *old_name
, const char *new_name
);
1495 static int refdb_fs_backend__rename(
1496 git_reference
**out
,
1497 git_refdb_backend
*_backend
,
1498 const char *old_name
,
1499 const char *new_name
,
1501 const git_signature
*who
,
1502 const char *message
)
1504 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1505 git_reference
*old
, *new = NULL
;
1506 git_filebuf file
= GIT_FILEBUF_INIT
;
1511 if ((error
= reference_path_available(
1512 backend
, new_name
, old_name
, force
)) < 0 ||
1513 (error
= refdb_fs_backend__lookup(&old
, _backend
, old_name
)) < 0)
1516 if ((error
= refdb_fs_backend__delete(_backend
, old_name
, NULL
, NULL
)) < 0) {
1517 git_reference_free(old
);
1521 new = git_reference__realloc(&old
, new_name
);
1523 git_reference_free(old
);
1527 if ((error
= loose_lock(&file
, backend
, new->name
)) < 0) {
1528 git_reference_free(new);
1532 /* Try to rename the refog; it's ok if the old doesn't exist */
1533 error
= refdb_reflog_fs__rename(_backend
, old_name
, new_name
);
1534 if (((error
== 0) || (error
== GIT_ENOTFOUND
)) &&
1535 ((error
= reflog_append(backend
, new, git_reference_target(new), NULL
, who
, message
)) < 0)) {
1536 git_reference_free(new);
1537 git_filebuf_cleanup(&file
);
1542 git_reference_free(new);
1543 git_filebuf_cleanup(&file
);
1548 if ((error
= loose_commit(&file
, new)) < 0 || out
== NULL
) {
1549 git_reference_free(new);
1557 static int refdb_fs_backend__compress(git_refdb_backend
*_backend
)
1560 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1564 if ((error
= packed_reload(backend
)) < 0 || /* load the existing packfile */
1565 (error
= packed_loadloose(backend
)) < 0 || /* add all the loose refs */
1566 (error
= packed_write(backend
)) < 0) /* write back to disk */
1572 static void refdb_fs_backend__free(git_refdb_backend
*_backend
)
1574 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1578 git_sortedcache_free(backend
->refcache
);
1579 git__free(backend
->gitpath
);
1580 git__free(backend
->commonpath
);
1584 static char *setup_namespace(git_repository
*repo
, const char *in
)
1586 git_buf path
= GIT_BUF_INIT
;
1587 char *parts
, *start
, *end
, *out
= NULL
;
1592 git_buf_puts(&path
, in
);
1594 /* if the repo is not namespaced, nothing else to do */
1595 if (repo
->namespace == NULL
) {
1596 out
= git_buf_detach(&path
);
1600 parts
= end
= git__strdup(repo
->namespace);
1605 * From `man gitnamespaces`:
1606 * namespaces which include a / will expand to a hierarchy
1607 * of namespaces; for example, GIT_NAMESPACE=foo/bar will store
1608 * refs under refs/namespaces/foo/refs/namespaces/bar/
1610 while ((start
= git__strsep(&end
, "/")) != NULL
)
1611 git_buf_printf(&path
, "refs/namespaces/%s/", start
);
1613 git_buf_printf(&path
, "refs/namespaces/%s/refs", end
);
1616 /* Make sure that the folder with the namespace exists */
1617 if (git_futils_mkdir_relative(git_buf_cstr(&path
), in
, 0777,
1618 GIT_MKDIR_PATH
, NULL
) < 0)
1621 /* Return root of the namespaced gitpath, i.e. without the trailing '/refs' */
1622 git_buf_rtruncate_at_char(&path
, '/');
1623 out
= git_buf_detach(&path
);
1626 git_buf_dispose(&path
);
1630 static int reflog_alloc(git_reflog
**reflog
, const char *name
)
1636 log
= git__calloc(1, sizeof(git_reflog
));
1637 GIT_ERROR_CHECK_ALLOC(log
);
1639 log
->ref_name
= git__strdup(name
);
1640 GIT_ERROR_CHECK_ALLOC(log
->ref_name
);
1642 if (git_vector_init(&log
->entries
, 0, NULL
) < 0) {
1643 git__free(log
->ref_name
);
1653 static int reflog_parse(git_reflog
*log
, const char *buf
, size_t buf_size
)
1655 git_parse_ctx parser
= GIT_PARSE_CTX_INIT
;
1657 if ((git_parse_ctx_init(&parser
, buf
, buf_size
)) < 0)
1660 for (; parser
.remain_len
; git_parse_advance_line(&parser
)) {
1661 git_reflog_entry
*entry
;
1665 entry
= git__calloc(1, sizeof(*entry
));
1666 GIT_ERROR_CHECK_ALLOC(entry
);
1667 entry
->committer
= git__calloc(1, sizeof(*entry
->committer
));
1668 GIT_ERROR_CHECK_ALLOC(entry
->committer
);
1670 if (git_parse_advance_oid(&entry
->oid_old
, &parser
) < 0 ||
1671 git_parse_advance_expected(&parser
, " ", 1) < 0 ||
1672 git_parse_advance_oid(&entry
->oid_cur
, &parser
) < 0)
1676 while (git_parse_peek(&c
, &parser
, 0) == 0 && c
!= '\t' && c
!= '\n')
1677 git_parse_advance_chars(&parser
, 1);
1679 if (git_signature__parse(entry
->committer
, &sig
, parser
.line
, NULL
, 0) < 0)
1684 git_parse_advance_chars(&parser
, 1);
1686 len
= parser
.line_len
;
1687 if (parser
.line
[len
- 1] == '\n')
1690 entry
->msg
= git__strndup(parser
.line
, len
);
1691 GIT_ERROR_CHECK_ALLOC(entry
->msg
);
1694 if ((git_vector_insert(&log
->entries
, entry
)) < 0) {
1695 git_reflog_entry__free(entry
);
1702 git_reflog_entry__free(entry
);
1708 static int create_new_reflog_file(const char *filepath
)
1712 if ((error
= git_futils_mkpath2file(filepath
, GIT_REFLOG_DIR_MODE
)) < 0)
1715 if ((fd
= p_open(filepath
,
1717 GIT_REFLOG_FILE_MODE
)) < 0)
1723 GIT_INLINE(int) retrieve_reflog_path(git_buf
*path
, git_repository
*repo
, const char *name
)
1725 if (strcmp(name
, GIT_HEAD_FILE
) == 0)
1726 return git_buf_join3(path
, '/', repo
->gitdir
, GIT_REFLOG_DIR
, name
);
1727 return git_buf_join3(path
, '/', repo
->commondir
, GIT_REFLOG_DIR
, name
);
1730 static int refdb_reflog_fs__ensure_log(git_refdb_backend
*_backend
, const char *name
)
1732 refdb_fs_backend
*backend
;
1733 git_repository
*repo
;
1734 git_buf path
= GIT_BUF_INIT
;
1737 assert(_backend
&& name
);
1739 backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1740 repo
= backend
->repo
;
1742 if ((error
= retrieve_reflog_path(&path
, repo
, name
)) < 0)
1745 error
= create_new_reflog_file(git_buf_cstr(&path
));
1746 git_buf_dispose(&path
);
1751 static int has_reflog(git_repository
*repo
, const char *name
)
1754 git_buf path
= GIT_BUF_INIT
;
1756 if (retrieve_reflog_path(&path
, repo
, name
) < 0)
1759 ret
= git_path_isfile(git_buf_cstr(&path
));
1762 git_buf_dispose(&path
);
1766 static int refdb_reflog_fs__has_log(git_refdb_backend
*_backend
, const char *name
)
1768 refdb_fs_backend
*backend
;
1770 assert(_backend
&& name
);
1772 backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1774 return has_reflog(backend
->repo
, name
);
1777 static int refdb_reflog_fs__read(git_reflog
**out
, git_refdb_backend
*_backend
, const char *name
)
1780 git_buf log_path
= GIT_BUF_INIT
;
1781 git_buf log_file
= GIT_BUF_INIT
;
1782 git_reflog
*log
= NULL
;
1783 git_repository
*repo
;
1784 refdb_fs_backend
*backend
;
1786 assert(out
&& _backend
&& name
);
1788 backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1789 repo
= backend
->repo
;
1791 if (reflog_alloc(&log
, name
) < 0)
1794 if (retrieve_reflog_path(&log_path
, repo
, name
) < 0)
1797 error
= git_futils_readbuffer(&log_file
, git_buf_cstr(&log_path
));
1798 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1801 if ((error
== GIT_ENOTFOUND
) &&
1802 ((error
= create_new_reflog_file(git_buf_cstr(&log_path
))) < 0))
1805 if ((error
= reflog_parse(log
,
1806 git_buf_cstr(&log_file
), git_buf_len(&log_file
))) < 0)
1813 git_reflog_free(log
);
1816 git_buf_dispose(&log_file
);
1817 git_buf_dispose(&log_path
);
1822 static int serialize_reflog_entry(
1824 const git_oid
*oid_old
,
1825 const git_oid
*oid_new
,
1826 const git_signature
*committer
,
1829 char raw_old
[GIT_OID_HEXSZ
+1];
1830 char raw_new
[GIT_OID_HEXSZ
+1];
1832 git_oid_tostr(raw_old
, GIT_OID_HEXSZ
+1, oid_old
);
1833 git_oid_tostr(raw_new
, GIT_OID_HEXSZ
+1, oid_new
);
1837 git_buf_puts(buf
, raw_old
);
1838 git_buf_putc(buf
, ' ');
1839 git_buf_puts(buf
, raw_new
);
1841 git_signature__writebuf(buf
, " ", committer
);
1843 /* drop trailing LF */
1849 git_buf_putc(buf
, '\t');
1850 git_buf_puts(buf
, msg
);
1852 for (i
= 0; i
< buf
->size
- 2; i
++)
1853 if (buf
->ptr
[i
] == '\n')
1858 git_buf_putc(buf
, '\n');
1860 return git_buf_oom(buf
);
1863 static int lock_reflog(git_filebuf
*file
, refdb_fs_backend
*backend
, const char *refname
)
1865 git_repository
*repo
;
1866 git_buf log_path
= GIT_BUF_INIT
;
1869 repo
= backend
->repo
;
1871 if (!git_path_isvalid(backend
->repo
, refname
, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS
)) {
1872 git_error_set(GIT_ERROR_INVALID
, "invalid reference name '%s'", refname
);
1873 return GIT_EINVALIDSPEC
;
1876 if (retrieve_reflog_path(&log_path
, repo
, refname
) < 0)
1879 if (!git_path_isfile(git_buf_cstr(&log_path
))) {
1880 git_error_set(GIT_ERROR_INVALID
,
1881 "log file for reference '%s' doesn't exist", refname
);
1886 error
= git_filebuf_open(file
, git_buf_cstr(&log_path
), 0, GIT_REFLOG_FILE_MODE
);
1889 git_buf_dispose(&log_path
);
1894 static int refdb_reflog_fs__write(git_refdb_backend
*_backend
, git_reflog
*reflog
)
1898 git_reflog_entry
*entry
;
1899 refdb_fs_backend
*backend
;
1900 git_buf log
= GIT_BUF_INIT
;
1901 git_filebuf fbuf
= GIT_FILEBUF_INIT
;
1903 assert(_backend
&& reflog
);
1905 backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1907 if ((error
= lock_reflog(&fbuf
, backend
, reflog
->ref_name
)) < 0)
1910 git_vector_foreach(&reflog
->entries
, i
, entry
) {
1911 if (serialize_reflog_entry(&log
, &(entry
->oid_old
), &(entry
->oid_cur
), entry
->committer
, entry
->msg
) < 0)
1914 if ((error
= git_filebuf_write(&fbuf
, log
.ptr
, log
.size
)) < 0)
1918 error
= git_filebuf_commit(&fbuf
);
1922 git_filebuf_cleanup(&fbuf
);
1925 git_buf_dispose(&log
);
1930 /* Append to the reflog, must be called under reference lock */
1931 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
)
1933 int error
, is_symbolic
, open_flags
;
1934 git_oid old_id
= {{0}}, new_id
= {{0}};
1935 git_buf buf
= GIT_BUF_INIT
, path
= GIT_BUF_INIT
;
1936 git_repository
*repo
= backend
->repo
;
1938 is_symbolic
= ref
->type
== GIT_REFERENCE_SYMBOLIC
;
1940 /* "normal" symbolic updates do not write */
1942 strcmp(ref
->name
, GIT_HEAD_FILE
) &&
1946 /* From here on is_symbolic also means that it's HEAD */
1949 git_oid_cpy(&old_id
, old
);
1951 error
= git_reference_name_to_id(&old_id
, repo
, ref
->name
);
1952 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1957 git_oid_cpy(&new_id
, new);
1960 git_oid_cpy(&new_id
, git_reference_target(ref
));
1962 error
= git_reference_name_to_id(&new_id
, repo
, git_reference_symbolic_target(ref
));
1963 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1965 /* detaching HEAD does not create an entry */
1966 if (error
== GIT_ENOTFOUND
)
1973 if ((error
= serialize_reflog_entry(&buf
, &old_id
, &new_id
, who
, message
)) < 0)
1976 if ((error
= retrieve_reflog_path(&path
, repo
, ref
->name
)) < 0)
1979 if (((error
= git_futils_mkpath2file(git_buf_cstr(&path
), 0777)) < 0) &&
1980 (error
!= GIT_EEXISTS
)) {
1984 /* If the new branch matches part of the namespace of a previously deleted branch,
1985 * there maybe an obsolete/unused directory (or directory hierarchy) in the way.
1987 if (git_path_isdir(git_buf_cstr(&path
))) {
1988 if ((error
= git_futils_rmdir_r(git_buf_cstr(&path
), NULL
, GIT_RMDIR_SKIP_NONEMPTY
)) < 0) {
1989 if (error
== GIT_ENOTFOUND
)
1991 } else if (git_path_isdir(git_buf_cstr(&path
))) {
1992 git_error_set(GIT_ERROR_REFERENCE
, "cannot create reflog at '%s', there are reflogs beneath that folder",
1994 error
= GIT_EDIRECTORY
;
2001 open_flags
= O_WRONLY
| O_CREAT
| O_APPEND
;
2004 open_flags
|= O_FSYNC
;
2006 error
= git_futils_writebuffer(&buf
, git_buf_cstr(&path
), open_flags
, GIT_REFLOG_FILE_MODE
);
2009 git_buf_dispose(&buf
);
2010 git_buf_dispose(&path
);
2015 static int refdb_reflog_fs__rename(git_refdb_backend
*_backend
, const char *old_name
, const char *new_name
)
2018 git_buf old_path
= GIT_BUF_INIT
;
2019 git_buf new_path
= GIT_BUF_INIT
;
2020 git_buf temp_path
= GIT_BUF_INIT
;
2021 git_buf normalized
= GIT_BUF_INIT
;
2022 git_repository
*repo
;
2023 refdb_fs_backend
*backend
;
2025 assert(_backend
&& old_name
&& new_name
);
2027 backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
2028 repo
= backend
->repo
;
2030 if ((error
= git_reference__normalize_name(
2031 &normalized
, new_name
, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL
)) < 0)
2034 if (git_buf_joinpath(&temp_path
, repo
->gitdir
, GIT_REFLOG_DIR
) < 0)
2037 if (git_buf_joinpath(&old_path
, git_buf_cstr(&temp_path
), old_name
) < 0)
2040 if (git_buf_joinpath(&new_path
, git_buf_cstr(&temp_path
), git_buf_cstr(&normalized
)) < 0)
2043 if (!git_path_exists(git_buf_cstr(&old_path
))) {
2044 error
= GIT_ENOTFOUND
;
2049 * Move the reflog to a temporary place. This two-phase renaming is required
2050 * in order to cope with funny renaming use cases when one tries to move a reference
2051 * to a partially colliding namespace:
2053 * - a/b/c/d -> a/b/c
2055 if (git_buf_joinpath(&temp_path
, git_buf_cstr(&temp_path
), "temp_reflog") < 0)
2058 if ((fd
= git_futils_mktmp(&temp_path
, git_buf_cstr(&temp_path
), GIT_REFLOG_FILE_MODE
)) < 0) {
2065 if (p_rename(git_buf_cstr(&old_path
), git_buf_cstr(&temp_path
)) < 0) {
2066 git_error_set(GIT_ERROR_OS
, "failed to rename reflog for %s", new_name
);
2071 if (git_path_isdir(git_buf_cstr(&new_path
)) &&
2072 (git_futils_rmdir_r(git_buf_cstr(&new_path
), NULL
, GIT_RMDIR_SKIP_NONEMPTY
) < 0)) {
2077 if (git_futils_mkpath2file(git_buf_cstr(&new_path
), GIT_REFLOG_DIR_MODE
) < 0) {
2082 if (p_rename(git_buf_cstr(&temp_path
), git_buf_cstr(&new_path
)) < 0) {
2083 git_error_set(GIT_ERROR_OS
, "failed to rename reflog for %s", new_name
);
2088 git_buf_dispose(&temp_path
);
2089 git_buf_dispose(&old_path
);
2090 git_buf_dispose(&new_path
);
2091 git_buf_dispose(&normalized
);
2096 static int refdb_reflog_fs__delete(git_refdb_backend
*_backend
, const char *name
)
2098 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
2099 git_buf path
= GIT_BUF_INIT
;
2102 assert(_backend
&& name
);
2104 if ((error
= retrieve_reflog_path(&path
, backend
->repo
, name
)) < 0)
2107 if (!git_path_exists(path
.ptr
))
2110 if ((error
= p_unlink(path
.ptr
)) < 0)
2113 refdb_fs_backend__prune_refs(backend
, name
, GIT_REFLOG_DIR
);
2116 git_buf_dispose(&path
);
2121 int git_refdb_backend_fs(
2122 git_refdb_backend
**backend_out
,
2123 git_repository
*repository
)
2126 git_buf gitpath
= GIT_BUF_INIT
;
2127 refdb_fs_backend
*backend
;
2129 backend
= git__calloc(1, sizeof(refdb_fs_backend
));
2130 GIT_ERROR_CHECK_ALLOC(backend
);
2132 backend
->repo
= repository
;
2134 if (repository
->gitdir
) {
2135 backend
->gitpath
= setup_namespace(repository
, repository
->gitdir
);
2137 if (backend
->gitpath
== NULL
)
2141 if (repository
->commondir
) {
2142 backend
->commonpath
= setup_namespace(repository
, repository
->commondir
);
2144 if (backend
->commonpath
== NULL
)
2148 if (git_buf_joinpath(&gitpath
, backend
->commonpath
, GIT_PACKEDREFS_FILE
) < 0 ||
2149 git_sortedcache_new(
2150 &backend
->refcache
, offsetof(struct packref
, name
),
2151 NULL
, NULL
, packref_cmp
, git_buf_cstr(&gitpath
)) < 0)
2154 git_buf_dispose(&gitpath
);
2156 if (!git_repository__configmap_lookup(&t
, backend
->repo
, GIT_CONFIGMAP_IGNORECASE
) && t
) {
2157 backend
->iterator_flags
|= GIT_ITERATOR_IGNORE_CASE
;
2158 backend
->direach_flags
|= GIT_PATH_DIR_IGNORE_CASE
;
2160 if (!git_repository__configmap_lookup(&t
, backend
->repo
, GIT_CONFIGMAP_PRECOMPOSE
) && t
) {
2161 backend
->iterator_flags
|= GIT_ITERATOR_PRECOMPOSE_UNICODE
;
2162 backend
->direach_flags
|= GIT_PATH_DIR_PRECOMPOSE_UNICODE
;
2164 if ((!git_repository__configmap_lookup(&t
, backend
->repo
, GIT_CONFIGMAP_FSYNCOBJECTFILES
) && t
) ||
2165 git_repository__fsync_gitdir
)
2167 backend
->iterator_flags
|= GIT_ITERATOR_DESCEND_SYMLINKS
;
2169 backend
->parent
.exists
= &refdb_fs_backend__exists
;
2170 backend
->parent
.lookup
= &refdb_fs_backend__lookup
;
2171 backend
->parent
.iterator
= &refdb_fs_backend__iterator
;
2172 backend
->parent
.write
= &refdb_fs_backend__write
;
2173 backend
->parent
.del
= &refdb_fs_backend__delete
;
2174 backend
->parent
.rename
= &refdb_fs_backend__rename
;
2175 backend
->parent
.compress
= &refdb_fs_backend__compress
;
2176 backend
->parent
.lock
= &refdb_fs_backend__lock
;
2177 backend
->parent
.unlock
= &refdb_fs_backend__unlock
;
2178 backend
->parent
.has_log
= &refdb_reflog_fs__has_log
;
2179 backend
->parent
.ensure_log
= &refdb_reflog_fs__ensure_log
;
2180 backend
->parent
.free
= &refdb_fs_backend__free
;
2181 backend
->parent
.reflog_read
= &refdb_reflog_fs__read
;
2182 backend
->parent
.reflog_write
= &refdb_reflog_fs__write
;
2183 backend
->parent
.reflog_rename
= &refdb_reflog_fs__rename
;
2184 backend
->parent
.reflog_delete
= &refdb_reflog_fs__delete
;
2186 *backend_out
= (git_refdb_backend
*)backend
;
2190 git_buf_dispose(&gitpath
);
2191 git__free(backend
->gitpath
);
2192 git__free(backend
->commonpath
);