Skip to content

Commit ce5553d

Browse files
committed
refdb: bubble up locked files on the read side
On Windows we can find locked files even when reading a reference or the packed-refs file. Bubble up the error in this case as well to allow callers on Windows to retry more intelligently.
1 parent 7c32d87 commit ce5553d

File tree

4 files changed

+42
-23
lines changed

4 files changed

+42
-23
lines changed

src/path.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,10 @@ int git_path_set_error(int errno_value, const char *path, const char *action)
644644
giterr_set(GITERR_OS, "Failed %s - '%s' already exists", action, path);
645645
return GIT_EEXISTS;
646646

647+
case EACCES:
648+
giterr_set(GITERR_OS, "Failed %s - '%s' is locked", action, path);
649+
return GIT_ELOCKED;
650+
647651
default:
648652
giterr_set(GITERR_OS, "Could not %s '%s'", action, path);
649653
return -1;

src/refdb.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,15 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name)
125125

126126
int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob)
127127
{
128+
int error;
129+
128130
if (!db->backend || !db->backend->iterator) {
129131
giterr_set(GITERR_REFERENCE, "This backend doesn't support iterators");
130132
return -1;
131133
}
132134

133-
if (db->backend->iterator(out, db->backend, glob) < 0)
134-
return -1;
135+
if ((error = db->backend->iterator(out, db->backend, glob)) < 0)
136+
return error;
135137

136138
GIT_REFCOUNT_INC(db);
137139
(*out)->db = db;

src/refdb_fs.c

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,13 @@ static int refdb_fs_backend__exists(
326326
{
327327
refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
328328
git_buf ref_path = GIT_BUF_INIT;
329+
int error;
329330

330331
assert(backend);
331332

332-
if (packed_reload(backend) < 0 ||
333-
git_buf_joinpath(&ref_path, backend->path, ref_name) < 0)
334-
return -1;
333+
if ((error = packed_reload(backend)) < 0 ||
334+
(error = git_buf_joinpath(&ref_path, backend->path, ref_name)) < 0)
335+
return error;
335336

336337
*exists = git_path_isfile(ref_path.ptr) ||
337338
(git_sortedcache_lookup(backend->refcache, ref_name) != NULL);
@@ -409,8 +410,8 @@ static int packed_lookup(
409410
int error = 0;
410411
struct packref *entry;
411412

412-
if (packed_reload(backend) < 0)
413-
return -1;
413+
if ((error = packed_reload(backend)) < 0)
414+
return error;
414415

415416
if (git_sortedcache_rlock(backend->refcache) < 0)
416417
return -1;
@@ -615,13 +616,14 @@ static int refdb_fs_backend__iterator_next_name(
615616
static int refdb_fs_backend__iterator(
616617
git_reference_iterator **out, git_refdb_backend *_backend, const char *glob)
617618
{
619+
int error;
618620
refdb_fs_iter *iter;
619621
refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
620622

621623
assert(backend);
622624

623-
if (packed_reload(backend) < 0)
624-
return -1;
625+
if ((error = packed_reload(backend)) < 0)
626+
return error;
625627

626628
iter = git__calloc(1, sizeof(refdb_fs_iter));
627629
GITERR_CHECK_ALLOC(iter);
@@ -674,16 +676,18 @@ static int reference_path_available(
674676
int force)
675677
{
676678
size_t i;
679+
int error;
677680

678-
if (packed_reload(backend) < 0)
679-
return -1;
681+
if ((error = packed_reload(backend)) < 0)
682+
return error;
680683

681684
if (!force) {
682685
int exists;
683686

684-
if (refdb_fs_backend__exists(
685-
&exists, (git_refdb_backend *)backend, new_ref) < 0)
686-
return -1;
687+
if ((error = refdb_fs_backend__exists(
688+
&exists, (git_refdb_backend *)backend, new_ref)) < 0) {
689+
return error;
690+
}
687691

688692
if (exists) {
689693
giterr_set(GITERR_REFERENCE,
@@ -1164,8 +1168,7 @@ static int refdb_fs_backend__write(
11641168

11651169
assert(backend);
11661170

1167-
error = reference_path_available(backend, ref->name, NULL, force);
1168-
if (error < 0)
1171+
if ((error = reference_path_available(backend, ref->name, NULL, force)) < 0)
11691172
return error;
11701173

11711174
/* We need to perform the reflog append and old value check under the ref's lock */
@@ -1811,9 +1814,10 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co
18111814
* there maybe an obsolete/unused directory (or directory hierarchy) in the way.
18121815
*/
18131816
if (git_path_isdir(git_buf_cstr(&path))) {
1814-
if ((git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0))
1815-
error = -1;
1816-
else if (git_path_isdir(git_buf_cstr(&path))) {
1817+
if ((error = git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY)) < 0) {
1818+
if (error == GIT_ENOTFOUND)
1819+
error = 0;
1820+
} else if (git_path_isdir(git_buf_cstr(&path))) {
18171821
giterr_set(GITERR_REFERENCE, "cannot create reflog at '%s', there are reflogs beneath that folder",
18181822
ref->name);
18191823
error = GIT_EDIRECTORY;

tests/threads/refdb.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ static void *iterate_refs(void *arg)
2929
struct th_data *data = (struct th_data *) arg;
3030
git_reference_iterator *i;
3131
git_reference *ref;
32-
int count = 0;
32+
int count = 0, error;
3333
git_repository *repo;
3434

3535
cl_git_pass(git_repository_open(&repo, data->path));
36-
cl_git_pass(git_reference_iterator_new(&i, repo));
36+
do {
37+
error = git_reference_iterator_new(&i, repo);
38+
} while (error == GIT_ELOCKED);
39+
cl_git_pass(error);
3740

3841
for (count = 0; !git_reference_next(&ref, i); ++count) {
3942
cl_assert(ref != NULL);
@@ -61,11 +64,17 @@ static void *create_refs(void *arg)
6164

6265
cl_git_pass(git_repository_open(&repo, data->path));
6366

64-
cl_git_pass(git_reference_name_to_id(&head, repo, "HEAD"));
67+
do {
68+
error = git_reference_name_to_id(&head, repo, "HEAD");
69+
} while (error == GIT_ELOCKED);
70+
cl_git_pass(error);
6571

6672
for (i = 0; i < 10; ++i) {
6773
p_snprintf(name, sizeof(name), "refs/heads/thread-%03d-%02d", data->id, i);
68-
cl_git_pass(git_reference_create(&ref[i], repo, name, &head, 0, NULL));
74+
do {
75+
error = git_reference_create(&ref[i], repo, name, &head, 0, NULL);
76+
} while (error == GIT_ELOCKED);
77+
cl_git_pass(error);
6978

7079
if (i == 5) {
7180
git_refdb *refdb;

0 commit comments

Comments
 (0)