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"
22 #include <git2/object.h>
23 #include <git2/refdb.h>
24 #include <git2/branch.h>
25 #include <git2/sys/refdb_backend.h>
26 #include <git2/sys/refs.h>
27 #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
;
60 git_sortedcache
*refcache
;
62 git_iterator_flag_t iterator_flags
;
63 uint32_t direach_flags
;
66 static int refdb_reflog_fs__delete(git_refdb_backend
*_backend
, const char *name
);
68 static int packref_cmp(const void *a_
, const void *b_
)
70 const struct packref
*a
= a_
, *b
= b_
;
71 return strcmp(a
->name
, b
->name
);
74 static int packed_reload(refdb_fs_backend
*backend
)
77 git_buf packedrefs
= GIT_BUF_INIT
;
78 char *scan
, *eof
, *eol
;
83 error
= git_sortedcache_lockandload(backend
->refcache
, &packedrefs
);
86 * If we can't find the packed-refs, clear table and return.
87 * Any other error just gets passed through.
88 * If no error, and file wasn't changed, just return.
89 * Anything else means we need to refresh the packed refs.
92 if (error
== GIT_ENOTFOUND
) {
93 git_sortedcache_clear(backend
->refcache
, true);
100 /* At this point, refresh the packed refs from the loaded buffer. */
102 git_sortedcache_clear(backend
->refcache
, false);
104 scan
= (char *)packedrefs
.ptr
;
105 eof
= scan
+ packedrefs
.size
;
107 backend
->peeling_mode
= PEELING_NONE
;
110 static const char *traits_header
= "# pack-refs with: ";
112 if (git__prefixcmp(scan
, traits_header
) == 0) {
113 scan
+= strlen(traits_header
);
114 eol
= strchr(scan
, '\n');
120 if (strstr(scan
, " fully-peeled ") != NULL
) {
121 backend
->peeling_mode
= PEELING_FULL
;
122 } else if (strstr(scan
, " peeled ") != NULL
) {
123 backend
->peeling_mode
= PEELING_STANDARD
;
130 while (scan
< eof
&& *scan
== '#') {
131 if (!(eol
= strchr(scan
, '\n')))
140 /* parse "<OID> <refname>\n" */
142 if (git_oid_fromstr(&oid
, scan
) < 0)
144 scan
+= GIT_OID_HEXSZ
;
148 if (!(eol
= strchr(scan
, '\n')))
154 if (git_sortedcache_upsert((void **)&ref
, backend
->refcache
, scan
) < 0)
158 git_oid_cpy(&ref
->oid
, &oid
);
160 /* look for optional "^<OID>\n" */
163 if (git_oid_fromstr(&oid
, scan
+ 1) < 0)
165 scan
+= GIT_OID_HEXSZ
+ 1;
168 if (!(eol
= strchr(scan
, '\n')))
173 git_oid_cpy(&ref
->peel
, &oid
);
174 ref
->flags
|= PACKREF_HAS_PEEL
;
176 else if (backend
->peeling_mode
== PEELING_FULL
||
177 (backend
->peeling_mode
== PEELING_STANDARD
&&
178 git__prefixcmp(ref
->name
, GIT_REFS_TAGS_DIR
) == 0))
179 ref
->flags
|= PACKREF_CANNOT_PEEL
;
182 git_sortedcache_wunlock(backend
->refcache
);
183 git_buf_free(&packedrefs
);
188 giterr_set(GITERR_REFERENCE
, "Corrupted packed references file");
190 git_sortedcache_clear(backend
->refcache
, false);
191 git_sortedcache_wunlock(backend
->refcache
);
192 git_buf_free(&packedrefs
);
197 static int loose_parse_oid(
198 git_oid
*oid
, const char *filename
, git_buf
*file_content
)
200 const char *str
= git_buf_cstr(file_content
);
202 if (git_buf_len(file_content
) < GIT_OID_HEXSZ
)
205 /* we need to get 40 OID characters from the file */
206 if (git_oid_fromstr(oid
, str
) < 0)
209 /* If the file is longer than 40 chars, the 41st must be a space */
210 str
+= GIT_OID_HEXSZ
;
211 if (*str
== '\0' || git__isspace(*str
))
215 giterr_set(GITERR_REFERENCE
, "Corrupted loose reference file: %s", filename
);
219 static int loose_readbuffer(git_buf
*buf
, const char *base
, const char *path
)
223 /* build full path to file */
224 if ((error
= git_buf_joinpath(buf
, base
, path
)) < 0 ||
225 (error
= git_futils_readbuffer(buf
, buf
->ptr
)) < 0)
231 static int loose_lookup_to_packfile(refdb_fs_backend
*backend
, const char *name
)
234 git_buf ref_file
= GIT_BUF_INIT
;
235 struct packref
*ref
= NULL
;
238 /* if we fail to load the loose reference, assume someone changed
239 * the filesystem under us and skip it...
241 if (loose_readbuffer(&ref_file
, backend
->path
, name
) < 0) {
246 /* skip symbolic refs */
247 if (!git__prefixcmp(git_buf_cstr(&ref_file
), GIT_SYMREF
))
250 /* parse OID from file */
251 if ((error
= loose_parse_oid(&oid
, name
, &ref_file
)) < 0)
254 git_sortedcache_wlock(backend
->refcache
);
256 if (!(error
= git_sortedcache_upsert(
257 (void **)&ref
, backend
->refcache
, name
))) {
259 git_oid_cpy(&ref
->oid
, &oid
);
260 ref
->flags
= PACKREF_WAS_LOOSE
;
263 git_sortedcache_wunlock(backend
->refcache
);
266 git_buf_free(&ref_file
);
270 static int _dirent_loose_load(void *payload
, git_buf
*full_path
)
272 refdb_fs_backend
*backend
= payload
;
273 const char *file_path
;
275 if (git__suffixcmp(full_path
->ptr
, ".lock") == 0)
278 if (git_path_isdir(full_path
->ptr
)) {
279 int error
= git_path_direach(
280 full_path
, backend
->direach_flags
, _dirent_loose_load
, backend
);
281 /* Race with the filesystem, ignore it */
282 if (error
== GIT_ENOTFOUND
) {
290 file_path
= full_path
->ptr
+ strlen(backend
->path
);
292 return loose_lookup_to_packfile(backend
, file_path
);
296 * Load all the loose references from the repository
297 * into the in-memory Packfile, and build a vector with
298 * all the references so it can be written back to
301 static int packed_loadloose(refdb_fs_backend
*backend
)
304 git_buf refs_path
= GIT_BUF_INIT
;
306 if (git_buf_joinpath(&refs_path
, backend
->path
, GIT_REFS_DIR
) < 0)
310 * Load all the loose files from disk into the Packfile table.
311 * This will overwrite any old packed entries with their
312 * updated loose versions
314 error
= git_path_direach(
315 &refs_path
, backend
->direach_flags
, _dirent_loose_load
, backend
);
317 git_buf_free(&refs_path
);
322 static int refdb_fs_backend__exists(
324 git_refdb_backend
*_backend
,
325 const char *ref_name
)
327 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
328 git_buf ref_path
= GIT_BUF_INIT
;
332 if (packed_reload(backend
) < 0 ||
333 git_buf_joinpath(&ref_path
, backend
->path
, ref_name
) < 0)
336 *exists
= git_path_isfile(ref_path
.ptr
) ||
337 (git_sortedcache_lookup(backend
->refcache
, ref_name
) != NULL
);
339 git_buf_free(&ref_path
);
343 static const char *loose_parse_symbolic(git_buf
*file_content
)
345 const unsigned int header_len
= (unsigned int)strlen(GIT_SYMREF
);
346 const char *refname_start
;
348 refname_start
= (const char *)file_content
->ptr
;
350 if (git_buf_len(file_content
) < header_len
+ 1) {
351 giterr_set(GITERR_REFERENCE
, "Corrupted loose reference file");
356 * Assume we have already checked for the header
357 * before calling this function
359 refname_start
+= header_len
;
361 return refname_start
;
364 static int loose_lookup(
366 refdb_fs_backend
*backend
,
367 const char *ref_name
)
369 git_buf ref_file
= GIT_BUF_INIT
;
375 if ((error
= loose_readbuffer(&ref_file
, backend
->path
, ref_name
)) < 0)
376 /* cannot read loose ref file - gah */;
377 else if (git__prefixcmp(git_buf_cstr(&ref_file
), GIT_SYMREF
) == 0) {
380 git_buf_rtrim(&ref_file
);
382 if (!(target
= loose_parse_symbolic(&ref_file
)))
384 else if (out
!= NULL
)
385 *out
= git_reference__alloc_symbolic(ref_name
, target
);
389 if (!(error
= loose_parse_oid(&oid
, ref_name
, &ref_file
)) &&
391 *out
= git_reference__alloc(ref_name
, &oid
, NULL
);
394 git_buf_free(&ref_file
);
398 static int ref_error_notfound(const char *name
)
400 giterr_set(GITERR_REFERENCE
, "Reference '%s' not found", name
);
401 return GIT_ENOTFOUND
;
404 static int packed_lookup(
406 refdb_fs_backend
*backend
,
407 const char *ref_name
)
410 struct packref
*entry
;
412 if (packed_reload(backend
) < 0)
415 if (git_sortedcache_rlock(backend
->refcache
) < 0)
418 entry
= git_sortedcache_lookup(backend
->refcache
, ref_name
);
420 error
= ref_error_notfound(ref_name
);
422 *out
= git_reference__alloc(ref_name
, &entry
->oid
, &entry
->peel
);
427 git_sortedcache_runlock(backend
->refcache
);
432 static int refdb_fs_backend__lookup(
434 git_refdb_backend
*_backend
,
435 const char *ref_name
)
437 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
442 if (!(error
= loose_lookup(out
, backend
, ref_name
)))
445 /* only try to lookup this reference on the packfile if it
446 * wasn't found on the loose refs; not if there was a critical error */
447 if (error
== GIT_ENOTFOUND
) {
449 error
= packed_lookup(out
, backend
, ref_name
);
456 git_reference_iterator parent
;
463 git_sortedcache
*cache
;
468 static void refdb_fs_backend__iterator_free(git_reference_iterator
*_iter
)
470 refdb_fs_iter
*iter
= (refdb_fs_iter
*) _iter
;
472 git_vector_free(&iter
->loose
);
473 git_pool_clear(&iter
->pool
);
474 git_sortedcache_free(iter
->cache
);
478 static int iter_load_loose_paths(refdb_fs_backend
*backend
, refdb_fs_iter
*iter
)
481 git_buf path
= GIT_BUF_INIT
;
482 git_iterator
*fsit
= NULL
;
483 const git_index_entry
*entry
= NULL
;
485 if (!backend
->path
) /* do nothing if no path for loose refs */
488 if ((error
= git_buf_printf(&path
, "%s/refs", backend
->path
)) < 0 ||
489 (error
= git_iterator_for_filesystem(
490 &fsit
, path
.ptr
, backend
->iterator_flags
, NULL
, NULL
)) < 0) {
495 error
= git_buf_sets(&path
, GIT_REFS_DIR
);
497 while (!error
&& !git_iterator_advance(&entry
, fsit
)) {
498 const char *ref_name
;
502 git_buf_truncate(&path
, strlen(GIT_REFS_DIR
));
503 git_buf_puts(&path
, entry
->path
);
504 ref_name
= git_buf_cstr(&path
);
506 if (git__suffixcmp(ref_name
, ".lock") == 0 ||
507 (iter
->glob
&& p_fnmatch(iter
->glob
, ref_name
, 0) != 0))
510 git_sortedcache_rlock(backend
->refcache
);
511 ref
= git_sortedcache_lookup(backend
->refcache
, ref_name
);
513 ref
->flags
|= PACKREF_SHADOWED
;
514 git_sortedcache_runlock(backend
->refcache
);
516 ref_dup
= git_pool_strdup(&iter
->pool
, ref_name
);
520 error
= git_vector_insert(&iter
->loose
, ref_dup
);
523 git_iterator_free(fsit
);
529 static int refdb_fs_backend__iterator_next(
530 git_reference
**out
, git_reference_iterator
*_iter
)
532 int error
= GIT_ITEROVER
;
533 refdb_fs_iter
*iter
= (refdb_fs_iter
*)_iter
;
534 refdb_fs_backend
*backend
= (refdb_fs_backend
*)iter
->parent
.db
->backend
;
537 while (iter
->loose_pos
< iter
->loose
.length
) {
538 const char *path
= git_vector_get(&iter
->loose
, iter
->loose_pos
++);
540 if (loose_lookup(out
, backend
, path
) == 0)
547 if ((error
= git_sortedcache_copy(&iter
->cache
, backend
->refcache
, 1, NULL
, NULL
)) < 0)
551 error
= GIT_ITEROVER
;
552 while (iter
->packed_pos
< git_sortedcache_entrycount(iter
->cache
)) {
553 ref
= git_sortedcache_entry(iter
->cache
, iter
->packed_pos
++);
554 if (!ref
) /* stop now if another thread deleted refs and we past end */
557 if (ref
->flags
& PACKREF_SHADOWED
)
559 if (iter
->glob
&& p_fnmatch(iter
->glob
, ref
->name
, 0) != 0)
562 *out
= git_reference__alloc(ref
->name
, &ref
->oid
, &ref
->peel
);
563 error
= (*out
!= NULL
) ? 0 : -1;
570 static int refdb_fs_backend__iterator_next_name(
571 const char **out
, git_reference_iterator
*_iter
)
573 int error
= GIT_ITEROVER
;
574 refdb_fs_iter
*iter
= (refdb_fs_iter
*)_iter
;
575 refdb_fs_backend
*backend
= (refdb_fs_backend
*)iter
->parent
.db
->backend
;
578 while (iter
->loose_pos
< iter
->loose
.length
) {
579 const char *path
= git_vector_get(&iter
->loose
, iter
->loose_pos
++);
581 if (loose_lookup(NULL
, backend
, path
) == 0) {
590 if ((error
= git_sortedcache_copy(&iter
->cache
, backend
->refcache
, 1, NULL
, NULL
)) < 0)
594 error
= GIT_ITEROVER
;
595 while (iter
->packed_pos
< git_sortedcache_entrycount(iter
->cache
)) {
596 ref
= git_sortedcache_entry(iter
->cache
, iter
->packed_pos
++);
597 if (!ref
) /* stop now if another thread deleted refs and we past end */
600 if (ref
->flags
& PACKREF_SHADOWED
)
602 if (iter
->glob
&& p_fnmatch(iter
->glob
, ref
->name
, 0) != 0)
613 static int refdb_fs_backend__iterator(
614 git_reference_iterator
**out
, git_refdb_backend
*_backend
, const char *glob
)
617 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
621 if (packed_reload(backend
) < 0)
624 iter
= git__calloc(1, sizeof(refdb_fs_iter
));
625 GITERR_CHECK_ALLOC(iter
);
627 if (git_pool_init(&iter
->pool
, 1, 0) < 0 ||
628 git_vector_init(&iter
->loose
, 8, NULL
) < 0)
632 (iter
->glob
= git_pool_strdup(&iter
->pool
, glob
)) == NULL
)
635 iter
->parent
.next
= refdb_fs_backend__iterator_next
;
636 iter
->parent
.next_name
= refdb_fs_backend__iterator_next_name
;
637 iter
->parent
.free
= refdb_fs_backend__iterator_free
;
639 if (iter_load_loose_paths(backend
, iter
) < 0)
642 *out
= (git_reference_iterator
*)iter
;
646 refdb_fs_backend__iterator_free((git_reference_iterator
*)iter
);
650 static bool ref_is_available(
651 const char *old_ref
, const char *new_ref
, const char *this_ref
)
653 if (old_ref
== NULL
|| strcmp(old_ref
, this_ref
)) {
654 size_t reflen
= strlen(this_ref
);
655 size_t newlen
= strlen(new_ref
);
656 size_t cmplen
= reflen
< newlen
? reflen
: newlen
;
657 const char *lead
= reflen
< newlen
? new_ref
: this_ref
;
659 if (!strncmp(new_ref
, this_ref
, cmplen
) && lead
[cmplen
] == '/') {
667 static int reference_path_available(
668 refdb_fs_backend
*backend
,
675 if (packed_reload(backend
) < 0)
681 if (refdb_fs_backend__exists(
682 &exists
, (git_refdb_backend
*)backend
, new_ref
) < 0)
686 giterr_set(GITERR_REFERENCE
,
687 "Failed to write reference '%s': a reference with "
688 "that name already exists.", new_ref
);
693 git_sortedcache_rlock(backend
->refcache
);
695 for (i
= 0; i
< git_sortedcache_entrycount(backend
->refcache
); ++i
) {
696 struct packref
*ref
= git_sortedcache_entry(backend
->refcache
, i
);
698 if (ref
&& !ref_is_available(old_ref
, new_ref
, ref
->name
)) {
699 git_sortedcache_runlock(backend
->refcache
);
700 giterr_set(GITERR_REFERENCE
,
701 "Path to reference '%s' collides with existing one", new_ref
);
706 git_sortedcache_runlock(backend
->refcache
);
710 static int loose_lock(git_filebuf
*file
, refdb_fs_backend
*backend
, const char *name
)
713 git_buf ref_path
= GIT_BUF_INIT
;
715 assert(file
&& backend
&& name
);
717 if (!git_path_isvalid(backend
->repo
, name
, GIT_PATH_REJECT_DEFAULTS
)) {
718 giterr_set(GITERR_INVALID
, "Invalid reference name '%s'.", name
);
719 return GIT_EINVALIDSPEC
;
722 /* Remove a possibly existing empty directory hierarchy
723 * which name would collide with the reference name
725 if (git_futils_rmdir_r(name
, backend
->path
, GIT_RMDIR_SKIP_NONEMPTY
) < 0)
728 if (git_buf_joinpath(&ref_path
, backend
->path
, name
) < 0)
731 error
= git_filebuf_open(file
, ref_path
.ptr
, GIT_FILEBUF_FORCE
, GIT_REFS_FILE_MODE
);
733 git_buf_free(&ref_path
);
737 static int loose_commit(git_filebuf
*file
, const git_reference
*ref
)
741 if (ref
->type
== GIT_REF_OID
) {
742 char oid
[GIT_OID_HEXSZ
+ 1];
743 git_oid_nfmt(oid
, sizeof(oid
), &ref
->target
.oid
);
745 git_filebuf_printf(file
, "%s\n", oid
);
746 } else if (ref
->type
== GIT_REF_SYMBOLIC
) {
747 git_filebuf_printf(file
, GIT_SYMREF
"%s\n", ref
->target
.symbolic
);
749 assert(0); /* don't let this happen */
752 return git_filebuf_commit(file
);
755 static int refdb_fs_backend__lock(void **out
, git_refdb_backend
*_backend
, const char *refname
)
759 refdb_fs_backend
*backend
= (refdb_fs_backend
*) _backend
;
761 lock
= git__calloc(1, sizeof(git_filebuf
));
762 GITERR_CHECK_ALLOC(lock
);
764 if ((error
= loose_lock(lock
, backend
, refname
)) < 0) {
773 static int refdb_fs_backend__write_tail(
774 git_refdb_backend
*_backend
,
775 const git_reference
*ref
,
778 const git_signature
*who
,
780 const git_oid
*old_id
,
781 const char *old_target
);
783 static int refdb_fs_backend__delete_tail(
784 git_refdb_backend
*_backend
,
786 const char *ref_name
,
787 const git_oid
*old_id
, const char *old_target
);
789 static int refdb_fs_backend__unlock(git_refdb_backend
*backend
, void *payload
, int success
, int update_reflog
,
790 const git_reference
*ref
, const git_signature
*sig
, const char *message
)
792 git_filebuf
*lock
= (git_filebuf
*) payload
;
796 error
= refdb_fs_backend__delete_tail(backend
, lock
, ref
->name
, NULL
, NULL
);
798 error
= refdb_fs_backend__write_tail(backend
, ref
, lock
, update_reflog
, sig
, message
, NULL
, NULL
);
800 git_filebuf_cleanup(lock
);
807 * Find out what object this reference resolves to.
809 * For references that point to a 'big' tag (e.g. an
810 * actual tag object on the repository), we need to
811 * cache on the packfile the OID of the object to
812 * which that 'big tag' is pointing to.
814 static int packed_find_peel(refdb_fs_backend
*backend
, struct packref
*ref
)
818 if (ref
->flags
& PACKREF_HAS_PEEL
|| ref
->flags
& PACKREF_CANNOT_PEEL
)
822 * Find the tagged object in the repository
824 if (git_object_lookup(&object
, backend
->repo
, &ref
->oid
, GIT_OBJ_ANY
) < 0)
828 * If the tagged object is a Tag object, we need to resolve it;
829 * if the ref is actually a 'weak' ref, we don't need to resolve
832 if (git_object_type(object
) == GIT_OBJ_TAG
) {
833 git_tag
*tag
= (git_tag
*)object
;
836 * Find the object pointed at by this tag
838 git_oid_cpy(&ref
->peel
, git_tag_target_id(tag
));
839 ref
->flags
|= PACKREF_HAS_PEEL
;
842 * The reference has now cached the resolved OID, and is
843 * marked at such. When written to the packfile, it'll be
844 * accompanied by this resolved oid
848 git_object_free(object
);
853 * Write a single reference into a packfile
855 static int packed_write_ref(struct packref
*ref
, git_filebuf
*file
)
857 char oid
[GIT_OID_HEXSZ
+ 1];
858 git_oid_nfmt(oid
, sizeof(oid
), &ref
->oid
);
861 * For references that peel to an object in the repo, we must
862 * write the resulting peel on a separate line, e.g.
864 * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4
865 * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100
867 * This obviously only applies to tags.
868 * The required peels have already been loaded into `ref->peel_target`.
870 if (ref
->flags
& PACKREF_HAS_PEEL
) {
871 char peel
[GIT_OID_HEXSZ
+ 1];
872 git_oid_nfmt(peel
, sizeof(peel
), &ref
->peel
);
874 if (git_filebuf_printf(file
, "%s %s\n^%s\n", oid
, ref
->name
, peel
) < 0)
877 if (git_filebuf_printf(file
, "%s %s\n", oid
, ref
->name
) < 0)
885 * Remove all loose references
887 * Once we have successfully written a packfile,
888 * all the loose references that were packed must be
891 * This is a dangerous method; make sure the packfile
892 * is well-written, because we are destructing references
895 static int packed_remove_loose(refdb_fs_backend
*backend
)
898 git_buf full_path
= GIT_BUF_INIT
;
901 /* backend->refcache is already locked when this is called */
903 for (i
= 0; i
< git_sortedcache_entrycount(backend
->refcache
); ++i
) {
904 struct packref
*ref
= git_sortedcache_entry(backend
->refcache
, i
);
906 if (!ref
|| !(ref
->flags
& PACKREF_WAS_LOOSE
))
909 if (git_buf_joinpath(&full_path
, backend
->path
, ref
->name
) < 0)
910 return -1; /* critical; do not try to recover on oom */
912 if (git_path_exists(full_path
.ptr
) && p_unlink(full_path
.ptr
) < 0) {
916 giterr_set(GITERR_REFERENCE
,
917 "Failed to remove loose reference '%s' after packing: %s",
918 full_path
.ptr
, strerror(errno
));
923 * if we fail to remove a single file, this is *not* good,
924 * but we should keep going and remove as many as possible.
925 * After we've removed as many files as possible, we return
926 * the error code anyway.
930 git_buf_free(&full_path
);
931 return failed
? -1 : 0;
935 * Write all the contents in the in-memory packfile to disk.
937 static int packed_write(refdb_fs_backend
*backend
)
939 git_sortedcache
*refcache
= backend
->refcache
;
940 git_filebuf pack_file
= GIT_FILEBUF_INIT
;
943 /* lock the cache to updates while we do this */
944 if (git_sortedcache_wlock(refcache
) < 0)
948 if (git_filebuf_open(&pack_file
, git_sortedcache_path(refcache
), 0, GIT_PACKEDREFS_FILE_MODE
) < 0)
951 /* Packfiles have a header... apparently
952 * This is in fact not required, but we might as well print it
954 if (git_filebuf_printf(&pack_file
, "%s\n", GIT_PACKEDREFS_HEADER
) < 0)
957 for (i
= 0; i
< git_sortedcache_entrycount(refcache
); ++i
) {
958 struct packref
*ref
= git_sortedcache_entry(refcache
, i
);
960 if (packed_find_peel(backend
, ref
) < 0)
963 if (packed_write_ref(ref
, &pack_file
) < 0)
967 /* if we've written all the references properly, we can commit
968 * the packfile to make the changes effective */
969 if (git_filebuf_commit(&pack_file
) < 0)
972 /* when and only when the packfile has been properly written,
973 * we can go ahead and remove the loose refs */
974 if (packed_remove_loose(backend
) < 0)
977 git_sortedcache_updated(refcache
);
978 git_sortedcache_wunlock(refcache
);
984 git_filebuf_cleanup(&pack_file
);
985 git_sortedcache_wunlock(refcache
);
990 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
);
991 static int has_reflog(git_repository
*repo
, const char *name
);
993 /* We only write if it's under heads/, remotes/ or notes/ or if it already has a log */
994 static int should_write_reflog(int *write
, git_repository
*repo
, const char *name
)
998 error
= git_repository__cvar(&logall
, repo
, GIT_CVAR_LOGALLREFUPDATES
);
1002 /* Defaults to the opposite of the repo being bare */
1003 if (logall
== GIT_LOGALLREFUPDATES_UNSET
)
1004 logall
= !git_repository_is_bare(repo
);
1008 } else if (has_reflog(repo
, name
)) {
1010 } else if (!git__prefixcmp(name
, GIT_REFS_HEADS_DIR
) ||
1011 !git__strcmp(name
, GIT_HEAD_FILE
) ||
1012 !git__prefixcmp(name
, GIT_REFS_REMOTES_DIR
) ||
1013 !git__prefixcmp(name
, GIT_REFS_NOTES_DIR
)) {
1022 static int cmp_old_ref(int *cmp
, git_refdb_backend
*backend
, const char *name
,
1023 const git_oid
*old_id
, const char *old_target
)
1026 git_reference
*old_ref
= NULL
;
1029 /* It "matches" if there is no old value to compare against */
1030 if (!old_id
&& !old_target
)
1033 if ((error
= refdb_fs_backend__lookup(&old_ref
, backend
, name
)) < 0)
1036 /* If the types don't match, there's no way the values do */
1037 if (old_id
&& old_ref
->type
!= GIT_REF_OID
) {
1041 if (old_target
&& old_ref
->type
!= GIT_REF_SYMBOLIC
) {
1046 if (old_id
&& old_ref
->type
== GIT_REF_OID
)
1047 *cmp
= git_oid_cmp(old_id
, &old_ref
->target
.oid
);
1049 if (old_target
&& old_ref
->type
== GIT_REF_SYMBOLIC
)
1050 *cmp
= git__strcmp(old_target
, old_ref
->target
.symbolic
);
1053 git_reference_free(old_ref
);
1059 * The git.git comment regarding this, for your viewing pleasure:
1061 * Special hack: If a branch is updated directly and HEAD
1062 * points to it (may happen on the remote side of a push
1063 * for example) then logically the HEAD reflog should be
1065 * A generic solution implies reverse symref information,
1066 * but finding all symrefs pointing to the given branch
1067 * would be rather costly for this rare event (the direct
1068 * update of a branch) to be worth it. So let's cheat and
1069 * check with HEAD only which should cover 99% of all usage
1070 * scenarios (even 100% of the default ones).
1072 static int maybe_append_head(refdb_fs_backend
*backend
, const git_reference
*ref
, const git_signature
*who
, const char *message
)
1075 git_oid old_id
= {{0}};
1076 git_reference
*tmp
= NULL
, *head
= NULL
, *peeled
= NULL
;
1079 if (ref
->type
== GIT_REF_SYMBOLIC
)
1082 /* if we can't resolve, we use {0}*40 as old id */
1083 git_reference_name_to_id(&old_id
, backend
->repo
, ref
->name
);
1085 if ((error
= git_reference_lookup(&head
, backend
->repo
, GIT_HEAD_FILE
)) < 0)
1088 if (git_reference_type(head
) == GIT_REF_OID
)
1091 if ((error
= git_reference_lookup(&tmp
, backend
->repo
, GIT_HEAD_FILE
)) < 0)
1094 /* Go down the symref chain until we find the branch */
1095 while (git_reference_type(tmp
) == GIT_REF_SYMBOLIC
) {
1096 error
= git_reference_lookup(&peeled
, backend
->repo
, git_reference_symbolic_target(tmp
));
1100 git_reference_free(tmp
);
1104 if (error
== GIT_ENOTFOUND
) {
1106 name
= git_reference_symbolic_target(tmp
);
1107 } else if (error
< 0) {
1110 name
= git_reference_name(tmp
);
1113 if (strcmp(name
, ref
->name
))
1116 error
= reflog_append(backend
, head
, &old_id
, git_reference_target(ref
), who
, message
);
1119 git_reference_free(tmp
);
1120 git_reference_free(head
);
1124 static int refdb_fs_backend__write(
1125 git_refdb_backend
*_backend
,
1126 const git_reference
*ref
,
1128 const git_signature
*who
,
1129 const char *message
,
1130 const git_oid
*old_id
,
1131 const char *old_target
)
1133 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1134 git_filebuf file
= GIT_FILEBUF_INIT
;
1139 error
= reference_path_available(backend
, ref
->name
, NULL
, force
);
1143 /* We need to perform the reflog append and old value check under the ref's lock */
1144 if ((error
= loose_lock(&file
, backend
, ref
->name
)) < 0)
1147 return refdb_fs_backend__write_tail(_backend
, ref
, &file
, true, who
, message
, old_id
, old_target
);
1150 static int refdb_fs_backend__write_tail(
1151 git_refdb_backend
*_backend
,
1152 const git_reference
*ref
,
1155 const git_signature
*who
,
1156 const char *message
,
1157 const git_oid
*old_id
,
1158 const char *old_target
)
1160 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1161 int error
= 0, cmp
= 0, should_write
;
1162 const char *new_target
= NULL
;
1163 const git_oid
*new_id
= NULL
;
1165 if ((error
= cmp_old_ref(&cmp
, _backend
, ref
->name
, old_id
, old_target
)) < 0)
1169 giterr_set(GITERR_REFERENCE
, "old reference value does not match");
1170 error
= GIT_EMODIFIED
;
1174 if (ref
->type
== GIT_REF_SYMBOLIC
)
1175 new_target
= ref
->target
.symbolic
;
1177 new_id
= &ref
->target
.oid
;
1179 error
= cmp_old_ref(&cmp
, _backend
, ref
->name
, new_id
, new_target
);
1180 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1183 /* Don't update if we have the same value */
1184 if (!error
&& !cmp
) {
1186 goto on_error
; /* not really error */
1189 if (update_reflog
) {
1190 if ((error
= should_write_reflog(&should_write
, backend
->repo
, ref
->name
)) < 0)
1194 if ((error
= reflog_append(backend
, ref
, NULL
, NULL
, who
, message
)) < 0)
1196 if ((error
= maybe_append_head(backend
, ref
, who
, message
)) < 0)
1201 return loose_commit(file
, ref
);
1204 git_filebuf_cleanup(file
);
1208 static int refdb_fs_backend__delete(
1209 git_refdb_backend
*_backend
,
1210 const char *ref_name
,
1211 const git_oid
*old_id
, const char *old_target
)
1213 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1214 git_filebuf file
= GIT_FILEBUF_INIT
;
1217 assert(backend
&& ref_name
);
1219 if ((error
= loose_lock(&file
, backend
, ref_name
)) < 0)
1222 if ((error
= refdb_reflog_fs__delete(_backend
, ref_name
)) < 0) {
1223 git_filebuf_cleanup(&file
);
1227 return refdb_fs_backend__delete_tail(_backend
, &file
, ref_name
, old_id
, old_target
);
1230 static int refdb_fs_backend__delete_tail(
1231 git_refdb_backend
*_backend
,
1233 const char *ref_name
,
1234 const git_oid
*old_id
, const char *old_target
)
1236 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1237 git_buf loose_path
= GIT_BUF_INIT
;
1239 int error
= 0, cmp
= 0;
1240 bool loose_deleted
= 0;
1242 error
= cmp_old_ref(&cmp
, _backend
, ref_name
, old_id
, old_target
);
1247 giterr_set(GITERR_REFERENCE
, "old reference value does not match");
1248 error
= GIT_EMODIFIED
;
1252 /* If a loose reference exists, remove it from the filesystem */
1253 if (git_buf_joinpath(&loose_path
, backend
->path
, ref_name
) < 0)
1256 if (git_path_isfile(loose_path
.ptr
)) {
1257 error
= p_unlink(loose_path
.ptr
);
1261 git_buf_free(&loose_path
);
1266 if ((error
= packed_reload(backend
)) < 0)
1269 /* If a packed reference exists, remove it from the packfile and repack */
1270 if ((error
= git_sortedcache_wlock(backend
->refcache
)) < 0)
1273 if (!(error
= git_sortedcache_lookup_index(
1274 &pack_pos
, backend
->refcache
, ref_name
)))
1275 error
= git_sortedcache_remove(backend
->refcache
, pack_pos
);
1277 git_sortedcache_wunlock(backend
->refcache
);
1279 if (error
== GIT_ENOTFOUND
) {
1280 error
= loose_deleted
? 0 : ref_error_notfound(ref_name
);
1284 error
= packed_write(backend
);
1287 git_filebuf_cleanup(file
);
1292 static int refdb_reflog_fs__rename(git_refdb_backend
*_backend
, const char *old_name
, const char *new_name
);
1294 static int refdb_fs_backend__rename(
1295 git_reference
**out
,
1296 git_refdb_backend
*_backend
,
1297 const char *old_name
,
1298 const char *new_name
,
1300 const git_signature
*who
,
1301 const char *message
)
1303 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1304 git_reference
*old
, *new;
1305 git_filebuf file
= GIT_FILEBUF_INIT
;
1310 if ((error
= reference_path_available(
1311 backend
, new_name
, old_name
, force
)) < 0 ||
1312 (error
= refdb_fs_backend__lookup(&old
, _backend
, old_name
)) < 0)
1315 if ((error
= refdb_fs_backend__delete(_backend
, old_name
, NULL
, NULL
)) < 0) {
1316 git_reference_free(old
);
1320 new = git_reference__set_name(old
, new_name
);
1322 git_reference_free(old
);
1326 if ((error
= loose_lock(&file
, backend
, new->name
)) < 0) {
1327 git_reference_free(new);
1331 /* Try to rename the refog; it's ok if the old doesn't exist */
1332 error
= refdb_reflog_fs__rename(_backend
, old_name
, new_name
);
1333 if (((error
== 0) || (error
== GIT_ENOTFOUND
)) &&
1334 ((error
= reflog_append(backend
, new, git_reference_target(new), NULL
, who
, message
)) < 0)) {
1335 git_reference_free(new);
1336 git_filebuf_cleanup(&file
);
1341 git_reference_free(new);
1342 git_filebuf_cleanup(&file
);
1347 if ((error
= loose_commit(&file
, new)) < 0 || out
== NULL
) {
1348 git_reference_free(new);
1356 static int refdb_fs_backend__compress(git_refdb_backend
*_backend
)
1358 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1362 if (packed_reload(backend
) < 0 || /* load the existing packfile */
1363 packed_loadloose(backend
) < 0 || /* add all the loose refs */
1364 packed_write(backend
) < 0) /* write back to disk */
1370 static void refdb_fs_backend__free(git_refdb_backend
*_backend
)
1372 refdb_fs_backend
*backend
= (refdb_fs_backend
*)_backend
;
1376 git_sortedcache_free(backend
->refcache
);
1377 git__free(backend
->path
);
1381 static int setup_namespace(git_buf
*path
, git_repository
*repo
)
1383 char *parts
, *start
, *end
;
1385 /* Not all repositories have a path */
1386 if (repo
->path_repository
== NULL
)
1389 /* Load the path to the repo first */
1390 git_buf_puts(path
, repo
->path_repository
);
1392 /* if the repo is not namespaced, nothing else to do */
1393 if (repo
->namespace == NULL
)
1396 parts
= end
= git__strdup(repo
->namespace);
1401 * From `man gitnamespaces`:
1402 * namespaces which include a / will expand to a hierarchy
1403 * of namespaces; for example, GIT_NAMESPACE=foo/bar will store
1404 * refs under refs/namespaces/foo/refs/namespaces/bar/
1406 while ((start
= git__strsep(&end
, "/")) != NULL
) {
1407 git_buf_printf(path
, "refs/namespaces/%s/", start
);
1410 git_buf_printf(path
, "refs/namespaces/%s/refs", end
);
1413 /* Make sure that the folder with the namespace exists */
1414 if (git_futils_mkdir_r(git_buf_cstr(path
), repo
->path_repository
, 0777) < 0)
1417 /* Return root of the namespaced path, i.e. without the trailing '/refs' */
1418 git_buf_rtruncate_at_char(path
, '/');
1422 static int reflog_alloc(git_reflog
**reflog
, const char *name
)
1428 log
= git__calloc(1, sizeof(git_reflog
));
1429 GITERR_CHECK_ALLOC(log
);
1431 log
->ref_name
= git__strdup(name
);
1432 GITERR_CHECK_ALLOC(log
->ref_name
);
1434 if (git_vector_init(&log
->entries
, 0, NULL
) < 0) {
1435 git__free(log
->ref_name
);
1445 static int reflog_parse(git_reflog
*log
, const char *buf
, size_t buf_size
)
1448 git_reflog_entry
*entry
;
1450 #define seek_forward(_increase) do { \
1451 if (_increase >= buf_size) { \
1452 giterr_set(GITERR_INVALID, "Ran out of data while parsing reflog"); \
1456 buf_size -= _increase; \
1459 while (buf_size
> GIT_REFLOG_SIZE_MIN
) {
1460 entry
= git__calloc(1, sizeof(git_reflog_entry
));
1461 GITERR_CHECK_ALLOC(entry
);
1463 entry
->committer
= git__malloc(sizeof(git_signature
));
1464 GITERR_CHECK_ALLOC(entry
->committer
);
1466 if (git_oid_fromstrn(&entry
->oid_old
, buf
, GIT_OID_HEXSZ
) < 0)
1468 seek_forward(GIT_OID_HEXSZ
+ 1);
1470 if (git_oid_fromstrn(&entry
->oid_cur
, buf
, GIT_OID_HEXSZ
) < 0)
1472 seek_forward(GIT_OID_HEXSZ
+ 1);
1476 /* Seek forward to the end of the signature. */
1477 while (*buf
&& *buf
!= '\t' && *buf
!= '\n')
1480 if (git_signature__parse(entry
->committer
, &ptr
, buf
+ 1, NULL
, *buf
) < 0)
1484 /* We got a message. Read everything till we reach LF. */
1488 while (*buf
&& *buf
!= '\n')
1491 entry
->msg
= git__strndup(ptr
, buf
- ptr
);
1492 GITERR_CHECK_ALLOC(entry
->msg
);
1496 while (*buf
&& *buf
== '\n' && buf_size
> 1)
1499 if (git_vector_insert(&log
->entries
, entry
) < 0)
1509 git_reflog_entry__free(entry
);
1514 static int create_new_reflog_file(const char *filepath
)
1518 if ((error
= git_futils_mkpath2file(filepath
, GIT_REFLOG_DIR_MODE
)) < 0)
1521 if ((fd
= p_open(filepath
,
1523 GIT_REFLOG_FILE_MODE
)) < 0)
1529 GIT_INLINE(int) retrieve_reflog_path(git_buf
*path
, git_repository
*repo
, const char *name
)
1531 return git_buf_join3(path
, '/', repo
->path_repository
, GIT_REFLOG_DIR
, name
);
1534 static int refdb_reflog_fs__ensure_log(git_refdb_backend
*_backend
, const char *name
)
1536 refdb_fs_backend
*backend
;
1537 git_repository
*repo
;
1538 git_buf path
= GIT_BUF_INIT
;
1541 assert(_backend
&& name
);
1543 backend
= (refdb_fs_backend
*) _backend
;
1544 repo
= backend
->repo
;
1546 if ((error
= retrieve_reflog_path(&path
, repo
, name
)) < 0)
1549 error
= create_new_reflog_file(git_buf_cstr(&path
));
1550 git_buf_free(&path
);
1555 static int has_reflog(git_repository
*repo
, const char *name
)
1558 git_buf path
= GIT_BUF_INIT
;
1560 if (retrieve_reflog_path(&path
, repo
, name
) < 0)
1563 ret
= git_path_isfile(git_buf_cstr(&path
));
1566 git_buf_free(&path
);
1570 static int refdb_reflog_fs__has_log(git_refdb_backend
*_backend
, const char *name
)
1572 refdb_fs_backend
*backend
;
1574 assert(_backend
&& name
);
1576 backend
= (refdb_fs_backend
*) _backend
;
1578 return has_reflog(backend
->repo
, name
);
1581 static int refdb_reflog_fs__read(git_reflog
**out
, git_refdb_backend
*_backend
, const char *name
)
1584 git_buf log_path
= GIT_BUF_INIT
;
1585 git_buf log_file
= GIT_BUF_INIT
;
1586 git_reflog
*log
= NULL
;
1587 git_repository
*repo
;
1588 refdb_fs_backend
*backend
;
1590 assert(out
&& _backend
&& name
);
1592 backend
= (refdb_fs_backend
*) _backend
;
1593 repo
= backend
->repo
;
1595 if (reflog_alloc(&log
, name
) < 0)
1598 if (retrieve_reflog_path(&log_path
, repo
, name
) < 0)
1601 error
= git_futils_readbuffer(&log_file
, git_buf_cstr(&log_path
));
1602 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1605 if ((error
== GIT_ENOTFOUND
) &&
1606 ((error
= create_new_reflog_file(git_buf_cstr(&log_path
))) < 0))
1609 if ((error
= reflog_parse(log
,
1610 git_buf_cstr(&log_file
), git_buf_len(&log_file
))) < 0)
1617 git_reflog_free(log
);
1620 git_buf_free(&log_file
);
1621 git_buf_free(&log_path
);
1626 static int serialize_reflog_entry(
1628 const git_oid
*oid_old
,
1629 const git_oid
*oid_new
,
1630 const git_signature
*committer
,
1633 char raw_old
[GIT_OID_HEXSZ
+1];
1634 char raw_new
[GIT_OID_HEXSZ
+1];
1636 git_oid_tostr(raw_old
, GIT_OID_HEXSZ
+1, oid_old
);
1637 git_oid_tostr(raw_new
, GIT_OID_HEXSZ
+1, oid_new
);
1641 git_buf_puts(buf
, raw_old
);
1642 git_buf_putc(buf
, ' ');
1643 git_buf_puts(buf
, raw_new
);
1645 git_signature__writebuf(buf
, " ", committer
);
1647 /* drop trailing LF */
1651 git_buf_putc(buf
, '\t');
1652 git_buf_puts(buf
, msg
);
1655 git_buf_putc(buf
, '\n');
1657 return git_buf_oom(buf
);
1660 static int lock_reflog(git_filebuf
*file
, refdb_fs_backend
*backend
, const char *refname
)
1662 git_repository
*repo
;
1663 git_buf log_path
= GIT_BUF_INIT
;
1666 repo
= backend
->repo
;
1668 if (!git_path_isvalid(backend
->repo
, refname
, GIT_PATH_REJECT_DEFAULTS
)) {
1669 giterr_set(GITERR_INVALID
, "Invalid reference name '%s'.", refname
);
1670 return GIT_EINVALIDSPEC
;
1673 if (retrieve_reflog_path(&log_path
, repo
, refname
) < 0)
1676 if (!git_path_isfile(git_buf_cstr(&log_path
))) {
1677 giterr_set(GITERR_INVALID
,
1678 "Log file for reference '%s' doesn't exist.", refname
);
1683 error
= git_filebuf_open(file
, git_buf_cstr(&log_path
), 0, GIT_REFLOG_FILE_MODE
);
1686 git_buf_free(&log_path
);
1691 static int refdb_reflog_fs__write(git_refdb_backend
*_backend
, git_reflog
*reflog
)
1695 git_reflog_entry
*entry
;
1696 refdb_fs_backend
*backend
;
1697 git_buf log
= GIT_BUF_INIT
;
1698 git_filebuf fbuf
= GIT_FILEBUF_INIT
;
1700 assert(_backend
&& reflog
);
1702 backend
= (refdb_fs_backend
*) _backend
;
1704 if ((error
= lock_reflog(&fbuf
, backend
, reflog
->ref_name
)) < 0)
1707 git_vector_foreach(&reflog
->entries
, i
, entry
) {
1708 if (serialize_reflog_entry(&log
, &(entry
->oid_old
), &(entry
->oid_cur
), entry
->committer
, entry
->msg
) < 0)
1711 if ((error
= git_filebuf_write(&fbuf
, log
.ptr
, log
.size
)) < 0)
1715 error
= git_filebuf_commit(&fbuf
);
1719 git_filebuf_cleanup(&fbuf
);
1727 /* Append to the reflog, must be called under reference lock */
1728 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
)
1730 int error
, is_symbolic
;
1731 git_oid old_id
= {{0}}, new_id
= {{0}};
1732 git_buf buf
= GIT_BUF_INIT
, path
= GIT_BUF_INIT
;
1733 git_repository
*repo
= backend
->repo
;
1735 is_symbolic
= ref
->type
== GIT_REF_SYMBOLIC
;
1737 /* "normal" symbolic updates do not write */
1739 strcmp(ref
->name
, GIT_HEAD_FILE
) &&
1743 /* From here on is_symoblic also means that it's HEAD */
1746 git_oid_cpy(&old_id
, old
);
1748 error
= git_reference_name_to_id(&old_id
, repo
, ref
->name
);
1749 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1754 git_oid_cpy(&new_id
, new);
1757 git_oid_cpy(&new_id
, git_reference_target(ref
));
1759 error
= git_reference_name_to_id(&new_id
, repo
, git_reference_symbolic_target(ref
));
1760 if (error
< 0 && error
!= GIT_ENOTFOUND
)
1762 /* detaching HEAD does not create an entry */
1763 if (error
== GIT_ENOTFOUND
)
1770 if ((error
= serialize_reflog_entry(&buf
, &old_id
, &new_id
, who
, message
)) < 0)
1773 if ((error
= retrieve_reflog_path(&path
, repo
, ref
->name
)) < 0)
1776 if (((error
= git_futils_mkpath2file(git_buf_cstr(&path
), 0777)) < 0) &&
1777 (error
!= GIT_EEXISTS
)) {
1781 /* If the new branch matches part of the namespace of a previously deleted branch,
1782 * there maybe an obsolete/unused directory (or directory hierarchy) in the way.
1784 if (git_path_isdir(git_buf_cstr(&path
)) &&
1785 (git_futils_rmdir_r(git_buf_cstr(&path
), NULL
, GIT_RMDIR_SKIP_NONEMPTY
) < 0)) {
1790 error
= git_futils_writebuffer(&buf
, git_buf_cstr(&path
), O_WRONLY
|O_CREAT
|O_APPEND
, GIT_REFLOG_FILE_MODE
);
1794 git_buf_free(&path
);
1799 static int refdb_reflog_fs__rename(git_refdb_backend
*_backend
, const char *old_name
, const char *new_name
)
1802 git_buf old_path
= GIT_BUF_INIT
;
1803 git_buf new_path
= GIT_BUF_INIT
;
1804 git_buf temp_path
= GIT_BUF_INIT
;
1805 git_buf normalized
= GIT_BUF_INIT
;
1806 git_repository
*repo
;
1807 refdb_fs_backend
*backend
;
1809 assert(_backend
&& old_name
&& new_name
);
1811 backend
= (refdb_fs_backend
*) _backend
;
1812 repo
= backend
->repo
;
1814 if ((error
= git_reference__normalize_name(
1815 &normalized
, new_name
, GIT_REF_FORMAT_ALLOW_ONELEVEL
)) < 0)
1818 if (git_buf_joinpath(&temp_path
, repo
->path_repository
, GIT_REFLOG_DIR
) < 0)
1821 if (git_buf_joinpath(&old_path
, git_buf_cstr(&temp_path
), old_name
) < 0)
1824 if (git_buf_joinpath(&new_path
, git_buf_cstr(&temp_path
), git_buf_cstr(&normalized
)) < 0)
1827 if (!git_path_exists(git_buf_cstr(&old_path
))) {
1828 error
= GIT_ENOTFOUND
;
1833 * Move the reflog to a temporary place. This two-phase renaming is required
1834 * in order to cope with funny renaming use cases when one tries to move a reference
1835 * to a partially colliding namespace:
1837 * - a/b/c/d -> a/b/c
1839 if (git_buf_joinpath(&temp_path
, git_buf_cstr(&temp_path
), "temp_reflog") < 0)
1842 if ((fd
= git_futils_mktmp(&temp_path
, git_buf_cstr(&temp_path
), GIT_REFLOG_FILE_MODE
)) < 0) {
1849 if (p_rename(git_buf_cstr(&old_path
), git_buf_cstr(&temp_path
)) < 0) {
1850 giterr_set(GITERR_OS
, "Failed to rename reflog for %s", new_name
);
1855 if (git_path_isdir(git_buf_cstr(&new_path
)) &&
1856 (git_futils_rmdir_r(git_buf_cstr(&new_path
), NULL
, GIT_RMDIR_SKIP_NONEMPTY
) < 0)) {
1861 if (git_futils_mkpath2file(git_buf_cstr(&new_path
), GIT_REFLOG_DIR_MODE
) < 0) {
1866 if (p_rename(git_buf_cstr(&temp_path
), git_buf_cstr(&new_path
)) < 0) {
1867 giterr_set(GITERR_OS
, "Failed to rename reflog for %s", new_name
);
1872 git_buf_free(&temp_path
);
1873 git_buf_free(&old_path
);
1874 git_buf_free(&new_path
);
1875 git_buf_free(&normalized
);
1880 static int refdb_reflog_fs__delete(git_refdb_backend
*_backend
, const char *name
)
1883 git_buf path
= GIT_BUF_INIT
;
1885 git_repository
*repo
;
1886 refdb_fs_backend
*backend
;
1888 assert(_backend
&& name
);
1890 backend
= (refdb_fs_backend
*) _backend
;
1891 repo
= backend
->repo
;
1893 error
= retrieve_reflog_path(&path
, repo
, name
);
1895 if (!error
&& git_path_exists(path
.ptr
))
1896 error
= p_unlink(path
.ptr
);
1898 git_buf_free(&path
);
1904 int git_refdb_backend_fs(
1905 git_refdb_backend
**backend_out
,
1906 git_repository
*repository
)
1909 git_buf path
= GIT_BUF_INIT
;
1910 refdb_fs_backend
*backend
;
1912 backend
= git__calloc(1, sizeof(refdb_fs_backend
));
1913 GITERR_CHECK_ALLOC(backend
);
1915 backend
->repo
= repository
;
1917 if (setup_namespace(&path
, repository
) < 0)
1920 backend
->path
= git_buf_detach(&path
);
1922 if (git_buf_joinpath(&path
, backend
->path
, GIT_PACKEDREFS_FILE
) < 0 ||
1923 git_sortedcache_new(
1924 &backend
->refcache
, offsetof(struct packref
, name
),
1925 NULL
, NULL
, packref_cmp
, git_buf_cstr(&path
)) < 0)
1928 git_buf_free(&path
);
1930 if (!git_repository__cvar(&t
, backend
->repo
, GIT_CVAR_IGNORECASE
) && t
) {
1931 backend
->iterator_flags
|= GIT_ITERATOR_IGNORE_CASE
;
1932 backend
->direach_flags
|= GIT_PATH_DIR_IGNORE_CASE
;
1934 if (!git_repository__cvar(&t
, backend
->repo
, GIT_CVAR_PRECOMPOSE
) && t
) {
1935 backend
->iterator_flags
|= GIT_ITERATOR_PRECOMPOSE_UNICODE
;
1936 backend
->direach_flags
|= GIT_PATH_DIR_PRECOMPOSE_UNICODE
;
1939 backend
->parent
.exists
= &refdb_fs_backend__exists
;
1940 backend
->parent
.lookup
= &refdb_fs_backend__lookup
;
1941 backend
->parent
.iterator
= &refdb_fs_backend__iterator
;
1942 backend
->parent
.write
= &refdb_fs_backend__write
;
1943 backend
->parent
.del
= &refdb_fs_backend__delete
;
1944 backend
->parent
.rename
= &refdb_fs_backend__rename
;
1945 backend
->parent
.compress
= &refdb_fs_backend__compress
;
1946 backend
->parent
.lock
= &refdb_fs_backend__lock
;
1947 backend
->parent
.unlock
= &refdb_fs_backend__unlock
;
1948 backend
->parent
.has_log
= &refdb_reflog_fs__has_log
;
1949 backend
->parent
.ensure_log
= &refdb_reflog_fs__ensure_log
;
1950 backend
->parent
.free
= &refdb_fs_backend__free
;
1951 backend
->parent
.reflog_read
= &refdb_reflog_fs__read
;
1952 backend
->parent
.reflog_write
= &refdb_reflog_fs__write
;
1953 backend
->parent
.reflog_rename
= &refdb_reflog_fs__rename
;
1954 backend
->parent
.reflog_delete
= &refdb_reflog_fs__delete
;
1956 *backend_out
= (git_refdb_backend
*)backend
;
1960 git_buf_free(&path
);
1961 git__free(backend
->path
);