2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
10 #include "repository.h"
18 #include "sortedcache.h"
19 #include "signature.h"
20 #include "wildmatch.h"
24 #include <git2/object.h>
25 #include <git2/refdb.h>
26 #include <git2/branch.h>
27 #include <git2/sys/refdb_backend.h>
28 #include <git2/sys/refs.h>
29 #include <git2/sys/reflog.h>
31 #define DEFAULT_NESTING_LEVEL 5
32 #define MAX_NESTING_LEVEL 10
36 PACKREF_WAS_LOOSE
= 2,
37 PACKREF_CANNOT_PEEL
= 4,
51 char name
[GIT_FLEX_ARRAY
];
54 typedef struct refdb_fs_backend
{
55 git_refdb_backend parent
;
58 /* path to git directory */
60 /* path to common objects' directory */
63 git_sortedcache
*refcache
;
65 git_iterator_flag_t iterator_flags
;
66 uint32_t direach_flags
;
68 git_map packed_refs_map
;
69 git_mutex prlock
; /* protect packed_refs_map */
70 git_futils_filestamp packed_refs_stamp
;
74 static int refdb_reflog_fs__delete(git_refdb_backend
*_backend
, const char *name
);
75 static char *packed_set_peeling_mode(char *data
, size_t data_sz
, refdb_fs_backend
*backend
);
77 GIT_INLINE(int) loose_path(
82 if (git_str_joinpath(out
, base
, refname
) < 0)
85 return git_fs_path_validate_str_length_with_suffix(out
,
86 CONST_STRLEN(".lock"));
89 GIT_INLINE(int) reflog_path(
97 base
= (strcmp(refname
, GIT_HEAD_FILE
) == 0) ? repo
->gitdir
:
100 if ((error
= git_str_joinpath(out
, base
, GIT_REFLOG_DIR
)) < 0)
103 return loose_path(out
, out
->ptr
, refname
);
106 static int packref_cmp(const void *a_
, const void *b_
)
108 const struct packref
*a
= a_
, *b
= b_
;
109 return strcmp(a
->name
, b
->name
);
112 static int packed_reload(refdb_fs_backend
*backend
)
115 git_str packedrefs
= GIT_STR_INIT
;
116 char *scan
, *eof
, *eol
;
118 if (!backend
->gitpath
)
121 error
= git_sortedcache_lockandload(backend
->refcache
, &packedrefs
);
124 * If we can't find the packed-refs, clear table and return.
125 * Any other error just gets passed through.
126 * If no error, and file wasn't changed, just return.
127 * Anything else means we need to refresh the packed refs.
130 if (error
== GIT_ENOTFOUND
) {
131 GIT_UNUSED(git_sortedcache_clear(backend
->refcache
, true));
138 /* At this point, refresh the packed refs from the loaded buffer. */
140 GIT_UNUSED(git_sortedcache_clear(backend
->refcache
, false));
142 scan
= packedrefs
.ptr
;
143 eof
= scan
+ packedrefs
.size
;
145 scan
= packed_set_peeling_mode(scan
, packedrefs
.size
, backend
);
149 while (scan
< eof
&& *scan
== '#') {
150 if (!(eol
= strchr(scan
, '\n')))
159 /* parse "<OID> <refname>\n" */
161 if (git_oid_fromstr(&oid
, scan
) < 0)
163 scan
+= GIT_OID_HEXSZ
;
167 if (!(eol
= strchr(scan
, '\n')))
173 if (git_sortedcache_upsert((void **)&ref
, backend
->refcache
, scan
) < 0)
177 git_oid_cpy(&ref
->oid
, &oid
);
179 /* look for optional "^<OID>\n" */
182 if (git_oid_fromstr(&oid
, scan
+ 1) < 0)
184 scan
+= GIT_OID_HEXSZ
+ 1;
187 if (!(eol
= strchr(scan
, '\n')))
192 git_oid_cpy(&ref
->peel
, &oid
);
193 ref
->flags
|= PACKREF_HAS_PEEL
;
195 else if (backend
->peeling_mode
== PEELING_FULL
||
196 (backend
->peeling_mode
== PEELING_STANDARD
&&
197 git__prefixcmp(ref
->name
, GIT_REFS_TAGS_DIR
) == 0))
198 ref
->flags
|= PACKREF_CANNOT_PEEL
;
201 git_sortedcache_wunlock(backend
->refcache
);
202 git_str_dispose(&packedrefs
);
207 git_error_set(GIT_ERROR_REFERENCE
, "corrupted packed references file");
209 GIT_UNUSED(git_sortedcache_clear(backend
->refcache
, false));
210 git_sortedcache_wunlock(backend
->refcache
);
211 git_str_dispose(&packedrefs
);
216 static int loose_parse_oid(
217 git_oid
*oid
, const char *filename
, git_str
*file_content
)
219 const char *str
= git_str_cstr(file_content
);
221 if (git_str_len(file_content
) < GIT_OID_HEXSZ
)
224 /* we need to get 40 OID characters from the file */
225 if (git_oid_fromstr(oid
, str
) < 0)
228 /* If the file is longer than 40 chars, the 41st must be a space */
229 str
+= GIT_OID_HEXSZ
;
230 if (*str
== '\0' || git__isspace(*str
))
234 git_error_set(GIT_ERROR_REFERENCE
, "corrupted loose reference file: %s", filename
);
238 static int loose_readbuffer(git_str
*buf
, const char *base
, const char *path
)
242 if ((error
= loose_path(buf
, base
, path
)) < 0 ||
243 (error
= git_futils_readbuffer(buf
, buf
->ptr
)) < 0)
244 git_str_dispose(buf
);
249 static int loose_lookup_to_packfile(refdb_fs_backend
*backend
, const char *name
)
252 git_str ref_file
= GIT_STR_INIT
;
253 struct packref
*ref
= NULL
;
256 /* if we fail to load the loose reference, assume someone changed
257 * the filesystem under us and skip it...
259 if (loose_readbuffer(&ref_file
, backend
->gitpath
, name
) < 0) {
264 /* skip symbolic refs */
265 if (!git__prefixcmp(git_str_cstr(&ref_file
), GIT_SYMREF
))
268 /* parse OID from file */
269 if ((error
= loose_parse_oid(&oid
, name
, &ref_file
)) < 0)
272 if ((error
= git_sortedcache_wlock(backend
->refcache
)) < 0)
275 if (!(error
= git_sortedcache_upsert(
276 (void **)&ref
, backend
->refcache
, name
))) {
278 git_oid_cpy(&ref
->oid
, &oid
);
279 ref
->flags
= PACKREF_WAS_LOOSE
;
282 git_sortedcache_wunlock(backend
->refcache
);
285 git_str_dispose(&ref_file
);
289 static int _dirent_loose_load(void *payload
, git_str
*full_path
)
291 refdb_fs_backend
*backend
= payload
;
292 const char *file_path
;
294 if (git__suffixcmp(full_path
->ptr
, ".lock") == 0)
297 if (git_fs_path_isdir(full_path
->ptr
)) {
298 int error
= git_fs_path_direach(
299 full_path
, backend
->direach_flags
, _dirent_loose_load
, backend
);
300 /* Race with the filesystem, ignore it */
301 if (error
== GIT_ENOTFOUND
) {
309 file_path
= full_path
->ptr
+ strlen(backend
->gitpath
);
311 return loose_lookup_to_packfile(backend
, file_path
);
315 * Load all the loose references from the repository
316 * into the in-memory Packfile, and build a vector with
317 * all the references so it can be written back to
320 static int packed_loadloose(refdb_fs_backend
*backend
)
323 git_str refs_path
= GIT_STR_INIT
;
325 if (git_str_joinpath(&refs_path
, backend
->gitpath
, GIT_REFS_DIR
) < 0)
329 * Load all the loose files from disk into the Packfile table.
330 * This will overwrite any old packed entries with their
331 * updated loose versions
333 error
= git_fs_path_direach(
334 &refs_path
, backend
->direach_flags
, _dirent_loose_load
, backend
);
336 git_str_dispose(&refs_path
);
341 static int refdb_fs_backend__exists(
343 git_refdb_backend
*_backend
,
344 const char *ref_name
)
346 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
347 git_str ref_path
= GIT_STR_INIT
;
350 GIT_ASSERT_ARG(backend
);
354 if ((error
= loose_path(&ref_path
, backend
->gitpath
, ref_name
)) < 0)
357 if (git_fs_path_isfile(ref_path
.ptr
)) {
362 if ((error
= packed_reload(backend
)) < 0)
365 if (git_sortedcache_lookup(backend
->refcache
, ref_name
) != NULL
) {
371 git_str_dispose(&ref_path
);
375 static const char *loose_parse_symbolic(git_str
*file_content
)
377 const unsigned int header_len
= (unsigned int)strlen(GIT_SYMREF
);
378 const char *refname_start
;
380 refname_start
= (const char *)file_content
->ptr
;
382 if (git_str_len(file_content
) < header_len
+ 1) {
383 git_error_set(GIT_ERROR_REFERENCE
, "corrupted loose reference file");
388 * Assume we have already checked for the header
389 * before calling this function
391 refname_start
+= header_len
;
393 return refname_start
;
397 * Returns whether a reference is stored per worktree or not.
398 * Per-worktree references are:
400 * - all pseudorefs, e.g. HEAD and MERGE_HEAD
401 * - all references stored inside of "refs/bisect/"
403 static bool is_per_worktree_ref(const char *ref_name
)
405 return git__prefixcmp(ref_name
, "refs/") != 0 ||
406 git__prefixcmp(ref_name
, "refs/bisect/") == 0;
409 static int loose_lookup(
411 refdb_fs_backend
*backend
,
412 const char *ref_name
)
414 git_str ref_file
= GIT_STR_INIT
;
421 if (is_per_worktree_ref(ref_name
))
422 ref_dir
= backend
->gitpath
;
424 ref_dir
= backend
->commonpath
;
426 if ((error
= loose_readbuffer(&ref_file
, ref_dir
, ref_name
)) < 0)
427 /* cannot read loose ref file - gah */;
428 else if (git__prefixcmp(git_str_cstr(&ref_file
), GIT_SYMREF
) == 0) {
431 git_str_rtrim(&ref_file
);
433 if (!(target
= loose_parse_symbolic(&ref_file
)))
435 else if (out
!= NULL
)
436 *out
= git_reference__alloc_symbolic(ref_name
, target
);
440 if (!(error
= loose_parse_oid(&oid
, ref_name
, &ref_file
)) &&
442 *out
= git_reference__alloc(ref_name
, &oid
, NULL
);
445 git_str_dispose(&ref_file
);
449 static int ref_error_notfound(const char *name
)
451 git_error_set(GIT_ERROR_REFERENCE
, "reference '%s' not found", name
);
452 return GIT_ENOTFOUND
;
455 static char *packed_set_peeling_mode(
458 refdb_fs_backend
*backend
)
460 static const char *traits_header
= "# pack-refs with:";
462 backend
->peeling_mode
= PEELING_NONE
;
464 if (git__prefixncmp(data
, data_sz
, traits_header
) == 0) {
465 size_t hdr_sz
= strlen(traits_header
);
466 const char *sorted
= " sorted ";
467 const char *peeled
= " peeled ";
468 const char *fully_peeled
= " fully-peeled ";
472 eol
= memchr(data
, '\n', data_sz
);
477 if (git__memmem(data
, eol
- data
, fully_peeled
, strlen(fully_peeled
)))
478 backend
->peeling_mode
= PEELING_FULL
;
479 else if (git__memmem(data
, eol
- data
, peeled
, strlen(peeled
)))
480 backend
->peeling_mode
= PEELING_STANDARD
;
482 backend
->sorted
= NULL
!= git__memmem(data
, eol
- data
, sorted
, strlen(sorted
));
489 static void packed_map_free(refdb_fs_backend
*backend
)
491 if (backend
->packed_refs_map
.data
) {
493 git__free(backend
->packed_refs_map
.data
);
495 git_futils_mmap_free(&backend
->packed_refs_map
);
497 backend
->packed_refs_map
.data
= NULL
;
498 backend
->packed_refs_map
.len
= 0;
499 git_futils_filestamp_set(&backend
->packed_refs_stamp
, NULL
);
503 static int packed_map_check(refdb_fs_backend
*backend
)
509 if ((error
= git_mutex_lock(&backend
->prlock
)) < 0)
512 if (backend
->packed_refs_map
.data
&&
513 !git_futils_filestamp_check(
514 &backend
->packed_refs_stamp
, backend
->refcache
->path
)) {
515 git_mutex_unlock(&backend
->prlock
);
518 packed_map_free(backend
);
520 fd
= git_futils_open_ro(backend
->refcache
->path
);
522 git_mutex_unlock(&backend
->prlock
);
523 if (fd
== GIT_ENOTFOUND
) {
530 if (p_fstat(fd
, &st
) < 0) {
532 git_mutex_unlock(&backend
->prlock
);
533 git_error_set(GIT_ERROR_OS
, "unable to stat packed-refs '%s'", backend
->refcache
->path
);
537 if (st
.st_size
== 0) {
539 git_mutex_unlock(&backend
->prlock
);
543 git_futils_filestamp_set_from_stat(&backend
->packed_refs_stamp
, &st
);
546 /* on windows, we copy the entire file into memory rather than using
547 * mmap() because using mmap() on windows also locks the file and this
548 * map is long-lived. */
549 backend
->packed_refs_map
.len
= (size_t)st
.st_size
;
550 backend
->packed_refs_map
.data
=
551 git__malloc(backend
->packed_refs_map
.len
);
552 GIT_ERROR_CHECK_ALLOC(backend
->packed_refs_map
.data
);
555 p_read(fd
, backend
->packed_refs_map
.data
,
556 backend
->packed_refs_map
.len
);
557 error
= (bytesread
== (ssize_t
)backend
->packed_refs_map
.len
) ? 0 : -1;
560 error
= git_futils_mmap_ro(&backend
->packed_refs_map
, fd
, 0, (size_t)st
.st_size
);
564 git_mutex_unlock(&backend
->prlock
);
568 packed_set_peeling_mode(
569 backend
->packed_refs_map
.data
, backend
->packed_refs_map
.len
,
572 git_mutex_unlock(&backend
->prlock
);
577 * Find beginning of packed-ref record pointed to by p.
578 * buf - a lower-bound pointer to some memory buffer
579 * p - an upper-bound pointer to the same memory buffer
581 static const char *start_of_record(const char *buf
, const char *p
)
585 nl
= git__memrchr(buf
, '\n', nl
- buf
);
589 if (nl
[1] == '^' && nl
> buf
)
598 * Find end of packed-ref record pointed to by p.
599 * end - an upper-bound pointer to some memory buffer
600 * p - a lower-bound pointer to the same memory buffer
602 static const char *end_of_record(const char *p
, const char *end
)
606 p
= memchr(p
, '\n', sz
);
610 if (p
< end
&& p
[0] == '^')
619 cmp_record_to_refname(const char *rec
, size_t data_end
, const char *ref_name
)
621 const size_t ref_len
= strlen(ref_name
);
625 rec
+= GIT_OID_HEXSZ
+ 1; /* <oid> + space */
626 if (data_end
< GIT_OID_HEXSZ
+ 3) {
627 /* an incomplete (corrupt) record is treated as less than ref_name */
630 data_end
-= GIT_OID_HEXSZ
+ 1;
632 end
= memchr(rec
, '\n', data_end
);
634 data_end
= end
- rec
;
636 cmp_val
= memcmp(rec
, ref_name
, min(ref_len
, data_end
));
638 if (cmp_val
== 0 && data_end
!= ref_len
)
639 return (data_end
> ref_len
) ? 1 : -1;
643 static int packed_unsorted_lookup(
645 refdb_fs_backend
*backend
,
646 const char *ref_name
)
649 struct packref
*entry
;
651 if ((error
= packed_reload(backend
)) < 0)
654 if (git_sortedcache_rlock(backend
->refcache
) < 0)
657 entry
= git_sortedcache_lookup(backend
->refcache
, ref_name
);
659 error
= ref_error_notfound(ref_name
);
661 *out
= git_reference__alloc(ref_name
, &entry
->oid
, &entry
->peel
);
666 git_sortedcache_runlock(backend
->refcache
);
671 static int packed_lookup(
673 refdb_fs_backend
*backend
,
674 const char *ref_name
)
677 const char *left
, *right
, *data_end
;
679 if ((error
= packed_map_check(backend
)) < 0)
682 if (!backend
->sorted
)
683 return packed_unsorted_lookup(out
, backend
, ref_name
);
685 left
= backend
->packed_refs_map
.data
;
686 right
= data_end
= (const char *) backend
->packed_refs_map
.data
+
687 backend
->packed_refs_map
.len
;
689 while (left
< right
&& *left
== '#') {
690 if (!(left
= memchr(left
, '\n', data_end
- left
)))
695 while (left
< right
) {
696 const char *mid
, *rec
;
699 mid
= left
+ (right
- left
) / 2;
700 rec
= start_of_record(left
, mid
);
701 compare
= cmp_record_to_refname(rec
, data_end
- rec
, ref_name
);
704 left
= end_of_record(mid
, right
);
705 } else if (compare
> 0) {
709 git_oid oid
, peel
, *peel_ptr
= NULL
;
711 if (data_end
- rec
< GIT_OID_HEXSZ
||
712 git_oid_fromstr(&oid
, rec
) < 0) {
715 rec
+= GIT_OID_HEXSZ
+ 1;
716 if (!(eol
= memchr(rec
, '\n', data_end
- rec
))) {
720 /* look for optional "^<OID>\n" */
722 if (eol
+ 1 < data_end
) {
727 if (data_end
- rec
< GIT_OID_HEXSZ
||
728 git_oid_fromstr(&peel
, rec
) < 0) {
735 *out
= git_reference__alloc(ref_name
, &oid
, peel_ptr
);
743 return ref_error_notfound(ref_name
);
746 git_error_set(GIT_ERROR_REFERENCE
, "corrupted packed references file");
750 static int refdb_fs_backend__lookup(
752 git_refdb_backend
*_backend
,
753 const char *ref_name
)
755 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
758 GIT_ASSERT_ARG(backend
);
760 if (!(error
= loose_lookup(out
, backend
, ref_name
)))
763 /* only try to lookup this reference on the packfile if it
764 * wasn't found on the loose refs; not if there was a critical error */
765 if (error
== GIT_ENOTFOUND
) {
767 error
= packed_lookup(out
, backend
, ref_name
);
773 git_reference_iterator parent
;
780 git_sortedcache
*cache
;
785 static void refdb_fs_backend__iterator_free(git_reference_iterator
*_iter
)
787 refdb_fs_iter
*iter
= GIT_CONTAINER_OF(_iter
, refdb_fs_iter
, parent
);
789 git_vector_free(&iter
->loose
);
790 git_pool_clear(&iter
->pool
);
791 git_sortedcache_free(iter
->cache
);
795 static int iter_load_loose_paths(refdb_fs_backend
*backend
, refdb_fs_iter
*iter
)
798 git_str path
= GIT_STR_INIT
;
799 git_iterator
*fsit
= NULL
;
800 git_iterator_options fsit_opts
= GIT_ITERATOR_OPTIONS_INIT
;
801 const git_index_entry
*entry
= NULL
;
802 const char *ref_prefix
= GIT_REFS_DIR
;
803 size_t ref_prefix_len
= strlen(ref_prefix
);
805 if (!backend
->commonpath
) /* do nothing if no commonpath for loose refs */
808 fsit_opts
.flags
= backend
->iterator_flags
;
811 const char *last_sep
= NULL
;
813 for (pos
= iter
->glob
; *pos
; ++pos
) {
829 ref_prefix
= iter
->glob
;
830 ref_prefix_len
= (last_sep
- ref_prefix
) + 1;
834 if ((error
= git_str_puts(&path
, backend
->commonpath
)) < 0 ||
835 (error
= git_str_put(&path
, ref_prefix
, ref_prefix_len
)) < 0) {
836 git_str_dispose(&path
);
840 if ((error
= git_iterator_for_filesystem(&fsit
, path
.ptr
, &fsit_opts
)) < 0) {
841 git_str_dispose(&path
);
842 return (iter
->glob
&& error
== GIT_ENOTFOUND
)? 0 : error
;
845 error
= git_str_sets(&path
, ref_prefix
);
847 while (!error
&& !git_iterator_advance(&entry
, fsit
)) {
848 const char *ref_name
;
851 git_str_truncate(&path
, ref_prefix_len
);
852 git_str_puts(&path
, entry
->path
);
853 ref_name
= git_str_cstr(&path
);
855 if (git__suffixcmp(ref_name
, ".lock") == 0 ||
856 (iter
->glob
&& wildmatch(iter
->glob
, ref_name
, 0) != 0))
859 ref_dup
= git_pool_strdup(&iter
->pool
, ref_name
);
863 error
= git_vector_insert(&iter
->loose
, ref_dup
);
866 git_iterator_free(fsit
);
867 git_str_dispose(&path
);
872 static int refdb_fs_backend__iterator_next(
873 git_reference
**out
, git_reference_iterator
*_iter
)
875 int error
= GIT_ITEROVER
;
876 refdb_fs_iter
*iter
= GIT_CONTAINER_OF(_iter
, refdb_fs_iter
, parent
);
877 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(iter
->parent
.db
->backend
, refdb_fs_backend
, parent
);
880 while (iter
->loose_pos
< iter
->loose
.length
) {
881 const char *path
= git_vector_get(&iter
->loose
, iter
->loose_pos
++);
883 if (loose_lookup(out
, backend
, path
) == 0) {
884 ref
= git_sortedcache_lookup(iter
->cache
, path
);
886 ref
->flags
|= PACKREF_SHADOWED
;
894 error
= GIT_ITEROVER
;
895 while (iter
->packed_pos
< git_sortedcache_entrycount(iter
->cache
)) {
896 ref
= git_sortedcache_entry(iter
->cache
, iter
->packed_pos
++);
897 if (!ref
) /* stop now if another thread deleted refs and we past end */
900 if (ref
->flags
& PACKREF_SHADOWED
)
902 if (iter
->glob
&& wildmatch(iter
->glob
, ref
->name
, 0) != 0)
905 *out
= git_reference__alloc(ref
->name
, &ref
->oid
, &ref
->peel
);
906 error
= (*out
!= NULL
) ? 0 : -1;
913 static int refdb_fs_backend__iterator_next_name(
914 const char **out
, git_reference_iterator
*_iter
)
916 int error
= GIT_ITEROVER
;
917 refdb_fs_iter
*iter
= GIT_CONTAINER_OF(_iter
, refdb_fs_iter
, parent
);
918 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(iter
->parent
.db
->backend
, refdb_fs_backend
, parent
);
921 while (iter
->loose_pos
< iter
->loose
.length
) {
922 const char *path
= git_vector_get(&iter
->loose
, iter
->loose_pos
++);
925 if (loose_lookup(NULL
, backend
, path
) == 0) {
926 ref
= git_sortedcache_lookup(iter
->cache
, path
);
928 ref
->flags
|= PACKREF_SHADOWED
;
937 error
= GIT_ITEROVER
;
938 while (iter
->packed_pos
< git_sortedcache_entrycount(iter
->cache
)) {
939 ref
= git_sortedcache_entry(iter
->cache
, iter
->packed_pos
++);
940 if (!ref
) /* stop now if another thread deleted refs and we past end */
943 if (ref
->flags
& PACKREF_SHADOWED
)
945 if (iter
->glob
&& wildmatch(iter
->glob
, ref
->name
, 0) != 0)
956 static int refdb_fs_backend__iterator(
957 git_reference_iterator
**out
, git_refdb_backend
*_backend
, const char *glob
)
959 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
960 refdb_fs_iter
*iter
= NULL
;
963 GIT_ASSERT_ARG(backend
);
965 iter
= git__calloc(1, sizeof(refdb_fs_iter
));
966 GIT_ERROR_CHECK_ALLOC(iter
);
968 if ((error
= git_pool_init(&iter
->pool
, 1)) < 0)
971 if ((error
= git_vector_init(&iter
->loose
, 8, NULL
)) < 0)
975 (iter
->glob
= git_pool_strdup(&iter
->pool
, glob
)) == NULL
) {
976 error
= GIT_ERROR_NOMEMORY
;
980 if ((error
= iter_load_loose_paths(backend
, iter
)) < 0)
983 if ((error
= packed_reload(backend
)) < 0)
986 if ((error
= git_sortedcache_copy(&iter
->cache
, backend
->refcache
, 1, NULL
, NULL
)) < 0)
989 iter
->parent
.next
= refdb_fs_backend__iterator_next
;
990 iter
->parent
.next_name
= refdb_fs_backend__iterator_next_name
;
991 iter
->parent
.free
= refdb_fs_backend__iterator_free
;
993 *out
= (git_reference_iterator
*)iter
;
996 refdb_fs_backend__iterator_free((git_reference_iterator
*)iter
);
1000 static bool ref_is_available(
1001 const char *old_ref
, const char *new_ref
, const char *this_ref
)
1003 if (old_ref
== NULL
|| strcmp(old_ref
, this_ref
)) {
1004 size_t reflen
= strlen(this_ref
);
1005 size_t newlen
= strlen(new_ref
);
1006 size_t cmplen
= reflen
< newlen
? reflen
: newlen
;
1007 const char *lead
= reflen
< newlen
? new_ref
: this_ref
;
1009 if (!strncmp(new_ref
, this_ref
, cmplen
) && lead
[cmplen
] == '/') {
1017 static int reference_path_available(
1018 refdb_fs_backend
*backend
,
1019 const char *new_ref
,
1020 const char *old_ref
,
1026 if ((error
= packed_reload(backend
)) < 0)
1032 if ((error
= refdb_fs_backend__exists(
1033 &exists
, (git_refdb_backend
*)backend
, new_ref
)) < 0) {
1038 git_error_set(GIT_ERROR_REFERENCE
,
1039 "failed to write reference '%s': a reference with "
1040 "that name already exists.", new_ref
);
1045 if ((error
= git_sortedcache_rlock(backend
->refcache
)) < 0)
1048 for (i
= 0; i
< git_sortedcache_entrycount(backend
->refcache
); ++i
) {
1049 struct packref
*ref
= git_sortedcache_entry(backend
->refcache
, i
);
1051 if (ref
&& !ref_is_available(old_ref
, new_ref
, ref
->name
)) {
1052 git_sortedcache_runlock(backend
->refcache
);
1053 git_error_set(GIT_ERROR_REFERENCE
,
1054 "path to reference '%s' collides with existing one", new_ref
);
1059 git_sortedcache_runlock(backend
->refcache
);
1063 static int loose_lock(git_filebuf
*file
, refdb_fs_backend
*backend
, const char *name
)
1065 int error
, filebuf_flags
;
1066 git_str ref_path
= GIT_STR_INIT
;
1067 const char *basedir
;
1069 GIT_ASSERT_ARG(file
);
1070 GIT_ASSERT_ARG(backend
);
1071 GIT_ASSERT_ARG(name
);
1073 if (!git_path_is_valid(backend
->repo
, name
, 0, GIT_FS_PATH_REJECT_FILESYSTEM_DEFAULTS
)) {
1074 git_error_set(GIT_ERROR_INVALID
, "invalid reference name '%s'", name
);
1075 return GIT_EINVALIDSPEC
;
1078 if (is_per_worktree_ref(name
))
1079 basedir
= backend
->gitpath
;
1081 basedir
= backend
->commonpath
;
1083 /* Remove a possibly existing empty directory hierarchy
1084 * which name would collide with the reference name
1086 if ((error
= git_futils_rmdir_r(name
, basedir
, GIT_RMDIR_SKIP_NONEMPTY
)) < 0)
1089 if ((error
= loose_path(&ref_path
, basedir
, name
)) < 0)
1092 filebuf_flags
= GIT_FILEBUF_CREATE_LEADING_DIRS
;
1094 filebuf_flags
|= GIT_FILEBUF_FSYNC
;
1096 error
= git_filebuf_open(file
, ref_path
.ptr
, filebuf_flags
, GIT_REFS_FILE_MODE
);
1098 if (error
== GIT_EDIRECTORY
)
1099 git_error_set(GIT_ERROR_REFERENCE
, "cannot lock ref '%s', there are refs beneath that folder", name
);
1101 git_str_dispose(&ref_path
);
1105 static int loose_commit(git_filebuf
*file
, const git_reference
*ref
)
1107 GIT_ASSERT_ARG(file
);
1108 GIT_ASSERT_ARG(ref
);
1110 if (ref
->type
== GIT_REFERENCE_DIRECT
) {
1111 char oid
[GIT_OID_HEXSZ
+ 1];
1112 git_oid_nfmt(oid
, sizeof(oid
), &ref
->target
.oid
);
1114 git_filebuf_printf(file
, "%s\n", oid
);
1115 } else if (ref
->type
== GIT_REFERENCE_SYMBOLIC
) {
1116 git_filebuf_printf(file
, GIT_SYMREF
"%s\n", ref
->target
.symbolic
);
1121 return git_filebuf_commit(file
);
1124 static int refdb_fs_backend__lock(void **out
, git_refdb_backend
*_backend
, const char *refname
)
1128 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1130 lock
= git__calloc(1, sizeof(git_filebuf
));
1131 GIT_ERROR_CHECK_ALLOC(lock
);
1133 if ((error
= loose_lock(lock
, backend
, refname
)) < 0) {
1142 static int refdb_fs_backend__write_tail(
1143 git_refdb_backend
*_backend
,
1144 const git_reference
*ref
,
1147 const git_oid
*old_id
,
1148 const char *old_target
,
1149 const git_signature
*who
,
1150 const char *message
);
1152 static int refdb_fs_backend__delete_tail(
1153 git_refdb_backend
*_backend
,
1155 const char *ref_name
,
1156 const git_oid
*old_id
,
1157 const char *old_target
);
1159 static int refdb_fs_backend__unlock(git_refdb_backend
*backend
, void *payload
, int success
, int update_reflog
,
1160 const git_reference
*ref
, const git_signature
*sig
, const char *message
)
1162 git_filebuf
*lock
= (git_filebuf
*) payload
;
1166 error
= refdb_fs_backend__delete_tail(backend
, lock
, ref
->name
, NULL
, NULL
);
1168 error
= refdb_fs_backend__write_tail(backend
, ref
, lock
, update_reflog
, NULL
, NULL
, sig
, message
);
1170 git_filebuf_cleanup(lock
);
1177 * Find out what object this reference resolves to.
1179 * For references that point to a 'big' tag (e.g. an
1180 * actual tag object on the repository), we need to
1181 * cache on the packfile the OID of the object to
1182 * which that 'big tag' is pointing to.
1184 static int packed_find_peel(refdb_fs_backend
*backend
, struct packref
*ref
)
1188 if (ref
->flags
& PACKREF_HAS_PEEL
|| ref
->flags
& PACKREF_CANNOT_PEEL
)
1192 * Find the tagged object in the repository
1194 if (git_object_lookup(&object
, backend
->repo
, &ref
->oid
, GIT_OBJECT_ANY
) < 0)
1198 * If the tagged object is a Tag object, we need to resolve it;
1199 * if the ref is actually a 'weak' ref, we don't need to resolve
1202 if (git_object_type(object
) == GIT_OBJECT_TAG
) {
1203 git_tag
*tag
= (git_tag
*)object
;
1206 * Find the object pointed at by this tag
1208 git_oid_cpy(&ref
->peel
, git_tag_target_id(tag
));
1209 ref
->flags
|= PACKREF_HAS_PEEL
;
1212 * The reference has now cached the resolved OID, and is
1213 * marked at such. When written to the packfile, it'll be
1214 * accompanied by this resolved oid
1218 git_object_free(object
);
1223 * Write a single reference into a packfile
1225 static int packed_write_ref(struct packref
*ref
, git_filebuf
*file
)
1227 char oid
[GIT_OID_HEXSZ
+ 1];
1228 git_oid_nfmt(oid
, sizeof(oid
), &ref
->oid
);
1231 * For references that peel to an object in the repo, we must
1232 * write the resulting peel on a separate line, e.g.
1234 * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4
1235 * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100
1237 * This obviously only applies to tags.
1238 * The required peels have already been loaded into `ref->peel_target`.
1240 if (ref
->flags
& PACKREF_HAS_PEEL
) {
1241 char peel
[GIT_OID_HEXSZ
+ 1];
1242 git_oid_nfmt(peel
, sizeof(peel
), &ref
->peel
);
1244 if (git_filebuf_printf(file
, "%s %s\n^%s\n", oid
, ref
->name
, peel
) < 0)
1247 if (git_filebuf_printf(file
, "%s %s\n", oid
, ref
->name
) < 0)
1255 * Remove all loose references
1257 * Once we have successfully written a packfile,
1258 * all the loose references that were packed must be
1259 * removed from disk.
1261 * This is a dangerous method; make sure the packfile
1262 * is well-written, because we are destructing references
1265 static int packed_remove_loose(refdb_fs_backend
*backend
)
1268 git_filebuf lock
= GIT_FILEBUF_INIT
;
1269 git_str ref_content
= GIT_STR_INIT
;
1272 /* backend->refcache is already locked when this is called */
1274 for (i
= 0; i
< git_sortedcache_entrycount(backend
->refcache
); ++i
) {
1275 struct packref
*ref
= git_sortedcache_entry(backend
->refcache
, i
);
1278 if (!ref
|| !(ref
->flags
& PACKREF_WAS_LOOSE
))
1281 git_filebuf_cleanup(&lock
);
1283 /* We need to stop anybody from updating the ref while we try to do a safe delete */
1284 error
= loose_lock(&lock
, backend
, ref
->name
);
1285 /* If someone else is updating it, let them do it */
1286 if (error
== GIT_EEXISTS
|| error
== GIT_ENOTFOUND
)
1290 git_str_dispose(&ref_content
);
1291 git_error_set(GIT_ERROR_REFERENCE
, "failed to lock loose reference '%s'", ref
->name
);
1295 error
= git_futils_readbuffer(&ref_content
, lock
.path_original
);
1296 /* Someone else beat us to cleaning up the ref, let's simply continue */
1297 if (error
== GIT_ENOTFOUND
)
1300 /* This became a symref between us packing and trying to delete it, so ignore it */
1301 if (!git__prefixcmp(ref_content
.ptr
, GIT_SYMREF
))
1304 /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */
1305 if (loose_parse_oid(¤t_id
, lock
.path_original
, &ref_content
) < 0)
1308 /* If the ref moved since we packed it, we must not delete it */
1309 if (!git_oid_equal(¤t_id
, &ref
->oid
))
1313 * if we fail to remove a single file, this is *not* good,
1314 * but we should keep going and remove as many as possible.
1315 * If we fail to remove, the ref is still in the old state, so
1316 * we haven't lost information.
1318 p_unlink(lock
.path_original
);
1321 git_str_dispose(&ref_content
);
1322 git_filebuf_cleanup(&lock
);
1327 * Write all the contents in the in-memory packfile to disk.
1329 static int packed_write(refdb_fs_backend
*backend
)
1331 git_sortedcache
*refcache
= backend
->refcache
;
1332 git_filebuf pack_file
= GIT_FILEBUF_INIT
;
1333 int error
, open_flags
= 0;
1336 /* take lock and close up packed-refs mmap if open */
1337 if ((error
= git_mutex_lock(&backend
->prlock
)) < 0) {
1341 packed_map_free(backend
);
1343 git_mutex_unlock(&backend
->prlock
);
1345 /* lock the cache to updates while we do this */
1346 if ((error
= git_sortedcache_wlock(refcache
)) < 0)
1350 open_flags
= GIT_FILEBUF_FSYNC
;
1352 /* Open the file! */
1353 if ((error
= git_filebuf_open(&pack_file
, git_sortedcache_path(refcache
), open_flags
, GIT_PACKEDREFS_FILE_MODE
)) < 0)
1356 /* Packfiles have a header... apparently
1357 * This is in fact not required, but we might as well print it
1359 if ((error
= git_filebuf_printf(&pack_file
, "%s\n", GIT_PACKEDREFS_HEADER
)) < 0)
1362 for (i
= 0; i
< git_sortedcache_entrycount(refcache
); ++i
) {
1363 struct packref
*ref
= git_sortedcache_entry(refcache
, i
);
1365 GIT_ASSERT_WITH_CLEANUP(ref
, {
1370 if ((error
= packed_find_peel(backend
, ref
)) < 0)
1373 if ((error
= packed_write_ref(ref
, &pack_file
)) < 0)
1377 /* if we've written all the references properly, we can commit
1378 * the packfile to make the changes effective */
1379 if ((error
= git_filebuf_commit(&pack_file
)) < 0)
1382 /* when and only when the packfile has been properly written,
1383 * we can go ahead and remove the loose refs */
1384 if ((error
= packed_remove_loose(backend
)) < 0)
1387 git_sortedcache_updated(refcache
);
1388 git_sortedcache_wunlock(refcache
);
1390 /* we're good now */
1394 git_filebuf_cleanup(&pack_file
);
1395 git_sortedcache_wunlock(refcache
);
1400 static int packed_delete(refdb_fs_backend
*backend
, const char *ref_name
)
1403 int error
, found
= 0;
1405 if ((error
= packed_reload(backend
)) < 0)
1408 if ((error
= git_sortedcache_wlock(backend
->refcache
)) < 0)
1411 /* If a packed reference exists, remove it from the packfile and repack if necessary */
1412 error
= git_sortedcache_lookup_index(&pack_pos
, backend
->refcache
, ref_name
);
1414 error
= git_sortedcache_remove(backend
->refcache
, pack_pos
);
1417 if (error
== GIT_ENOTFOUND
)
1420 git_sortedcache_wunlock(backend
->refcache
);
1423 error
= packed_write(backend
);
1429 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
);
1431 static int cmp_old_ref(int *cmp
, git_refdb_backend
*backend
, const char *name
,
1432 const git_oid
*old_id
, const char *old_target
)
1435 git_reference
*old_ref
= NULL
;
1438 /* It "matches" if there is no old value to compare against */
1439 if (!old_id
&& !old_target
)
1442 if ((error
= refdb_fs_backend__lookup(&old_ref
, backend
, name
)) < 0) {
1443 if (error
== GIT_ENOTFOUND
&& old_id
&& git_oid_is_zero(old_id
))
1448 /* If the types don't match, there's no way the values do */
1449 if (old_id
&& old_ref
->type
!= GIT_REFERENCE_DIRECT
) {
1453 if (old_target
&& old_ref
->type
!= GIT_REFERENCE_SYMBOLIC
) {
1458 if (old_id
&& old_ref
->type
== GIT_REFERENCE_DIRECT
)
1459 *cmp
= git_oid_cmp(old_id
, &old_ref
->target
.oid
);
1461 if (old_target
&& old_ref
->type
== GIT_REFERENCE_SYMBOLIC
)
1462 *cmp
= git__strcmp(old_target
, old_ref
->target
.symbolic
);
1465 git_reference_free(old_ref
);
1471 * The git.git comment regarding this, for your viewing pleasure:
1473 * Special hack: If a branch is updated directly and HEAD
1474 * points to it (may happen on the remote side of a push
1475 * for example) then logically the HEAD reflog should be
1477 * A generic solution implies reverse symref information,
1478 * but finding all symrefs pointing to the given branch
1479 * would be rather costly for this rare event (the direct
1480 * update of a branch) to be worth it. So let's cheat and
1481 * check with HEAD only which should cover 99% of all usage
1482 * scenarios (even 100% of the default ones).
1484 static int maybe_append_head(refdb_fs_backend
*backend
, const git_reference
*ref
, const git_signature
*who
, const char *message
)
1486 git_reference
*head
= NULL
;
1487 git_refdb
*refdb
= NULL
;
1488 int error
, write_reflog
;
1491 if ((error
= git_repository_refdb(&refdb
, backend
->repo
)) < 0 ||
1492 (error
= git_refdb_should_write_head_reflog(&write_reflog
, refdb
, ref
)) < 0)
1497 /* if we can't resolve, we use {0}*40 as old id */
1498 if (git_reference_name_to_id(&old_id
, backend
->repo
, ref
->name
) < 0)
1499 memset(&old_id
, 0, sizeof(old_id
));
1501 if ((error
= git_reference_lookup(&head
, backend
->repo
, GIT_HEAD_FILE
)) < 0 ||
1502 (error
= reflog_append(backend
, head
, &old_id
, git_reference_target(ref
), who
, message
)) < 0)
1506 git_reference_free(head
);
1507 git_refdb_free(refdb
);
1511 static int refdb_fs_backend__write(
1512 git_refdb_backend
*_backend
,
1513 const git_reference
*ref
,
1515 const git_signature
*who
,
1516 const char *message
,
1517 const git_oid
*old_id
,
1518 const char *old_target
)
1520 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1521 git_filebuf file
= GIT_FILEBUF_INIT
;
1524 GIT_ASSERT_ARG(backend
);
1526 if ((error
= reference_path_available(backend
, ref
->name
, NULL
, force
)) < 0)
1529 /* We need to perform the reflog append and old value check under the ref's lock */
1530 if ((error
= loose_lock(&file
, backend
, ref
->name
)) < 0)
1533 return refdb_fs_backend__write_tail(_backend
, ref
, &file
, true, old_id
, old_target
, who
, message
);
1536 static int refdb_fs_backend__write_tail(
1537 git_refdb_backend
*_backend
,
1538 const git_reference
*ref
,
1541 const git_oid
*old_id
,
1542 const char *old_target
,
1543 const git_signature
*who
,
1544 const char *message
)
1546 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1547 int error
= 0, cmp
= 0, should_write
;
1548 const char *new_target
= NULL
;
1549 const git_oid
*new_id
= NULL
;
1551 if ((error
= cmp_old_ref(&cmp
, _backend
, ref
->name
, old_id
, old_target
)) < 0)
1555 git_error_set(GIT_ERROR_REFERENCE
, "old reference value does not match");
1556 error
= GIT_EMODIFIED
;
1560 if (ref
->type
== GIT_REFERENCE_SYMBOLIC
)
1561 new_target
= ref
->target
.symbolic
;
1563 new_id
= &ref
->target
.oid
;
1565 error
= cmp_old_ref(&cmp
, _backend
, ref
->name
, new_id
, new_target
);
1566 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1569 /* Don't update if we have the same value */
1570 if (!error
&& !cmp
) {
1572 goto on_error
; /* not really error */
1575 if (update_reflog
) {
1578 if ((error
= git_repository_refdb__weakptr(&refdb
, backend
->repo
)) < 0 ||
1579 (error
= git_refdb_should_write_reflog(&should_write
, refdb
, ref
)) < 0)
1583 if ((error
= reflog_append(backend
, ref
, NULL
, NULL
, who
, message
)) < 0)
1585 if ((error
= maybe_append_head(backend
, ref
, who
, message
)) < 0)
1590 return loose_commit(file
, ref
);
1593 git_filebuf_cleanup(file
);
1597 static int refdb_fs_backend__prune_refs(
1598 refdb_fs_backend
*backend
,
1599 const char *ref_name
,
1602 git_str relative_path
= GIT_STR_INIT
;
1603 git_str base_path
= GIT_STR_INIT
;
1607 GIT_ASSERT_ARG(backend
);
1608 GIT_ASSERT_ARG(ref_name
);
1610 if ((error
= git_str_sets(&relative_path
, ref_name
)) < 0)
1613 git_fs_path_squash_slashes(&relative_path
);
1614 if ((commonlen
= git_fs_path_common_dirlen("refs/heads/", git_str_cstr(&relative_path
))) == strlen("refs/heads/") ||
1615 (commonlen
= git_fs_path_common_dirlen("refs/tags/", git_str_cstr(&relative_path
))) == strlen("refs/tags/") ||
1616 (commonlen
= git_fs_path_common_dirlen("refs/remotes/", git_str_cstr(&relative_path
))) == strlen("refs/remotes/")) {
1618 git_str_truncate(&relative_path
, commonlen
);
1621 error
= git_str_join3(&base_path
, '/',
1622 backend
->commonpath
, prefix
,
1623 git_str_cstr(&relative_path
));
1625 error
= git_str_joinpath(&base_path
,
1626 backend
->commonpath
,
1627 git_str_cstr(&relative_path
));
1630 error
= git_path_validate_str_length(NULL
, &base_path
);
1635 error
= git_futils_rmdir_r(ref_name
+ commonlen
,
1636 git_str_cstr(&base_path
),
1637 GIT_RMDIR_EMPTY_PARENTS
| GIT_RMDIR_SKIP_ROOT
);
1639 if (error
== GIT_ENOTFOUND
)
1644 git_str_dispose(&relative_path
);
1645 git_str_dispose(&base_path
);
1649 static int refdb_fs_backend__delete(
1650 git_refdb_backend
*_backend
,
1651 const char *ref_name
,
1652 const git_oid
*old_id
, const char *old_target
)
1654 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1655 git_filebuf file
= GIT_FILEBUF_INIT
;
1658 GIT_ASSERT_ARG(backend
);
1659 GIT_ASSERT_ARG(ref_name
);
1661 if ((error
= loose_lock(&file
, backend
, ref_name
)) < 0)
1664 if ((error
= refdb_reflog_fs__delete(_backend
, ref_name
)) < 0) {
1665 git_filebuf_cleanup(&file
);
1669 return refdb_fs_backend__delete_tail(_backend
, &file
, ref_name
, old_id
, old_target
);
1672 static int loose_delete(refdb_fs_backend
*backend
, const char *ref_name
)
1674 git_str path
= GIT_STR_INIT
;
1677 if ((error
= loose_path(&path
, backend
->commonpath
, ref_name
)) < 0)
1680 error
= p_unlink(path
.ptr
);
1681 if (error
< 0 && errno
== ENOENT
)
1682 error
= GIT_ENOTFOUND
;
1683 else if (error
!= 0)
1686 git_str_dispose(&path
);
1691 static int refdb_fs_backend__delete_tail(
1692 git_refdb_backend
*_backend
,
1694 const char *ref_name
,
1695 const git_oid
*old_id
, const char *old_target
)
1697 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1698 int error
= 0, cmp
= 0;
1699 bool packed_deleted
= 0;
1701 error
= cmp_old_ref(&cmp
, _backend
, ref_name
, old_id
, old_target
);
1706 git_error_set(GIT_ERROR_REFERENCE
, "old reference value does not match");
1707 error
= GIT_EMODIFIED
;
1712 * To ensure that an external observer will see either the current ref value
1713 * (because the loose ref still exists), or a missing ref (after the packed-file is
1714 * unlocked, there will be nothing left), we must ensure things happen in the
1717 * - the packed-ref file is locked and loaded, as well as a loose one, if it exists
1718 * - we optimistically delete a packed ref, keeping track of whether it existed
1719 * - we delete the loose ref, note that we have its .lock
1720 * - the loose ref is "unlocked", then the packed-ref file is rewritten and unlocked
1721 * - we should prune the path components if a loose ref was deleted
1723 * Note that, because our packed backend doesn't expose its filesystem lock,
1724 * we might not be able to guarantee that this is what actually happens (ie.
1725 * as our current code never write packed-refs.lock, nothing stops observers
1726 * from grabbing a "stale" value from there).
1728 if ((error
= packed_delete(backend
, ref_name
)) < 0 && error
!= GIT_ENOTFOUND
)
1734 if ((error
= loose_delete(backend
, ref_name
)) < 0 && error
!= GIT_ENOTFOUND
)
1737 if (error
== GIT_ENOTFOUND
) {
1738 error
= packed_deleted
? 0 : ref_error_notfound(ref_name
);
1743 git_filebuf_cleanup(file
);
1745 error
= refdb_fs_backend__prune_refs(backend
, ref_name
, "");
1749 static int refdb_reflog_fs__rename(git_refdb_backend
*_backend
, const char *old_name
, const char *new_name
);
1751 static int refdb_fs_backend__rename(
1752 git_reference
**out
,
1753 git_refdb_backend
*_backend
,
1754 const char *old_name
,
1755 const char *new_name
,
1757 const git_signature
*who
,
1758 const char *message
)
1760 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1761 git_reference
*old
, *new = NULL
;
1762 git_filebuf file
= GIT_FILEBUF_INIT
;
1765 GIT_ASSERT_ARG(backend
);
1767 if ((error
= reference_path_available(
1768 backend
, new_name
, old_name
, force
)) < 0 ||
1769 (error
= refdb_fs_backend__lookup(&old
, _backend
, old_name
)) < 0)
1772 if ((error
= refdb_fs_backend__delete(_backend
, old_name
, NULL
, NULL
)) < 0) {
1773 git_reference_free(old
);
1777 new = git_reference__realloc(&old
, new_name
);
1779 git_reference_free(old
);
1783 if ((error
= loose_lock(&file
, backend
, new->name
)) < 0) {
1784 git_reference_free(new);
1788 /* Try to rename the refog; it's ok if the old doesn't exist */
1789 error
= refdb_reflog_fs__rename(_backend
, old_name
, new_name
);
1790 if (((error
== 0) || (error
== GIT_ENOTFOUND
)) &&
1791 ((error
= reflog_append(backend
, new, git_reference_target(new), NULL
, who
, message
)) < 0)) {
1792 git_reference_free(new);
1793 git_filebuf_cleanup(&file
);
1798 git_reference_free(new);
1799 git_filebuf_cleanup(&file
);
1804 if ((error
= loose_commit(&file
, new)) < 0 || out
== NULL
) {
1805 git_reference_free(new);
1813 static int refdb_fs_backend__compress(git_refdb_backend
*_backend
)
1816 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1818 GIT_ASSERT_ARG(backend
);
1820 if ((error
= packed_reload(backend
)) < 0 || /* load the existing packfile */
1821 (error
= packed_loadloose(backend
)) < 0 || /* add all the loose refs */
1822 (error
= packed_write(backend
)) < 0) /* write back to disk */
1828 static void refdb_fs_backend__free(git_refdb_backend
*_backend
)
1830 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1835 git_sortedcache_free(backend
->refcache
);
1837 git_mutex_lock(&backend
->prlock
);
1838 packed_map_free(backend
);
1839 git_mutex_unlock(&backend
->prlock
);
1840 git_mutex_free(&backend
->prlock
);
1842 git__free(backend
->gitpath
);
1843 git__free(backend
->commonpath
);
1847 static char *setup_namespace(git_repository
*repo
, const char *in
)
1849 git_str path
= GIT_STR_INIT
;
1850 char *parts
, *start
, *end
, *out
= NULL
;
1855 git_str_puts(&path
, in
);
1857 /* if the repo is not namespaced, nothing else to do */
1858 if (repo
->namespace == NULL
) {
1859 out
= git_str_detach(&path
);
1863 parts
= end
= git__strdup(repo
->namespace);
1868 * From `man gitnamespaces`:
1869 * namespaces which include a / will expand to a hierarchy
1870 * of namespaces; for example, GIT_NAMESPACE=foo/bar will store
1871 * refs under refs/namespaces/foo/refs/namespaces/bar/
1873 while ((start
= git__strsep(&end
, "/")) != NULL
)
1874 git_str_printf(&path
, "refs/namespaces/%s/", start
);
1876 git_str_printf(&path
, "refs/namespaces/%s/refs", end
);
1879 /* Make sure that the folder with the namespace exists */
1880 if (git_futils_mkdir_relative(git_str_cstr(&path
), in
, 0777,
1881 GIT_MKDIR_PATH
, NULL
) < 0)
1884 /* Return root of the namespaced gitpath, i.e. without the trailing 'refs' */
1885 git_str_rtruncate_at_char(&path
, '/');
1886 git_str_putc(&path
, '/');
1887 out
= git_str_detach(&path
);
1890 git_str_dispose(&path
);
1894 static int reflog_alloc(git_reflog
**reflog
, const char *name
)
1900 log
= git__calloc(1, sizeof(git_reflog
));
1901 GIT_ERROR_CHECK_ALLOC(log
);
1903 log
->ref_name
= git__strdup(name
);
1904 GIT_ERROR_CHECK_ALLOC(log
->ref_name
);
1906 if (git_vector_init(&log
->entries
, 0, NULL
) < 0) {
1907 git__free(log
->ref_name
);
1917 static int reflog_parse(git_reflog
*log
, const char *buf
, size_t buf_size
)
1919 git_parse_ctx parser
= GIT_PARSE_CTX_INIT
;
1921 if ((git_parse_ctx_init(&parser
, buf
, buf_size
)) < 0)
1924 for (; parser
.remain_len
; git_parse_advance_line(&parser
)) {
1925 git_reflog_entry
*entry
;
1929 entry
= git__calloc(1, sizeof(*entry
));
1930 GIT_ERROR_CHECK_ALLOC(entry
);
1931 entry
->committer
= git__calloc(1, sizeof(*entry
->committer
));
1932 GIT_ERROR_CHECK_ALLOC(entry
->committer
);
1934 if (git_parse_advance_oid(&entry
->oid_old
, &parser
) < 0 ||
1935 git_parse_advance_expected(&parser
, " ", 1) < 0 ||
1936 git_parse_advance_oid(&entry
->oid_cur
, &parser
) < 0)
1940 while (git_parse_peek(&c
, &parser
, 0) == 0 && c
!= '\t' && c
!= '\n')
1941 git_parse_advance_chars(&parser
, 1);
1943 if (git_signature__parse(entry
->committer
, &sig
, parser
.line
, NULL
, 0) < 0)
1948 git_parse_advance_chars(&parser
, 1);
1950 len
= parser
.line_len
;
1951 if (parser
.line
[len
- 1] == '\n')
1954 entry
->msg
= git__strndup(parser
.line
, len
);
1955 GIT_ERROR_CHECK_ALLOC(entry
->msg
);
1958 if ((git_vector_insert(&log
->entries
, entry
)) < 0) {
1959 git_reflog_entry__free(entry
);
1966 git_reflog_entry__free(entry
);
1972 static int create_new_reflog_file(const char *filepath
)
1976 if ((error
= git_futils_mkpath2file(filepath
, GIT_REFLOG_DIR_MODE
)) < 0)
1979 if ((fd
= p_open(filepath
,
1981 GIT_REFLOG_FILE_MODE
)) < 0)
1987 static int refdb_reflog_fs__ensure_log(git_refdb_backend
*_backend
, const char *name
)
1989 refdb_fs_backend
*backend
;
1990 git_repository
*repo
;
1991 git_str path
= GIT_STR_INIT
;
1994 GIT_ASSERT_ARG(_backend
&& name
);
1996 backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
1997 repo
= backend
->repo
;
1999 if ((error
= reflog_path(&path
, repo
, name
)) < 0)
2002 error
= create_new_reflog_file(git_str_cstr(&path
));
2003 git_str_dispose(&path
);
2008 static int has_reflog(git_repository
*repo
, const char *name
)
2011 git_str path
= GIT_STR_INIT
;
2013 if (reflog_path(&path
, repo
, name
) < 0)
2016 ret
= git_fs_path_isfile(git_str_cstr(&path
));
2019 git_str_dispose(&path
);
2023 static int refdb_reflog_fs__has_log(git_refdb_backend
*_backend
, const char *name
)
2025 refdb_fs_backend
*backend
;
2027 GIT_ASSERT_ARG(_backend
);
2028 GIT_ASSERT_ARG(name
);
2030 backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
2032 return has_reflog(backend
->repo
, name
);
2035 static int refdb_reflog_fs__read(git_reflog
**out
, git_refdb_backend
*_backend
, const char *name
)
2038 git_str log_path
= GIT_STR_INIT
;
2039 git_str log_file
= GIT_STR_INIT
;
2040 git_reflog
*log
= NULL
;
2041 git_repository
*repo
;
2042 refdb_fs_backend
*backend
;
2044 GIT_ASSERT_ARG(out
);
2045 GIT_ASSERT_ARG(_backend
);
2046 GIT_ASSERT_ARG(name
);
2048 backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
2049 repo
= backend
->repo
;
2051 if (reflog_alloc(&log
, name
) < 0)
2054 if (reflog_path(&log_path
, repo
, name
) < 0)
2057 error
= git_futils_readbuffer(&log_file
, git_str_cstr(&log_path
));
2058 if (error
< 0 && error
!= GIT_ENOTFOUND
)
2061 if ((error
== GIT_ENOTFOUND
) &&
2062 ((error
= create_new_reflog_file(git_str_cstr(&log_path
))) < 0))
2065 if ((error
= reflog_parse(log
,
2066 git_str_cstr(&log_file
), git_str_len(&log_file
))) < 0)
2073 git_reflog_free(log
);
2076 git_str_dispose(&log_file
);
2077 git_str_dispose(&log_path
);
2082 static int serialize_reflog_entry(
2084 const git_oid
*oid_old
,
2085 const git_oid
*oid_new
,
2086 const git_signature
*committer
,
2089 char raw_old
[GIT_OID_HEXSZ
+1];
2090 char raw_new
[GIT_OID_HEXSZ
+1];
2092 git_oid_tostr(raw_old
, GIT_OID_HEXSZ
+1, oid_old
);
2093 git_oid_tostr(raw_new
, GIT_OID_HEXSZ
+1, oid_new
);
2097 git_str_puts(buf
, raw_old
);
2098 git_str_putc(buf
, ' ');
2099 git_str_puts(buf
, raw_new
);
2101 git_signature__writebuf(buf
, " ", committer
);
2103 /* drop trailing LF */
2109 git_str_putc(buf
, '\t');
2110 git_str_puts(buf
, msg
);
2112 for (i
= 0; i
< buf
->size
- 2; i
++)
2113 if (buf
->ptr
[i
] == '\n')
2118 git_str_putc(buf
, '\n');
2120 return git_str_oom(buf
);
2123 static int lock_reflog(git_filebuf
*file
, refdb_fs_backend
*backend
, const char *refname
)
2125 git_repository
*repo
;
2126 git_str log_path
= GIT_STR_INIT
;
2129 repo
= backend
->repo
;
2131 if (!git_path_is_valid(backend
->repo
, refname
, 0, GIT_FS_PATH_REJECT_FILESYSTEM_DEFAULTS
)) {
2132 git_error_set(GIT_ERROR_INVALID
, "invalid reference name '%s'", refname
);
2133 return GIT_EINVALIDSPEC
;
2136 if (reflog_path(&log_path
, repo
, refname
) < 0)
2139 if (!git_fs_path_isfile(git_str_cstr(&log_path
))) {
2140 git_error_set(GIT_ERROR_INVALID
,
2141 "log file for reference '%s' doesn't exist", refname
);
2146 error
= git_filebuf_open(file
, git_str_cstr(&log_path
), 0, GIT_REFLOG_FILE_MODE
);
2149 git_str_dispose(&log_path
);
2154 static int refdb_reflog_fs__write(git_refdb_backend
*_backend
, git_reflog
*reflog
)
2158 git_reflog_entry
*entry
;
2159 refdb_fs_backend
*backend
;
2160 git_str log
= GIT_STR_INIT
;
2161 git_filebuf fbuf
= GIT_FILEBUF_INIT
;
2163 GIT_ASSERT_ARG(_backend
);
2164 GIT_ASSERT_ARG(reflog
);
2166 backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
2168 if ((error
= lock_reflog(&fbuf
, backend
, reflog
->ref_name
)) < 0)
2171 git_vector_foreach(&reflog
->entries
, i
, entry
) {
2172 if (serialize_reflog_entry(&log
, &(entry
->oid_old
), &(entry
->oid_cur
), entry
->committer
, entry
->msg
) < 0)
2175 if ((error
= git_filebuf_write(&fbuf
, log
.ptr
, log
.size
)) < 0)
2179 error
= git_filebuf_commit(&fbuf
);
2183 git_filebuf_cleanup(&fbuf
);
2186 git_str_dispose(&log
);
2191 /* Append to the reflog, must be called under reference lock */
2192 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
)
2194 int error
, is_symbolic
, open_flags
;
2195 git_oid old_id
= {{0}}, new_id
= {{0}};
2196 git_str buf
= GIT_STR_INIT
, path
= GIT_STR_INIT
;
2197 git_repository
*repo
= backend
->repo
;
2199 is_symbolic
= ref
->type
== GIT_REFERENCE_SYMBOLIC
;
2201 /* "normal" symbolic updates do not write */
2203 strcmp(ref
->name
, GIT_HEAD_FILE
) &&
2207 /* From here on is_symbolic also means that it's HEAD */
2210 git_oid_cpy(&old_id
, old
);
2212 error
= git_reference_name_to_id(&old_id
, repo
, ref
->name
);
2213 if (error
< 0 && error
!= GIT_ENOTFOUND
)
2218 git_oid_cpy(&new_id
, new);
2221 git_oid_cpy(&new_id
, git_reference_target(ref
));
2223 error
= git_reference_name_to_id(&new_id
, repo
, git_reference_symbolic_target(ref
));
2224 if (error
< 0 && error
!= GIT_ENOTFOUND
)
2226 /* detaching HEAD does not create an entry */
2227 if (error
== GIT_ENOTFOUND
)
2234 if ((error
= serialize_reflog_entry(&buf
, &old_id
, &new_id
, who
, message
)) < 0)
2237 if ((error
= reflog_path(&path
, repo
, ref
->name
)) < 0)
2240 if (((error
= git_futils_mkpath2file(git_str_cstr(&path
), 0777)) < 0) &&
2241 (error
!= GIT_EEXISTS
)) {
2245 /* If the new branch matches part of the namespace of a previously deleted branch,
2246 * there maybe an obsolete/unused directory (or directory hierarchy) in the way.
2248 if (git_fs_path_isdir(git_str_cstr(&path
))) {
2249 if ((error
= git_futils_rmdir_r(git_str_cstr(&path
), NULL
, GIT_RMDIR_SKIP_NONEMPTY
)) < 0) {
2250 if (error
== GIT_ENOTFOUND
)
2252 } else if (git_fs_path_isdir(git_str_cstr(&path
))) {
2253 git_error_set(GIT_ERROR_REFERENCE
, "cannot create reflog at '%s', there are reflogs beneath that folder",
2255 error
= GIT_EDIRECTORY
;
2262 open_flags
= O_WRONLY
| O_CREAT
| O_APPEND
;
2265 open_flags
|= O_FSYNC
;
2267 error
= git_futils_writebuffer(&buf
, git_str_cstr(&path
), open_flags
, GIT_REFLOG_FILE_MODE
);
2270 git_str_dispose(&buf
);
2271 git_str_dispose(&path
);
2276 static int refdb_reflog_fs__rename(git_refdb_backend
*_backend
, const char *old_name
, const char *new_name
)
2279 git_str old_path
= GIT_STR_INIT
;
2280 git_str new_path
= GIT_STR_INIT
;
2281 git_str temp_path
= GIT_STR_INIT
;
2282 git_str normalized
= GIT_STR_INIT
;
2283 git_repository
*repo
;
2284 refdb_fs_backend
*backend
;
2286 GIT_ASSERT_ARG(_backend
);
2287 GIT_ASSERT_ARG(old_name
);
2288 GIT_ASSERT_ARG(new_name
);
2290 backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
2291 repo
= backend
->repo
;
2293 if ((error
= git_reference__normalize_name(
2294 &normalized
, new_name
, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL
)) < 0)
2297 if (git_str_joinpath(&temp_path
, repo
->gitdir
, GIT_REFLOG_DIR
) < 0)
2300 if ((error
= loose_path(&old_path
, git_str_cstr(&temp_path
), old_name
)) < 0)
2303 if ((error
= loose_path(&new_path
, git_str_cstr(&temp_path
), git_str_cstr(&normalized
))) < 0)
2306 if (!git_fs_path_exists(git_str_cstr(&old_path
))) {
2307 error
= GIT_ENOTFOUND
;
2312 * Move the reflog to a temporary place. This two-phase renaming is required
2313 * in order to cope with funny renaming use cases when one tries to move a reference
2314 * to a partially colliding namespace:
2316 * - a/b/c/d -> a/b/c
2318 if ((error
= loose_path(&temp_path
, git_str_cstr(&temp_path
), "temp_reflog")) < 0)
2321 if ((fd
= git_futils_mktmp(&temp_path
, git_str_cstr(&temp_path
), GIT_REFLOG_FILE_MODE
)) < 0) {
2328 if (p_rename(git_str_cstr(&old_path
), git_str_cstr(&temp_path
)) < 0) {
2329 git_error_set(GIT_ERROR_OS
, "failed to rename reflog for %s", new_name
);
2334 if (git_fs_path_isdir(git_str_cstr(&new_path
)) &&
2335 (git_futils_rmdir_r(git_str_cstr(&new_path
), NULL
, GIT_RMDIR_SKIP_NONEMPTY
) < 0)) {
2340 if (git_futils_mkpath2file(git_str_cstr(&new_path
), GIT_REFLOG_DIR_MODE
) < 0) {
2345 if (p_rename(git_str_cstr(&temp_path
), git_str_cstr(&new_path
)) < 0) {
2346 git_error_set(GIT_ERROR_OS
, "failed to rename reflog for %s", new_name
);
2351 git_str_dispose(&temp_path
);
2352 git_str_dispose(&old_path
);
2353 git_str_dispose(&new_path
);
2354 git_str_dispose(&normalized
);
2359 static int refdb_reflog_fs__delete(git_refdb_backend
*_backend
, const char *name
)
2361 refdb_fs_backend
*backend
= GIT_CONTAINER_OF(_backend
, refdb_fs_backend
, parent
);
2362 git_str path
= GIT_STR_INIT
;
2365 GIT_ASSERT_ARG(_backend
);
2366 GIT_ASSERT_ARG(name
);
2368 if ((error
= reflog_path(&path
, backend
->repo
, name
)) < 0)
2371 if (!git_fs_path_exists(path
.ptr
))
2374 if ((error
= p_unlink(path
.ptr
)) < 0)
2377 error
= refdb_fs_backend__prune_refs(backend
, name
, GIT_REFLOG_DIR
);
2380 git_str_dispose(&path
);
2385 int git_refdb_backend_fs(
2386 git_refdb_backend
**backend_out
,
2387 git_repository
*repository
)
2390 git_str gitpath
= GIT_STR_INIT
;
2391 refdb_fs_backend
*backend
;
2393 backend
= git__calloc(1, sizeof(refdb_fs_backend
));
2394 GIT_ERROR_CHECK_ALLOC(backend
);
2395 if (git_mutex_init(&backend
->prlock
) < 0) {
2401 if (git_refdb_init_backend(&backend
->parent
, GIT_REFDB_BACKEND_VERSION
) < 0)
2404 backend
->repo
= repository
;
2406 if (repository
->gitdir
) {
2407 backend
->gitpath
= setup_namespace(repository
, repository
->gitdir
);
2409 if (backend
->gitpath
== NULL
)
2413 if (repository
->commondir
) {
2414 backend
->commonpath
= setup_namespace(repository
, repository
->commondir
);
2416 if (backend
->commonpath
== NULL
)
2420 if (git_str_joinpath(&gitpath
, backend
->commonpath
, GIT_PACKEDREFS_FILE
) < 0 ||
2421 git_sortedcache_new(
2422 &backend
->refcache
, offsetof(struct packref
, name
),
2423 NULL
, NULL
, packref_cmp
, git_str_cstr(&gitpath
)) < 0)
2426 git_str_dispose(&gitpath
);
2428 if (!git_repository__configmap_lookup(&t
, backend
->repo
, GIT_CONFIGMAP_IGNORECASE
) && t
) {
2429 backend
->iterator_flags
|= GIT_ITERATOR_IGNORE_CASE
;
2430 backend
->direach_flags
|= GIT_FS_PATH_DIR_IGNORE_CASE
;
2432 if (!git_repository__configmap_lookup(&t
, backend
->repo
, GIT_CONFIGMAP_PRECOMPOSE
) && t
) {
2433 backend
->iterator_flags
|= GIT_ITERATOR_PRECOMPOSE_UNICODE
;
2434 backend
->direach_flags
|= GIT_FS_PATH_DIR_PRECOMPOSE_UNICODE
;
2436 if ((!git_repository__configmap_lookup(&t
, backend
->repo
, GIT_CONFIGMAP_FSYNCOBJECTFILES
) && t
) ||
2437 git_repository__fsync_gitdir
)
2439 backend
->iterator_flags
|= GIT_ITERATOR_DESCEND_SYMLINKS
;
2441 backend
->parent
.exists
= &refdb_fs_backend__exists
;
2442 backend
->parent
.lookup
= &refdb_fs_backend__lookup
;
2443 backend
->parent
.iterator
= &refdb_fs_backend__iterator
;
2444 backend
->parent
.write
= &refdb_fs_backend__write
;
2445 backend
->parent
.del
= &refdb_fs_backend__delete
;
2446 backend
->parent
.rename
= &refdb_fs_backend__rename
;
2447 backend
->parent
.compress
= &refdb_fs_backend__compress
;
2448 backend
->parent
.lock
= &refdb_fs_backend__lock
;
2449 backend
->parent
.unlock
= &refdb_fs_backend__unlock
;
2450 backend
->parent
.has_log
= &refdb_reflog_fs__has_log
;
2451 backend
->parent
.ensure_log
= &refdb_reflog_fs__ensure_log
;
2452 backend
->parent
.free
= &refdb_fs_backend__free
;
2453 backend
->parent
.reflog_read
= &refdb_reflog_fs__read
;
2454 backend
->parent
.reflog_write
= &refdb_reflog_fs__write
;
2455 backend
->parent
.reflog_rename
= &refdb_reflog_fs__rename
;
2456 backend
->parent
.reflog_delete
= &refdb_reflog_fs__delete
;
2458 *backend_out
= (git_refdb_backend
*)backend
;
2462 git_mutex_free(&backend
->prlock
);
2463 git_str_dispose(&gitpath
);
2464 git__free(backend
->gitpath
);
2465 git__free(backend
->commonpath
);