2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
12 #include "repository.h"
19 #include "sortedcache.h"
20 #include "signature.h"
23 #include <git2/object.h>
24 #include <git2/refdb.h>
25 #include <git2/branch.h>
26 #include <git2/sys/refdb_backend.h>
27 #include <git2/sys/refs.h>
28 #include <git2/sys/reflog.h>
30 #define DEFAULT_NESTING_LEVEL 5
31 #define MAX_NESTING_LEVEL 10
35 PACKREF_WAS_LOOSE
= 2,
36 PACKREF_CANNOT_PEEL
= 4,
50 char name
[GIT_FLEX_ARRAY
];
53 typedef struct refdb_fs_backend
{
54 git_refdb_backend parent
;
57 /* path to git directory */
59 /* path to common objects' directory */
62 git_sortedcache
*refcache
;
64 git_iterator_flag_t iterator_flags
;
65 uint32_t direach_flags
;
69 static int refdb_reflog_fs__delete(git_refdb_backend
*_backend
, const char *name
);
71 static int packref_cmp(const void *a_
, const void *b_
)
73 const struct packref
*a
= a_
, *b
= b_
;
74 return strcmp(a
->name
, b
->name
);
77 static int packed_reload(refdb_fs_backend
*backend
)
80 git_buf packedrefs
= GIT_BUF_INIT
;
81 char *scan
, *eof
, *eol
;
83 if (!backend
->gitpath
)
86 error
= git_sortedcache_lockandload(backend
->refcache
, &packedrefs
);
89 * If we can't find the packed-refs, clear table and return.
90 * Any other error just gets passed through.
91 * If no error, and file wasn't changed, just return.
92 * Anything else means we need to refresh the packed refs.
95 if (error
== GIT_ENOTFOUND
) {
96 git_sortedcache_clear(backend
->refcache
, true);
103 /* At this point, refresh the packed refs from the loaded buffer. */
105 git_sortedcache_clear(backend
->refcache
, false);
107 scan
= (char *)packedrefs
.ptr
;
108 eof
= scan
+ packedrefs
.size
;
110 backend
->peeling_mode
= PEELING_NONE
;
113 static const char *traits_header
= "# pack-refs with: ";
115 if (git__prefixcmp(scan
, traits_header
) == 0) {
116 scan
+= strlen(traits_header
);
117 eol
= strchr(scan
, '\n');
123 if (strstr(scan
, " fully-peeled ") != NULL
) {
124 backend
->peeling_mode
= PEELING_FULL
;
125 } else if (strstr(scan
, " peeled ") != NULL
) {
126 backend
->peeling_mode
= PEELING_STANDARD
;
133 while (scan
< eof
&& *scan
== '#') {
134 if (!(eol
= strchr(scan
, '\n')))
143 /* parse "<OID> <refname>\n" */
145 if (git_oid_fromstr(&oid
, scan
) < 0)
147 scan
+= GIT_OID_HEXSZ
;
151 if (!(eol
= strchr(scan
, '\n')))
157 if (git_sortedcache_upsert((void **)&ref
, backend
->refcache
, scan
) < 0)
161 git_oid_cpy(&ref
->oid
, &oid
);
163 /* look for optional "^<OID>\n" */
166 if (git_oid_fromstr(&oid
, scan
+ 1) < 0)
168 scan
+= GIT_OID_HEXSZ
+ 1;
171 if (!(eol
= strchr(scan
, '\n')))
176 git_oid_cpy(&ref
->peel
, &oid
);
177 ref
->flags
|= PACKREF_HAS_PEEL
;
179 else if (backend
->peeling_mode
== PEELING_FULL
||
180 (backend
->peeling_mode
== PEELING_STANDARD
&&
181 git__prefixcmp(ref
->name
, GIT_REFS_TAGS_DIR
) == 0))
182 ref
->flags
|= PACKREF_CANNOT_PEEL
;
185 git_sortedcache_wunlock(backend
->refcache
);
186 git_buf_free(&packedrefs
);
191 giterr_set(GITERR_REFERENCE
, "corrupted packed references file");
193 git_sortedcache_clear(backend
->refcache
, false);
194 git_sortedcache_wunlock(backend
->refcache
);
195 git_buf_free(&packedrefs
);
200 static int loose_parse_oid(
201 git_oid
*oid
, const char *filename
, git_buf
*file_content
)
203 const char *str
= git_buf_cstr(file_content
);
205 if (git_buf_len(file_content
) < GIT_OID_HEXSZ
)
208 /* we need to get 40 OID characters from the file */
209 if (git_oid_fromstr(oid
, str
) < 0)
212 /* If the file is longer than 40 chars, the 41st must be a space */
213 str
+= GIT_OID_HEXSZ
;
214 if (*str
== '\0' || git__isspace(*str
))
218 giterr_set(GITERR_REFERENCE
, "corrupted loose reference file: %s", filename
);
222 static int loose_readbuffer(git_buf
*buf
, const char *base
, const char *path
)
226 /* build full path to file */
227 if ((error
= git_buf_joinpath(buf
, base
, path
)) < 0 ||
228 (error
= git_futils_readbuffer(buf
, buf
->ptr
)) < 0)
234 static int loose_lookup_to_packfile(refdb_fs_backend
*backend
, const char *name
)
237 git_buf ref_file
= GIT_BUF_INIT
;
238 struct packref
*ref
= NULL
;
241 /* if we fail to load the loose reference, assume someone changed
242 * the filesystem under us and skip it...
244 if (loose_readbuffer(&ref_file
, backend
->gitpath
, name
) < 0) {
249 /* skip symbolic refs */
250 if (!git__prefixcmp(git_buf_cstr(&ref_file
), GIT_SYMREF
))
253 /* parse OID from file */
254 if ((error
= loose_parse_oid(&oid
, name
, &ref_file
)) < 0)
257 git_sortedcache_wlock(backend
->refcache
);
259 if (!(error
= git_sortedcache_upsert(
260 (void **)&ref
, backend
->refcache
, name
))) {
262 git_oid_cpy(&ref
->oid
, &oid
);
263 ref
->flags
= PACKREF_WAS_LOOSE
;
266 git_sortedcache_wunlock(backend
->refcache
);
269 git_buf_free(&ref_file
);
273 static int _dirent_loose_load(void *payload
, git_buf
*full_path
)
275 refdb_fs_backend
*backend
= payload
;
276 const char *file_path
;
278 if (git__suffixcmp(full_path
->ptr
, ".lock") == 0)
281 if (git_path_isdir(full_path
->ptr
)) {
282 int error
= git_path_direach(
283 full_path
, backend
->direach_flags
, _dirent_loose_load
, backend
);
284 /* Race with the filesystem, ignore it */
285 if (error
== GIT_ENOTFOUND
) {
293 file_path
= full_path
->ptr
+ strlen(backend
->gitpath
);
295 return loose_lookup_to_packfile(backend
, file_path
);
299 * Load all the loose references from the repository
300 * into the in-memory Packfile, and build a vector with
301 * all the references so it can be written back to
304 static int packed_loadloose(refdb_fs_backend
*backend
)
307 git_buf refs_path
= GIT_BUF_INIT
;
309 if (git_buf_joinpath(&refs_path
, backend
->gitpath
, GIT_REFS_DIR
) < 0)
313 * Load all the loose files from disk into the Packfile table.
314 * This will overwrite any old packed entries with their
315 * updated loose versions
317 error
= git_path_direach(
318 &refs_path
, backend
->direach_flags
, _dirent_loose_load
, backend
);
320 git_buf_free(&refs_path
);
325 static int refdb_fs_backend__exists(
327 git_refdb_backend
*_backend
,
328 const char *ref_name
)
330 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
331 git_buf ref_path
= GIT_BUF_INIT
;
336 if ((error
= packed_reload(backend
)) < 0 ||
337 (error
= git_buf_joinpath(&ref_path
, backend
->gitpath
, ref_name
)) < 0)
340 *exists
= git_path_isfile(ref_path
.ptr
) ||
341 (git_sortedcache_lookup(backend
->refcache
, ref_name
) != NULL
);
343 git_buf_free(&ref_path
);
347 static const char *loose_parse_symbolic(git_buf
*file_content
)
349 const unsigned int header_len
= (unsigned int)strlen(GIT_SYMREF
);
350 const char *refname_start
;
352 refname_start
= (const char *)file_content
->ptr
;
354 if (git_buf_len(file_content
) < header_len
+ 1) {
355 giterr_set(GITERR_REFERENCE
, "corrupted loose reference file");
360 * Assume we have already checked for the header
361 * before calling this function
363 refname_start
+= header_len
;
365 return refname_start
;
369 * Returns whether a reference is stored per worktree or not.
370 * Per-worktree references are:
372 * - all pseudorefs, e.g. HEAD and MERGE_HEAD
373 * - all references stored inside of "refs/bisect/"
375 static bool is_per_worktree_ref(const char *ref_name
)
377 return git__prefixcmp(ref_name
, "refs/") != 0 ||
378 git__prefixcmp(ref_name
, "refs/bisect/") == 0;
381 static int loose_lookup(
383 refdb_fs_backend
*backend
,
384 const char *ref_name
)
386 git_buf ref_file
= GIT_BUF_INIT
;
393 if (is_per_worktree_ref(ref_name
))
394 ref_dir
= backend
->gitpath
;
396 ref_dir
= backend
->commonpath
;
398 if ((error
= loose_readbuffer(&ref_file
, ref_dir
, ref_name
)) < 0)
399 /* cannot read loose ref file - gah */;
400 else if (git__prefixcmp(git_buf_cstr(&ref_file
), GIT_SYMREF
) == 0) {
403 git_buf_rtrim(&ref_file
);
405 if (!(target
= loose_parse_symbolic(&ref_file
)))
407 else if (out
!= NULL
)
408 *out
= git_reference__alloc_symbolic(ref_name
, target
);
412 if (!(error
= loose_parse_oid(&oid
, ref_name
, &ref_file
)) &&
414 *out
= git_reference__alloc(ref_name
, &oid
, NULL
);
417 git_buf_free(&ref_file
);
421 static int ref_error_notfound(const char *name
)
423 giterr_set(GITERR_REFERENCE
, "reference '%s' not found", name
);
424 return GIT_ENOTFOUND
;
427 static int packed_lookup(
429 refdb_fs_backend
*backend
,
430 const char *ref_name
)
433 struct packref
*entry
;
435 if ((error
= packed_reload(backend
)) < 0)
438 if (git_sortedcache_rlock(backend
->refcache
) < 0)
441 entry
= git_sortedcache_lookup(backend
->refcache
, ref_name
);
443 error
= ref_error_notfound(ref_name
);
445 *out
= git_reference__alloc(ref_name
, &entry
->oid
, &entry
->peel
);
450 git_sortedcache_runlock(backend
->refcache
);
455 static int refdb_fs_backend__lookup(
457 git_refdb_backend
*_backend
,
458 const char *ref_name
)
460 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
465 if (!(error
= loose_lookup(out
, backend
, ref_name
)))
468 /* only try to lookup this reference on the packfile if it
469 * wasn't found on the loose refs; not if there was a critical error */
470 if (error
== GIT_ENOTFOUND
) {
472 error
= packed_lookup(out
, backend
, ref_name
);
479 git_reference_iterator parent
;
486 git_sortedcache
*cache
;
491 static void refdb_fs_backend__iterator_free(git_reference_iterator
*_iter
)
493 refdb_fs_iter
*iter
= (refdb_fs_iter
*) _iter
;
495 git_vector_free(&iter
->loose
);
496 git_pool_clear(&iter
->pool
);
497 git_sortedcache_free(iter
->cache
);
501 static int iter_load_loose_paths(refdb_fs_backend
*backend
, refdb_fs_iter
*iter
)
504 git_buf path
= GIT_BUF_INIT
;
505 git_iterator
*fsit
= NULL
;
506 git_iterator_options fsit_opts
= GIT_ITERATOR_OPTIONS_INIT
;
507 const git_index_entry
*entry
= NULL
;
509 if (!backend
->commonpath
) /* do nothing if no commonpath for loose refs */
512 fsit_opts
.flags
= backend
->iterator_flags
;
514 if ((error
= git_buf_printf(&path
, "%s/refs", backend
->commonpath
)) < 0 ||
515 (error
= git_iterator_for_filesystem(&fsit
, path
.ptr
, &fsit_opts
)) < 0) {
520 error
= git_buf_sets(&path
, GIT_REFS_DIR
);
522 while (!error
&& !git_iterator_advance(&entry
, fsit
)) {
523 const char *ref_name
;
527 git_buf_truncate(&path
, strlen(GIT_REFS_DIR
));
528 git_buf_puts(&path
, entry
->path
);
529 ref_name
= git_buf_cstr(&path
);
531 if (git__suffixcmp(ref_name
, ".lock") == 0 ||
532 (iter
->glob
&& p_fnmatch(iter
->glob
, ref_name
, 0) != 0))
535 git_sortedcache_rlock(backend
->refcache
);
536 ref
= git_sortedcache_lookup(backend
->refcache
, ref_name
);
538 ref
->flags
|= PACKREF_SHADOWED
;
539 git_sortedcache_runlock(backend
->refcache
);
541 ref_dup
= git_pool_strdup(&iter
->pool
, ref_name
);
545 error
= git_vector_insert(&iter
->loose
, ref_dup
);
548 git_iterator_free(fsit
);
554 static int refdb_fs_backend__iterator_next(
555 git_reference
**out
, git_reference_iterator
*_iter
)
557 int error
= GIT_ITEROVER
;
558 refdb_fs_iter
*iter
= (refdb_fs_iter
*)_iter
;
559 refdb_fs_backend
*backend
= (refdb_fs_backend
*)iter
->parent
.db
->backend
;
562 while (iter
->loose_pos
< iter
->loose
.length
) {
563 const char *path
= git_vector_get(&iter
->loose
, iter
->loose_pos
++);
565 if (loose_lookup(out
, backend
, path
) == 0)
572 if ((error
= git_sortedcache_copy(&iter
->cache
, backend
->refcache
, 1, NULL
, NULL
)) < 0)
576 error
= GIT_ITEROVER
;
577 while (iter
->packed_pos
< git_sortedcache_entrycount(iter
->cache
)) {
578 ref
= git_sortedcache_entry(iter
->cache
, iter
->packed_pos
++);
579 if (!ref
) /* stop now if another thread deleted refs and we past end */
582 if (ref
->flags
& PACKREF_SHADOWED
)
584 if (iter
->glob
&& p_fnmatch(iter
->glob
, ref
->name
, 0) != 0)
587 *out
= git_reference__alloc(ref
->name
, &ref
->oid
, &ref
->peel
);
588 error
= (*out
!= NULL
) ? 0 : -1;
595 static int refdb_fs_backend__iterator_next_name(
596 const char **out
, git_reference_iterator
*_iter
)
598 int error
= GIT_ITEROVER
;
599 refdb_fs_iter
*iter
= (refdb_fs_iter
*)_iter
;
600 refdb_fs_backend
*backend
= (refdb_fs_backend
*)iter
->parent
.db
->backend
;
603 while (iter
->loose_pos
< iter
->loose
.length
) {
604 const char *path
= git_vector_get(&iter
->loose
, iter
->loose_pos
++);
606 if (loose_lookup(NULL
, backend
, path
) == 0) {
615 if ((error
= git_sortedcache_copy(&iter
->cache
, backend
->refcache
, 1, NULL
, NULL
)) < 0)
619 error
= GIT_ITEROVER
;
620 while (iter
->packed_pos
< git_sortedcache_entrycount(iter
->cache
)) {
621 ref
= git_sortedcache_entry(iter
->cache
, iter
->packed_pos
++);
622 if (!ref
) /* stop now if another thread deleted refs and we past end */
625 if (ref
->flags
& PACKREF_SHADOWED
)
627 if (iter
->glob
&& p_fnmatch(iter
->glob
, ref
->name
, 0) != 0)
638 static int refdb_fs_backend__iterator(
639 git_reference_iterator
**out
, git_refdb_backend
*_backend
, const char *glob
)
643 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
647 if ((error
= packed_reload(backend
)) < 0)
650 iter
= git__calloc(1, sizeof(refdb_fs_iter
));
651 GITERR_CHECK_ALLOC(iter
);
653 git_pool_init(&iter
->pool
, 1);
655 if (git_vector_init(&iter
->loose
, 8, NULL
) < 0)
659 (iter
->glob
= git_pool_strdup(&iter
->pool
, glob
)) == NULL
)
662 iter
->parent
.next
= refdb_fs_backend__iterator_next
;
663 iter
->parent
.next_name
= refdb_fs_backend__iterator_next_name
;
664 iter
->parent
.free
= refdb_fs_backend__iterator_free
;
666 if (iter_load_loose_paths(backend
, iter
) < 0)
669 *out
= (git_reference_iterator
*)iter
;
673 refdb_fs_backend__iterator_free((git_reference_iterator
*)iter
);
677 static bool ref_is_available(
678 const char *old_ref
, const char *new_ref
, const char *this_ref
)
680 if (old_ref
== NULL
|| strcmp(old_ref
, this_ref
)) {
681 size_t reflen
= strlen(this_ref
);
682 size_t newlen
= strlen(new_ref
);
683 size_t cmplen
= reflen
< newlen
? reflen
: newlen
;
684 const char *lead
= reflen
< newlen
? new_ref
: this_ref
;
686 if (!strncmp(new_ref
, this_ref
, cmplen
) && lead
[cmplen
] == '/') {
694 static int reference_path_available(
695 refdb_fs_backend
*backend
,
703 if ((error
= packed_reload(backend
)) < 0)
709 if ((error
= refdb_fs_backend__exists(
710 &exists
, (git_refdb_backend
*)backend
, new_ref
)) < 0) {
715 giterr_set(GITERR_REFERENCE
,
716 "failed to write reference '%s': a reference with "
717 "that name already exists.", new_ref
);
722 git_sortedcache_rlock(backend
->refcache
);
724 for (i
= 0; i
< git_sortedcache_entrycount(backend
->refcache
); ++i
) {
725 struct packref
*ref
= git_sortedcache_entry(backend
->refcache
, i
);
727 if (ref
&& !ref_is_available(old_ref
, new_ref
, ref
->name
)) {
728 git_sortedcache_runlock(backend
->refcache
);
729 giterr_set(GITERR_REFERENCE
,
730 "path to reference '%s' collides with existing one", new_ref
);
735 git_sortedcache_runlock(backend
->refcache
);
739 static int loose_lock(git_filebuf
*file
, refdb_fs_backend
*backend
, const char *name
)
741 int error
, filebuf_flags
;
742 git_buf ref_path
= GIT_BUF_INIT
;
745 assert(file
&& backend
&& name
);
747 if (!git_path_isvalid(backend
->repo
, name
, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS
)) {
748 giterr_set(GITERR_INVALID
, "invalid reference name '%s'", name
);
749 return GIT_EINVALIDSPEC
;
752 if (is_per_worktree_ref(name
))
753 basedir
= backend
->gitpath
;
755 basedir
= backend
->commonpath
;
757 /* Remove a possibly existing empty directory hierarchy
758 * which name would collide with the reference name
760 if ((error
= git_futils_rmdir_r(name
, basedir
, GIT_RMDIR_SKIP_NONEMPTY
)) < 0)
763 if (git_buf_joinpath(&ref_path
, basedir
, name
) < 0)
766 filebuf_flags
= GIT_FILEBUF_FORCE
;
768 filebuf_flags
|= GIT_FILEBUF_FSYNC
;
770 error
= git_filebuf_open(file
, ref_path
.ptr
, filebuf_flags
, GIT_REFS_FILE_MODE
);
772 if (error
== GIT_EDIRECTORY
)
773 giterr_set(GITERR_REFERENCE
, "cannot lock ref '%s', there are refs beneath that folder", name
);
775 git_buf_free(&ref_path
);
779 static int loose_commit(git_filebuf
*file
, const git_reference
*ref
)
783 if (ref
->type
== GIT_REF_OID
) {
784 char oid
[GIT_OID_HEXSZ
+ 1];
785 git_oid_nfmt(oid
, sizeof(oid
), &ref
->target
.oid
);
787 git_filebuf_printf(file
, "%s\n", oid
);
788 } else if (ref
->type
== GIT_REF_SYMBOLIC
) {
789 git_filebuf_printf(file
, GIT_SYMREF
"%s\n", ref
->target
.symbolic
);
791 assert(0); /* don't let this happen */
794 return git_filebuf_commit(file
);
797 static int refdb_fs_backend__lock(void **out
, git_refdb_backend
*_backend
, const char *refname
)
801 refdb_fs_backend
*backend
= (refdb_fs_backend
*) _backend
;
803 lock
= git__calloc(1, sizeof(git_filebuf
));
804 GITERR_CHECK_ALLOC(lock
);
806 if ((error
= loose_lock(lock
, backend
, refname
)) < 0) {
815 static int refdb_fs_backend__write_tail(
816 git_refdb_backend
*_backend
,
817 const git_reference
*ref
,
820 const git_signature
*who
,
822 const git_oid
*old_id
,
823 const char *old_target
);
825 static int refdb_fs_backend__delete_tail(
826 git_refdb_backend
*_backend
,
828 const char *ref_name
,
829 const git_oid
*old_id
, const char *old_target
);
831 static int refdb_fs_backend__unlock(git_refdb_backend
*backend
, void *payload
, int success
, int update_reflog
,
832 const git_reference
*ref
, const git_signature
*sig
, const char *message
)
834 git_filebuf
*lock
= (git_filebuf
*) payload
;
838 error
= refdb_fs_backend__delete_tail(backend
, lock
, ref
->name
, NULL
, NULL
);
840 error
= refdb_fs_backend__write_tail(backend
, ref
, lock
, update_reflog
, sig
, message
, NULL
, NULL
);
842 git_filebuf_cleanup(lock
);
849 * Find out what object this reference resolves to.
851 * For references that point to a 'big' tag (e.g. an
852 * actual tag object on the repository), we need to
853 * cache on the packfile the OID of the object to
854 * which that 'big tag' is pointing to.
856 static int packed_find_peel(refdb_fs_backend
*backend
, struct packref
*ref
)
860 if (ref
->flags
& PACKREF_HAS_PEEL
|| ref
->flags
& PACKREF_CANNOT_PEEL
)
864 * Find the tagged object in the repository
866 if (git_object_lookup(&object
, backend
->repo
, &ref
->oid
, GIT_OBJ_ANY
) < 0)
870 * If the tagged object is a Tag object, we need to resolve it;
871 * if the ref is actually a 'weak' ref, we don't need to resolve
874 if (git_object_type(object
) == GIT_OBJ_TAG
) {
875 git_tag
*tag
= (git_tag
*)object
;
878 * Find the object pointed at by this tag
880 git_oid_cpy(&ref
->peel
, git_tag_target_id(tag
));
881 ref
->flags
|= PACKREF_HAS_PEEL
;
884 * The reference has now cached the resolved OID, and is
885 * marked at such. When written to the packfile, it'll be
886 * accompanied by this resolved oid
890 git_object_free(object
);
895 * Write a single reference into a packfile
897 static int packed_write_ref(struct packref
*ref
, git_filebuf
*file
)
899 char oid
[GIT_OID_HEXSZ
+ 1];
900 git_oid_nfmt(oid
, sizeof(oid
), &ref
->oid
);
903 * For references that peel to an object in the repo, we must
904 * write the resulting peel on a separate line, e.g.
906 * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4
907 * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100
909 * This obviously only applies to tags.
910 * The required peels have already been loaded into `ref->peel_target`.
912 if (ref
->flags
& PACKREF_HAS_PEEL
) {
913 char peel
[GIT_OID_HEXSZ
+ 1];
914 git_oid_nfmt(peel
, sizeof(peel
), &ref
->peel
);
916 if (git_filebuf_printf(file
, "%s %s\n^%s\n", oid
, ref
->name
, peel
) < 0)
919 if (git_filebuf_printf(file
, "%s %s\n", oid
, ref
->name
) < 0)
927 * Remove all loose references
929 * Once we have successfully written a packfile,
930 * all the loose references that were packed must be
933 * This is a dangerous method; make sure the packfile
934 * is well-written, because we are destructing references
937 static int packed_remove_loose(refdb_fs_backend
*backend
)
940 git_filebuf lock
= GIT_FILEBUF_INIT
;
941 git_buf ref_content
= GIT_BUF_INIT
;
944 /* backend->refcache is already locked when this is called */
946 for (i
= 0; i
< git_sortedcache_entrycount(backend
->refcache
); ++i
) {
947 struct packref
*ref
= git_sortedcache_entry(backend
->refcache
, i
);
950 if (!ref
|| !(ref
->flags
& PACKREF_WAS_LOOSE
))
953 git_filebuf_cleanup(&lock
);
955 /* We need to stop anybody from updating the ref while we try to do a safe delete */
956 error
= loose_lock(&lock
, backend
, ref
->name
);
957 /* If someone else is updating it, let them do it */
958 if (error
== GIT_EEXISTS
|| error
== GIT_ENOTFOUND
)
962 git_buf_free(&ref_content
);
963 giterr_set(GITERR_REFERENCE
, "failed to lock loose reference '%s'", ref
->name
);
967 error
= git_futils_readbuffer(&ref_content
, lock
.path_original
);
968 /* Someone else beat us to cleaning up the ref, let's simply continue */
969 if (error
== GIT_ENOTFOUND
)
972 /* This became a symref between us packing and trying to delete it, so ignore it */
973 if (!git__prefixcmp(ref_content
.ptr
, GIT_SYMREF
))
976 /* Figure out the current id; if we find a bad ref file, skip it so we can do the rest */
977 if (loose_parse_oid(¤t_id
, lock
.path_original
, &ref_content
) < 0)
980 /* If the ref moved since we packed it, we must not delete it */
981 if (!git_oid_equal(¤t_id
, &ref
->oid
))
985 * if we fail to remove a single file, this is *not* good,
986 * but we should keep going and remove as many as possible.
987 * If we fail to remove, the ref is still in the old state, so
988 * we haven't lost information.
990 p_unlink(lock
.path_original
);
993 git_buf_free(&ref_content
);
994 git_filebuf_cleanup(&lock
);
999 * Write all the contents in the in-memory packfile to disk.
1001 static int packed_write(refdb_fs_backend
*backend
)
1003 git_sortedcache
*refcache
= backend
->refcache
;
1004 git_filebuf pack_file
= GIT_FILEBUF_INIT
;
1005 int error
, open_flags
= 0;
1008 /* lock the cache to updates while we do this */
1009 if ((error
= git_sortedcache_wlock(refcache
)) < 0)
1013 open_flags
= GIT_FILEBUF_FSYNC
;
1015 /* Open the file! */
1016 if ((error
= git_filebuf_open(&pack_file
, git_sortedcache_path(refcache
), open_flags
, GIT_PACKEDREFS_FILE_MODE
)) < 0)
1019 /* Packfiles have a header... apparently
1020 * This is in fact not required, but we might as well print it
1022 if ((error
= git_filebuf_printf(&pack_file
, "%s\n", GIT_PACKEDREFS_HEADER
)) < 0)
1025 for (i
= 0; i
< git_sortedcache_entrycount(refcache
); ++i
) {
1026 struct packref
*ref
= git_sortedcache_entry(refcache
, i
);
1029 if ((error
= packed_find_peel(backend
, ref
)) < 0)
1032 if ((error
= packed_write_ref(ref
, &pack_file
)) < 0)
1036 /* if we've written all the references properly, we can commit
1037 * the packfile to make the changes effective */
1038 if ((error
= git_filebuf_commit(&pack_file
)) < 0)
1041 /* when and only when the packfile has been properly written,
1042 * we can go ahead and remove the loose refs */
1043 if ((error
= packed_remove_loose(backend
)) < 0)
1046 git_sortedcache_updated(refcache
);
1047 git_sortedcache_wunlock(refcache
);
1049 /* we're good now */
1053 git_filebuf_cleanup(&pack_file
);
1054 git_sortedcache_wunlock(refcache
);
1059 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
);
1060 static int has_reflog(git_repository
*repo
, const char *name
);
1062 /* We only write if it's under heads/, remotes/ or notes/ or if it already has a log */
1063 static int should_write_reflog(int *write
, git_repository
*repo
, const char *name
)
1067 error
= git_repository__cvar(&logall
, repo
, GIT_CVAR_LOGALLREFUPDATES
);
1071 /* Defaults to the opposite of the repo being bare */
1072 if (logall
== GIT_LOGALLREFUPDATES_UNSET
)
1073 logall
= !git_repository_is_bare(repo
);
1077 } else if (has_reflog(repo
, name
)) {
1079 } else if (!git__prefixcmp(name
, GIT_REFS_HEADS_DIR
) ||
1080 !git__strcmp(name
, GIT_HEAD_FILE
) ||
1081 !git__prefixcmp(name
, GIT_REFS_REMOTES_DIR
) ||
1082 !git__prefixcmp(name
, GIT_REFS_NOTES_DIR
)) {
1091 static int cmp_old_ref(int *cmp
, git_refdb_backend
*backend
, const char *name
,
1092 const git_oid
*old_id
, const char *old_target
)
1095 git_reference
*old_ref
= NULL
;
1098 /* It "matches" if there is no old value to compare against */
1099 if (!old_id
&& !old_target
)
1102 if ((error
= refdb_fs_backend__lookup(&old_ref
, backend
, name
)) < 0)
1105 /* If the types don't match, there's no way the values do */
1106 if (old_id
&& old_ref
->type
!= GIT_REF_OID
) {
1110 if (old_target
&& old_ref
->type
!= GIT_REF_SYMBOLIC
) {
1115 if (old_id
&& old_ref
->type
== GIT_REF_OID
)
1116 *cmp
= git_oid_cmp(old_id
, &old_ref
->target
.oid
);
1118 if (old_target
&& old_ref
->type
== GIT_REF_SYMBOLIC
)
1119 *cmp
= git__strcmp(old_target
, old_ref
->target
.symbolic
);
1122 git_reference_free(old_ref
);
1128 * The git.git comment regarding this, for your viewing pleasure:
1130 * Special hack: If a branch is updated directly and HEAD
1131 * points to it (may happen on the remote side of a push
1132 * for example) then logically the HEAD reflog should be
1134 * A generic solution implies reverse symref information,
1135 * but finding all symrefs pointing to the given branch
1136 * would be rather costly for this rare event (the direct
1137 * update of a branch) to be worth it. So let's cheat and
1138 * check with HEAD only which should cover 99% of all usage
1139 * scenarios (even 100% of the default ones).
1141 static int maybe_append_head(refdb_fs_backend
*backend
, const git_reference
*ref
, const git_signature
*who
, const char *message
)
1145 git_reference
*tmp
= NULL
, *head
= NULL
, *peeled
= NULL
;
1148 if (ref
->type
== GIT_REF_SYMBOLIC
)
1151 /* if we can't resolve, we use {0}*40 as old id */
1152 if (git_reference_name_to_id(&old_id
, backend
->repo
, ref
->name
) < 0)
1153 memset(&old_id
, 0, sizeof(old_id
));
1155 if ((error
= git_reference_lookup(&head
, backend
->repo
, GIT_HEAD_FILE
)) < 0)
1158 if (git_reference_type(head
) == GIT_REF_OID
)
1161 if ((error
= git_reference_lookup(&tmp
, backend
->repo
, GIT_HEAD_FILE
)) < 0)
1164 /* Go down the symref chain until we find the branch */
1165 while (git_reference_type(tmp
) == GIT_REF_SYMBOLIC
) {
1166 error
= git_reference_lookup(&peeled
, backend
->repo
, git_reference_symbolic_target(tmp
));
1170 git_reference_free(tmp
);
1174 if (error
== GIT_ENOTFOUND
) {
1176 name
= git_reference_symbolic_target(tmp
);
1177 } else if (error
< 0) {
1180 name
= git_reference_name(tmp
);
1183 if (strcmp(name
, ref
->name
))
1186 error
= reflog_append(backend
, head
, &old_id
, git_reference_target(ref
), who
, message
);
1189 git_reference_free(tmp
);
1190 git_reference_free(head
);
1194 static int refdb_fs_backend__write(
1195 git_refdb_backend
*_backend
,
1196 const git_reference
*ref
,
1198 const git_signature
*who
,
1199 const char *message
,
1200 const git_oid
*old_id
,
1201 const char *old_target
)
1203 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1204 git_filebuf file
= GIT_FILEBUF_INIT
;
1209 if ((error
= reference_path_available(backend
, ref
->name
, NULL
, force
)) < 0)
1212 /* We need to perform the reflog append and old value check under the ref's lock */
1213 if ((error
= loose_lock(&file
, backend
, ref
->name
)) < 0)
1216 return refdb_fs_backend__write_tail(_backend
, ref
, &file
, true, who
, message
, old_id
, old_target
);
1219 static int refdb_fs_backend__write_tail(
1220 git_refdb_backend
*_backend
,
1221 const git_reference
*ref
,
1224 const git_signature
*who
,
1225 const char *message
,
1226 const git_oid
*old_id
,
1227 const char *old_target
)
1229 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1230 int error
= 0, cmp
= 0, should_write
;
1231 const char *new_target
= NULL
;
1232 const git_oid
*new_id
= NULL
;
1234 if ((error
= cmp_old_ref(&cmp
, _backend
, ref
->name
, old_id
, old_target
)) < 0)
1238 giterr_set(GITERR_REFERENCE
, "old reference value does not match");
1239 error
= GIT_EMODIFIED
;
1243 if (ref
->type
== GIT_REF_SYMBOLIC
)
1244 new_target
= ref
->target
.symbolic
;
1246 new_id
= &ref
->target
.oid
;
1248 error
= cmp_old_ref(&cmp
, _backend
, ref
->name
, new_id
, new_target
);
1249 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1252 /* Don't update if we have the same value */
1253 if (!error
&& !cmp
) {
1255 goto on_error
; /* not really error */
1258 if (update_reflog
) {
1259 if ((error
= should_write_reflog(&should_write
, backend
->repo
, ref
->name
)) < 0)
1263 if ((error
= reflog_append(backend
, ref
, NULL
, NULL
, who
, message
)) < 0)
1265 if ((error
= maybe_append_head(backend
, ref
, who
, message
)) < 0)
1270 return loose_commit(file
, ref
);
1273 git_filebuf_cleanup(file
);
1277 static int refdb_fs_backend__delete(
1278 git_refdb_backend
*_backend
,
1279 const char *ref_name
,
1280 const git_oid
*old_id
, const char *old_target
)
1282 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1283 git_filebuf file
= GIT_FILEBUF_INIT
;
1286 assert(backend
&& ref_name
);
1288 if ((error
= loose_lock(&file
, backend
, ref_name
)) < 0)
1291 if ((error
= refdb_reflog_fs__delete(_backend
, ref_name
)) < 0) {
1292 git_filebuf_cleanup(&file
);
1296 return refdb_fs_backend__delete_tail(_backend
, &file
, ref_name
, old_id
, old_target
);
1299 static int refdb_fs_backend__delete_tail(
1300 git_refdb_backend
*_backend
,
1302 const char *ref_name
,
1303 const git_oid
*old_id
, const char *old_target
)
1305 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1306 git_buf loose_path
= GIT_BUF_INIT
;
1308 int error
= 0, cmp
= 0;
1309 bool loose_deleted
= 0;
1311 error
= cmp_old_ref(&cmp
, _backend
, ref_name
, old_id
, old_target
);
1316 giterr_set(GITERR_REFERENCE
, "old reference value does not match");
1317 error
= GIT_EMODIFIED
;
1321 /* If a loose reference exists, remove it from the filesystem */
1322 if (git_buf_joinpath(&loose_path
, backend
->gitpath
, ref_name
) < 0)
1326 error
= p_unlink(loose_path
.ptr
);
1327 if (error
< 0 && errno
== ENOENT
)
1331 else if (error
== 0)
1334 if ((error
= packed_reload(backend
)) < 0)
1337 /* If a packed reference exists, remove it from the packfile and repack */
1338 if ((error
= git_sortedcache_wlock(backend
->refcache
)) < 0)
1341 if (!(error
= git_sortedcache_lookup_index(
1342 &pack_pos
, backend
->refcache
, ref_name
)))
1343 error
= git_sortedcache_remove(backend
->refcache
, pack_pos
);
1345 git_sortedcache_wunlock(backend
->refcache
);
1347 if (error
== GIT_ENOTFOUND
) {
1348 error
= loose_deleted
? 0 : ref_error_notfound(ref_name
);
1352 error
= packed_write(backend
);
1355 git_buf_free(&loose_path
);
1356 git_filebuf_cleanup(file
);
1361 static int refdb_reflog_fs__rename(git_refdb_backend
*_backend
, const char *old_name
, const char *new_name
);
1363 static int refdb_fs_backend__rename(
1364 git_reference
**out
,
1365 git_refdb_backend
*_backend
,
1366 const char *old_name
,
1367 const char *new_name
,
1369 const git_signature
*who
,
1370 const char *message
)
1372 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1373 git_reference
*old
, *new;
1374 git_filebuf file
= GIT_FILEBUF_INIT
;
1379 if ((error
= reference_path_available(
1380 backend
, new_name
, old_name
, force
)) < 0 ||
1381 (error
= refdb_fs_backend__lookup(&old
, _backend
, old_name
)) < 0)
1384 if ((error
= refdb_fs_backend__delete(_backend
, old_name
, NULL
, NULL
)) < 0) {
1385 git_reference_free(old
);
1389 new = git_reference__set_name(old
, new_name
);
1391 git_reference_free(old
);
1395 if ((error
= loose_lock(&file
, backend
, new->name
)) < 0) {
1396 git_reference_free(new);
1400 /* Try to rename the refog; it's ok if the old doesn't exist */
1401 error
= refdb_reflog_fs__rename(_backend
, old_name
, new_name
);
1402 if (((error
== 0) || (error
== GIT_ENOTFOUND
)) &&
1403 ((error
= reflog_append(backend
, new, git_reference_target(new), NULL
, who
, message
)) < 0)) {
1404 git_reference_free(new);
1405 git_filebuf_cleanup(&file
);
1410 git_reference_free(new);
1411 git_filebuf_cleanup(&file
);
1416 if ((error
= loose_commit(&file
, new)) < 0 || out
== NULL
) {
1417 git_reference_free(new);
1425 static int refdb_fs_backend__compress(git_refdb_backend
*_backend
)
1428 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1432 if ((error
= packed_reload(backend
)) < 0 || /* load the existing packfile */
1433 (error
= packed_loadloose(backend
)) < 0 || /* add all the loose refs */
1434 (error
= packed_write(backend
)) < 0) /* write back to disk */
1440 static void refdb_fs_backend__free(git_refdb_backend
*_backend
)
1442 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1446 git_sortedcache_free(backend
->refcache
);
1447 git__free(backend
->gitpath
);
1448 git__free(backend
->commonpath
);
1452 static char *setup_namespace(git_repository
*repo
, const char *in
)
1454 git_buf path
= GIT_BUF_INIT
;
1455 char *parts
, *start
, *end
, *out
= NULL
;
1460 git_buf_puts(&path
, in
);
1462 /* if the repo is not namespaced, nothing else to do */
1463 if (repo
->namespace == NULL
) {
1464 out
= git_buf_detach(&path
);
1468 parts
= end
= git__strdup(repo
->namespace);
1473 * From `man gitnamespaces`:
1474 * namespaces which include a / will expand to a hierarchy
1475 * of namespaces; for example, GIT_NAMESPACE=foo/bar will store
1476 * refs under refs/namespaces/foo/refs/namespaces/bar/
1478 while ((start
= git__strsep(&end
, "/")) != NULL
)
1479 git_buf_printf(&path
, "refs/namespaces/%s/", start
);
1481 git_buf_printf(&path
, "refs/namespaces/%s/refs", end
);
1484 /* Make sure that the folder with the namespace exists */
1485 if (git_futils_mkdir_relative(git_buf_cstr(&path
), in
, 0777,
1486 GIT_MKDIR_PATH
, NULL
) < 0)
1489 /* Return root of the namespaced gitpath, i.e. without the trailing '/refs' */
1490 git_buf_rtruncate_at_char(&path
, '/');
1491 out
= git_buf_detach(&path
);
1494 git_buf_free(&path
);
1498 static int reflog_alloc(git_reflog
**reflog
, const char *name
)
1504 log
= git__calloc(1, sizeof(git_reflog
));
1505 GITERR_CHECK_ALLOC(log
);
1507 log
->ref_name
= git__strdup(name
);
1508 GITERR_CHECK_ALLOC(log
->ref_name
);
1510 if (git_vector_init(&log
->entries
, 0, NULL
) < 0) {
1511 git__free(log
->ref_name
);
1521 static int reflog_parse(git_reflog
*log
, const char *buf
, size_t buf_size
)
1524 git_reflog_entry
*entry
;
1526 #define seek_forward(_increase) do { \
1527 if (_increase >= buf_size) { \
1528 giterr_set(GITERR_INVALID, "ran out of data while parsing reflog"); \
1532 buf_size -= _increase; \
1535 while (buf_size
> GIT_REFLOG_SIZE_MIN
) {
1536 entry
= git__calloc(1, sizeof(git_reflog_entry
));
1537 GITERR_CHECK_ALLOC(entry
);
1539 entry
->committer
= git__calloc(1, sizeof(git_signature
));
1540 GITERR_CHECK_ALLOC(entry
->committer
);
1542 if (git_oid_fromstrn(&entry
->oid_old
, buf
, GIT_OID_HEXSZ
) < 0)
1544 seek_forward(GIT_OID_HEXSZ
+ 1);
1546 if (git_oid_fromstrn(&entry
->oid_cur
, buf
, GIT_OID_HEXSZ
) < 0)
1548 seek_forward(GIT_OID_HEXSZ
+ 1);
1552 /* Seek forward to the end of the signature. */
1553 while (*buf
&& *buf
!= '\t' && *buf
!= '\n')
1556 if (git_signature__parse(entry
->committer
, &ptr
, buf
+ 1, NULL
, *buf
) < 0)
1560 /* We got a message. Read everything till we reach LF. */
1564 while (*buf
&& *buf
!= '\n')
1567 entry
->msg
= git__strndup(ptr
, buf
- ptr
);
1568 GITERR_CHECK_ALLOC(entry
->msg
);
1572 while (*buf
&& *buf
== '\n' && buf_size
> 1)
1575 if (git_vector_insert(&log
->entries
, entry
) < 0)
1584 git_reflog_entry__free(entry
);
1589 static int create_new_reflog_file(const char *filepath
)
1593 if ((error
= git_futils_mkpath2file(filepath
, GIT_REFLOG_DIR_MODE
)) < 0)
1596 if ((fd
= p_open(filepath
,
1598 GIT_REFLOG_FILE_MODE
)) < 0)
1604 GIT_INLINE(int) retrieve_reflog_path(git_buf
*path
, git_repository
*repo
, const char *name
)
1606 if (strcmp(name
, GIT_HEAD_FILE
) == 0)
1607 return git_buf_join3(path
, '/', repo
->gitdir
, GIT_REFLOG_DIR
, name
);
1608 return git_buf_join3(path
, '/', repo
->commondir
, GIT_REFLOG_DIR
, name
);
1611 static int refdb_reflog_fs__ensure_log(git_refdb_backend
*_backend
, const char *name
)
1613 refdb_fs_backend
*backend
;
1614 git_repository
*repo
;
1615 git_buf path
= GIT_BUF_INIT
;
1618 assert(_backend
&& name
);
1620 backend
= (refdb_fs_backend
*) _backend
;
1621 repo
= backend
->repo
;
1623 if ((error
= retrieve_reflog_path(&path
, repo
, name
)) < 0)
1626 error
= create_new_reflog_file(git_buf_cstr(&path
));
1627 git_buf_free(&path
);
1632 static int has_reflog(git_repository
*repo
, const char *name
)
1635 git_buf path
= GIT_BUF_INIT
;
1637 if (retrieve_reflog_path(&path
, repo
, name
) < 0)
1640 ret
= git_path_isfile(git_buf_cstr(&path
));
1643 git_buf_free(&path
);
1647 static int refdb_reflog_fs__has_log(git_refdb_backend
*_backend
, const char *name
)
1649 refdb_fs_backend
*backend
;
1651 assert(_backend
&& name
);
1653 backend
= (refdb_fs_backend
*) _backend
;
1655 return has_reflog(backend
->repo
, name
);
1658 static int refdb_reflog_fs__read(git_reflog
**out
, git_refdb_backend
*_backend
, const char *name
)
1661 git_buf log_path
= GIT_BUF_INIT
;
1662 git_buf log_file
= GIT_BUF_INIT
;
1663 git_reflog
*log
= NULL
;
1664 git_repository
*repo
;
1665 refdb_fs_backend
*backend
;
1667 assert(out
&& _backend
&& name
);
1669 backend
= (refdb_fs_backend
*) _backend
;
1670 repo
= backend
->repo
;
1672 if (reflog_alloc(&log
, name
) < 0)
1675 if (retrieve_reflog_path(&log_path
, repo
, name
) < 0)
1678 error
= git_futils_readbuffer(&log_file
, git_buf_cstr(&log_path
));
1679 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1682 if ((error
== GIT_ENOTFOUND
) &&
1683 ((error
= create_new_reflog_file(git_buf_cstr(&log_path
))) < 0))
1686 if ((error
= reflog_parse(log
,
1687 git_buf_cstr(&log_file
), git_buf_len(&log_file
))) < 0)
1694 git_reflog_free(log
);
1697 git_buf_free(&log_file
);
1698 git_buf_free(&log_path
);
1703 static int serialize_reflog_entry(
1705 const git_oid
*oid_old
,
1706 const git_oid
*oid_new
,
1707 const git_signature
*committer
,
1710 char raw_old
[GIT_OID_HEXSZ
+1];
1711 char raw_new
[GIT_OID_HEXSZ
+1];
1713 git_oid_tostr(raw_old
, GIT_OID_HEXSZ
+1, oid_old
);
1714 git_oid_tostr(raw_new
, GIT_OID_HEXSZ
+1, oid_new
);
1718 git_buf_puts(buf
, raw_old
);
1719 git_buf_putc(buf
, ' ');
1720 git_buf_puts(buf
, raw_new
);
1722 git_signature__writebuf(buf
, " ", committer
);
1724 /* drop trailing LF */
1728 git_buf_putc(buf
, '\t');
1729 git_buf_puts(buf
, msg
);
1732 git_buf_putc(buf
, '\n');
1734 return git_buf_oom(buf
);
1737 static int lock_reflog(git_filebuf
*file
, refdb_fs_backend
*backend
, const char *refname
)
1739 git_repository
*repo
;
1740 git_buf log_path
= GIT_BUF_INIT
;
1743 repo
= backend
->repo
;
1745 if (!git_path_isvalid(backend
->repo
, refname
, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS
)) {
1746 giterr_set(GITERR_INVALID
, "invalid reference name '%s'", refname
);
1747 return GIT_EINVALIDSPEC
;
1750 if (retrieve_reflog_path(&log_path
, repo
, refname
) < 0)
1753 if (!git_path_isfile(git_buf_cstr(&log_path
))) {
1754 giterr_set(GITERR_INVALID
,
1755 "log file for reference '%s' doesn't exist", refname
);
1760 error
= git_filebuf_open(file
, git_buf_cstr(&log_path
), 0, GIT_REFLOG_FILE_MODE
);
1763 git_buf_free(&log_path
);
1768 static int refdb_reflog_fs__write(git_refdb_backend
*_backend
, git_reflog
*reflog
)
1772 git_reflog_entry
*entry
;
1773 refdb_fs_backend
*backend
;
1774 git_buf log
= GIT_BUF_INIT
;
1775 git_filebuf fbuf
= GIT_FILEBUF_INIT
;
1777 assert(_backend
&& reflog
);
1779 backend
= (refdb_fs_backend
*) _backend
;
1781 if ((error
= lock_reflog(&fbuf
, backend
, reflog
->ref_name
)) < 0)
1784 git_vector_foreach(&reflog
->entries
, i
, entry
) {
1785 if (serialize_reflog_entry(&log
, &(entry
->oid_old
), &(entry
->oid_cur
), entry
->committer
, entry
->msg
) < 0)
1788 if ((error
= git_filebuf_write(&fbuf
, log
.ptr
, log
.size
)) < 0)
1792 error
= git_filebuf_commit(&fbuf
);
1796 git_filebuf_cleanup(&fbuf
);
1804 /* Append to the reflog, must be called under reference lock */
1805 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
)
1807 int error
, is_symbolic
, open_flags
;
1808 git_oid old_id
= {{0}}, new_id
= {{0}};
1809 git_buf buf
= GIT_BUF_INIT
, path
= GIT_BUF_INIT
;
1810 git_repository
*repo
= backend
->repo
;
1812 is_symbolic
= ref
->type
== GIT_REF_SYMBOLIC
;
1814 /* "normal" symbolic updates do not write */
1816 strcmp(ref
->name
, GIT_HEAD_FILE
) &&
1820 /* From here on is_symoblic also means that it's HEAD */
1823 git_oid_cpy(&old_id
, old
);
1825 error
= git_reference_name_to_id(&old_id
, repo
, ref
->name
);
1826 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1831 git_oid_cpy(&new_id
, new);
1834 git_oid_cpy(&new_id
, git_reference_target(ref
));
1836 error
= git_reference_name_to_id(&new_id
, repo
, git_reference_symbolic_target(ref
));
1837 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1839 /* detaching HEAD does not create an entry */
1840 if (error
== GIT_ENOTFOUND
)
1847 if ((error
= serialize_reflog_entry(&buf
, &old_id
, &new_id
, who
, message
)) < 0)
1850 if ((error
= retrieve_reflog_path(&path
, repo
, ref
->name
)) < 0)
1853 if (((error
= git_futils_mkpath2file(git_buf_cstr(&path
), 0777)) < 0) &&
1854 (error
!= GIT_EEXISTS
)) {
1858 /* If the new branch matches part of the namespace of a previously deleted branch,
1859 * there maybe an obsolete/unused directory (or directory hierarchy) in the way.
1861 if (git_path_isdir(git_buf_cstr(&path
))) {
1862 if ((error
= git_futils_rmdir_r(git_buf_cstr(&path
), NULL
, GIT_RMDIR_SKIP_NONEMPTY
)) < 0) {
1863 if (error
== GIT_ENOTFOUND
)
1865 } else if (git_path_isdir(git_buf_cstr(&path
))) {
1866 giterr_set(GITERR_REFERENCE
, "cannot create reflog at '%s', there are reflogs beneath that folder",
1868 error
= GIT_EDIRECTORY
;
1875 open_flags
= O_WRONLY
| O_CREAT
| O_APPEND
;
1878 open_flags
|= O_FSYNC
;
1880 error
= git_futils_writebuffer(&buf
, git_buf_cstr(&path
), open_flags
, GIT_REFLOG_FILE_MODE
);
1884 git_buf_free(&path
);
1889 static int refdb_reflog_fs__rename(git_refdb_backend
*_backend
, const char *old_name
, const char *new_name
)
1892 git_buf old_path
= GIT_BUF_INIT
;
1893 git_buf new_path
= GIT_BUF_INIT
;
1894 git_buf temp_path
= GIT_BUF_INIT
;
1895 git_buf normalized
= GIT_BUF_INIT
;
1896 git_repository
*repo
;
1897 refdb_fs_backend
*backend
;
1899 assert(_backend
&& old_name
&& new_name
);
1901 backend
= (refdb_fs_backend
*) _backend
;
1902 repo
= backend
->repo
;
1904 if ((error
= git_reference__normalize_name(
1905 &normalized
, new_name
, GIT_REF_FORMAT_ALLOW_ONELEVEL
)) < 0)
1908 if (git_buf_joinpath(&temp_path
, repo
->gitdir
, GIT_REFLOG_DIR
) < 0)
1911 if (git_buf_joinpath(&old_path
, git_buf_cstr(&temp_path
), old_name
) < 0)
1914 if (git_buf_joinpath(&new_path
, git_buf_cstr(&temp_path
), git_buf_cstr(&normalized
)) < 0)
1917 if (!git_path_exists(git_buf_cstr(&old_path
))) {
1918 error
= GIT_ENOTFOUND
;
1923 * Move the reflog to a temporary place. This two-phase renaming is required
1924 * in order to cope with funny renaming use cases when one tries to move a reference
1925 * to a partially colliding namespace:
1927 * - a/b/c/d -> a/b/c
1929 if (git_buf_joinpath(&temp_path
, git_buf_cstr(&temp_path
), "temp_reflog") < 0)
1932 if ((fd
= git_futils_mktmp(&temp_path
, git_buf_cstr(&temp_path
), GIT_REFLOG_FILE_MODE
)) < 0) {
1939 if (p_rename(git_buf_cstr(&old_path
), git_buf_cstr(&temp_path
)) < 0) {
1940 giterr_set(GITERR_OS
, "failed to rename reflog for %s", new_name
);
1945 if (git_path_isdir(git_buf_cstr(&new_path
)) &&
1946 (git_futils_rmdir_r(git_buf_cstr(&new_path
), NULL
, GIT_RMDIR_SKIP_NONEMPTY
) < 0)) {
1951 if (git_futils_mkpath2file(git_buf_cstr(&new_path
), GIT_REFLOG_DIR_MODE
) < 0) {
1956 if (p_rename(git_buf_cstr(&temp_path
), git_buf_cstr(&new_path
)) < 0) {
1957 giterr_set(GITERR_OS
, "failed to rename reflog for %s", new_name
);
1962 git_buf_free(&temp_path
);
1963 git_buf_free(&old_path
);
1964 git_buf_free(&new_path
);
1965 git_buf_free(&normalized
);
1970 static int refdb_reflog_fs__delete(git_refdb_backend
*_backend
, const char *name
)
1973 git_buf path
= GIT_BUF_INIT
;
1975 git_repository
*repo
;
1976 refdb_fs_backend
*backend
;
1978 assert(_backend
&& name
);
1980 backend
= (refdb_fs_backend
*) _backend
;
1981 repo
= backend
->repo
;
1983 error
= retrieve_reflog_path(&path
, repo
, name
);
1985 if (!error
&& git_path_exists(path
.ptr
))
1986 error
= p_unlink(path
.ptr
);
1988 git_buf_free(&path
);
1994 int git_refdb_backend_fs(
1995 git_refdb_backend
**backend_out
,
1996 git_repository
*repository
)
1999 git_buf gitpath
= GIT_BUF_INIT
;
2000 refdb_fs_backend
*backend
;
2002 backend
= git__calloc(1, sizeof(refdb_fs_backend
));
2003 GITERR_CHECK_ALLOC(backend
);
2005 backend
->repo
= repository
;
2007 if (repository
->gitdir
) {
2008 backend
->gitpath
= setup_namespace(repository
, repository
->gitdir
);
2010 if (backend
->gitpath
== NULL
)
2014 if (repository
->commondir
) {
2015 backend
->commonpath
= setup_namespace(repository
, repository
->commondir
);
2017 if (backend
->commonpath
== NULL
)
2021 if (git_buf_joinpath(&gitpath
, backend
->commonpath
, GIT_PACKEDREFS_FILE
) < 0 ||
2022 git_sortedcache_new(
2023 &backend
->refcache
, offsetof(struct packref
, name
),
2024 NULL
, NULL
, packref_cmp
, git_buf_cstr(&gitpath
)) < 0)
2027 git_buf_free(&gitpath
);
2029 if (!git_repository__cvar(&t
, backend
->repo
, GIT_CVAR_IGNORECASE
) && t
) {
2030 backend
->iterator_flags
|= GIT_ITERATOR_IGNORE_CASE
;
2031 backend
->direach_flags
|= GIT_PATH_DIR_IGNORE_CASE
;
2033 if (!git_repository__cvar(&t
, backend
->repo
, GIT_CVAR_PRECOMPOSE
) && t
) {
2034 backend
->iterator_flags
|= GIT_ITERATOR_PRECOMPOSE_UNICODE
;
2035 backend
->direach_flags
|= GIT_PATH_DIR_PRECOMPOSE_UNICODE
;
2037 if ((!git_repository__cvar(&t
, backend
->repo
, GIT_CVAR_FSYNCOBJECTFILES
) && t
) ||
2038 git_repository__fsync_gitdir
)
2040 backend
->iterator_flags
|= GIT_ITERATOR_DESCEND_SYMLINKS
;
2042 backend
->parent
.exists
= &refdb_fs_backend__exists
;
2043 backend
->parent
.lookup
= &refdb_fs_backend__lookup
;
2044 backend
->parent
.iterator
= &refdb_fs_backend__iterator
;
2045 backend
->parent
.write
= &refdb_fs_backend__write
;
2046 backend
->parent
.del
= &refdb_fs_backend__delete
;
2047 backend
->parent
.rename
= &refdb_fs_backend__rename
;
2048 backend
->parent
.compress
= &refdb_fs_backend__compress
;
2049 backend
->parent
.lock
= &refdb_fs_backend__lock
;
2050 backend
->parent
.unlock
= &refdb_fs_backend__unlock
;
2051 backend
->parent
.has_log
= &refdb_reflog_fs__has_log
;
2052 backend
->parent
.ensure_log
= &refdb_reflog_fs__ensure_log
;
2053 backend
->parent
.free
= &refdb_fs_backend__free
;
2054 backend
->parent
.reflog_read
= &refdb_reflog_fs__read
;
2055 backend
->parent
.reflog_write
= &refdb_reflog_fs__write
;
2056 backend
->parent
.reflog_rename
= &refdb_reflog_fs__rename
;
2057 backend
->parent
.reflog_delete
= &refdb_reflog_fs__delete
;
2059 *backend_out
= (git_refdb_backend
*)backend
;
2063 git_buf_free(&gitpath
);
2064 git__free(backend
->gitpath
);
2065 git__free(backend
->commonpath
);