Skip to content

Commit 75dd7f2

Browse files
authored
Merge pull request libgit2#4984 from pks-t/pks/refdb-fs-race
refdb_fs: fix loose/packed refs lookup racing with repacks
2 parents c559485 + 94743da commit 75dd7f2

File tree

1 file changed

+50
-41
lines changed

1 file changed

+50
-41
lines changed

src/refdb_fs.c

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -333,15 +333,27 @@ static int refdb_fs_backend__exists(
333333

334334
assert(backend);
335335

336-
if ((error = packed_reload(backend)) < 0 ||
337-
(error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0)
338-
return error;
336+
*exists = 0;
339337

340-
*exists = git_path_isfile(ref_path.ptr) ||
341-
(git_sortedcache_lookup(backend->refcache, ref_name) != NULL);
338+
if ((error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0)
339+
goto out;
342340

341+
if (git_path_isfile(ref_path.ptr)) {
342+
*exists = 1;
343+
goto out;
344+
}
345+
346+
if ((error = packed_reload(backend)) < 0)
347+
goto out;
348+
349+
if (git_sortedcache_lookup(backend->refcache, ref_name) != NULL) {
350+
*exists = 1;
351+
goto out;
352+
}
353+
354+
out:
343355
git_buf_dispose(&ref_path);
344-
return 0;
356+
return error;
345357
}
346358

347359
static const char *loose_parse_symbolic(git_buf *file_content)
@@ -552,7 +564,6 @@ static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter)
552564

553565
while (!error && !git_iterator_advance(&entry, fsit)) {
554566
const char *ref_name;
555-
struct packref *ref;
556567
char *ref_dup;
557568

558569
git_buf_truncate(&path, ref_prefix_len);
@@ -563,12 +574,6 @@ static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter)
563574
(iter->glob && p_fnmatch(iter->glob, ref_name, 0) != 0))
564575
continue;
565576

566-
git_sortedcache_rlock(backend->refcache);
567-
ref = git_sortedcache_lookup(backend->refcache, ref_name);
568-
if (ref)
569-
ref->flags |= PACKREF_SHADOWED;
570-
git_sortedcache_runlock(backend->refcache);
571-
572577
ref_dup = git_pool_strdup(&iter->pool, ref_name);
573578
if (!ref_dup)
574579
error = -1;
@@ -593,17 +598,17 @@ static int refdb_fs_backend__iterator_next(
593598
while (iter->loose_pos < iter->loose.length) {
594599
const char *path = git_vector_get(&iter->loose, iter->loose_pos++);
595600

596-
if (loose_lookup(out, backend, path) == 0)
601+
if (loose_lookup(out, backend, path) == 0) {
602+
ref = git_sortedcache_lookup(iter->cache, path);
603+
if (ref)
604+
ref->flags |= PACKREF_SHADOWED;
605+
597606
return 0;
607+
}
598608

599609
git_error_clear();
600610
}
601611

602-
if (!iter->cache) {
603-
if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
604-
return error;
605-
}
606-
607612
error = GIT_ITEROVER;
608613
while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
609614
ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
@@ -633,20 +638,20 @@ static int refdb_fs_backend__iterator_next_name(
633638

634639
while (iter->loose_pos < iter->loose.length) {
635640
const char *path = git_vector_get(&iter->loose, iter->loose_pos++);
641+
struct packref *ref;
636642

637643
if (loose_lookup(NULL, backend, path) == 0) {
644+
ref = git_sortedcache_lookup(iter->cache, path);
645+
if (ref)
646+
ref->flags |= PACKREF_SHADOWED;
647+
638648
*out = path;
639649
return 0;
640650
}
641651

642652
git_error_clear();
643653
}
644654

645-
if (!iter->cache) {
646-
if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
647-
return error;
648-
}
649-
650655
error = GIT_ITEROVER;
651656
while (iter->packed_pos < git_sortedcache_entrycount(iter->cache)) {
652657
ref = git_sortedcache_entry(iter->cache, iter->packed_pos++);
@@ -669,40 +674,44 @@ static int refdb_fs_backend__iterator_next_name(
669674
static int refdb_fs_backend__iterator(
670675
git_reference_iterator **out, git_refdb_backend *_backend, const char *glob)
671676
{
672-
int error;
673-
refdb_fs_iter *iter;
674677
refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
678+
refdb_fs_iter *iter = NULL;
679+
int error;
675680

676681
assert(backend);
677682

678-
if ((error = packed_reload(backend)) < 0)
679-
return error;
680-
681683
iter = git__calloc(1, sizeof(refdb_fs_iter));
682684
GIT_ERROR_CHECK_ALLOC(iter);
683685

684686
git_pool_init(&iter->pool, 1);
685687

686-
if (git_vector_init(&iter->loose, 8, NULL) < 0)
687-
goto fail;
688+
if ((error = git_vector_init(&iter->loose, 8, NULL)) < 0)
689+
goto out;
688690

689691
if (glob != NULL &&
690-
(iter->glob = git_pool_strdup(&iter->pool, glob)) == NULL)
691-
goto fail;
692+
(iter->glob = git_pool_strdup(&iter->pool, glob)) == NULL) {
693+
error = GIT_ERROR_NOMEMORY;
694+
goto out;
695+
}
696+
697+
if ((error = iter_load_loose_paths(backend, iter)) < 0)
698+
goto out;
699+
700+
if ((error = packed_reload(backend)) < 0)
701+
goto out;
702+
703+
if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)
704+
goto out;
692705

693706
iter->parent.next = refdb_fs_backend__iterator_next;
694707
iter->parent.next_name = refdb_fs_backend__iterator_next_name;
695708
iter->parent.free = refdb_fs_backend__iterator_free;
696709

697-
if (iter_load_loose_paths(backend, iter) < 0)
698-
goto fail;
699-
700710
*out = (git_reference_iterator *)iter;
701-
return 0;
702-
703-
fail:
704-
refdb_fs_backend__iterator_free((git_reference_iterator *)iter);
705-
return -1;
711+
out:
712+
if (error)
713+
refdb_fs_backend__iterator_free((git_reference_iterator *)iter);
714+
return error;
706715
}
707716

708717
static bool ref_is_available(

0 commit comments

Comments
 (0)