summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2016-03-10 22:01:09 +0100
committerCarlos Martín Nieto <cmn@dwim.me>2016-11-14 11:35:38 +0100
commitce5553d48b8ba3510dd5032dfbfd161fb801cd77 (patch)
tree0d8cd5183cc431db35de00cc1b236b807183dea5
parent7c32d874503ee43206cb5d2a8e65dbe23f18eaca (diff)
downloadlibgit2-ce5553d48b8ba3510dd5032dfbfd161fb801cd77.tar.gz
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.
-rw-r--r--src/path.c4
-rw-r--r--src/refdb.c6
-rw-r--r--src/refdb_fs.c38
-rw-r--r--tests/threads/refdb.c17
4 files changed, 42 insertions, 23 deletions
diff --git a/src/path.c b/src/path.c
index f91e42242..2b1a9622e 100644
--- a/src/path.c
+++ b/src/path.c
@@ -644,6 +644,10 @@ int git_path_set_error(int errno_value, const char *path, const char *action)
giterr_set(GITERR_OS, "Failed %s - '%s' already exists", action, path);
return GIT_EEXISTS;
+ case EACCES:
+ giterr_set(GITERR_OS, "Failed %s - '%s' is locked", action, path);
+ return GIT_ELOCKED;
+
default:
giterr_set(GITERR_OS, "Could not %s '%s'", action, path);
return -1;
diff --git a/src/refdb.c b/src/refdb.c
index debba1276..85c84892b 100644
--- a/src/refdb.c
+++ b/src/refdb.c
@@ -125,13 +125,15 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name)
int git_refdb_iterator(git_reference_iterator **out, git_refdb *db, const char *glob)
{
+ int error;
+
if (!db->backend || !db->backend->iterator) {
giterr_set(GITERR_REFERENCE, "This backend doesn't support iterators");
return -1;
}
- if (db->backend->iterator(out, db->backend, glob) < 0)
- return -1;
+ if ((error = db->backend->iterator(out, db->backend, glob)) < 0)
+ return error;
GIT_REFCOUNT_INC(db);
(*out)->db = db;
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index ab309c841..7601aa0ac 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -326,12 +326,13 @@ static int refdb_fs_backend__exists(
{
refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
git_buf ref_path = GIT_BUF_INIT;
+ int error;
assert(backend);
- if (packed_reload(backend) < 0 ||
- git_buf_joinpath(&ref_path, backend->path, ref_name) < 0)
- return -1;
+ if ((error = packed_reload(backend)) < 0 ||
+ (error = git_buf_joinpath(&ref_path, backend->path, ref_name)) < 0)
+ return error;
*exists = git_path_isfile(ref_path.ptr) ||
(git_sortedcache_lookup(backend->refcache, ref_name) != NULL);
@@ -409,8 +410,8 @@ static int packed_lookup(
int error = 0;
struct packref *entry;
- if (packed_reload(backend) < 0)
- return -1;
+ if ((error = packed_reload(backend)) < 0)
+ return error;
if (git_sortedcache_rlock(backend->refcache) < 0)
return -1;
@@ -615,13 +616,14 @@ static int refdb_fs_backend__iterator_next_name(
static int refdb_fs_backend__iterator(
git_reference_iterator **out, git_refdb_backend *_backend, const char *glob)
{
+ int error;
refdb_fs_iter *iter;
refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
assert(backend);
- if (packed_reload(backend) < 0)
- return -1;
+ if ((error = packed_reload(backend)) < 0)
+ return error;
iter = git__calloc(1, sizeof(refdb_fs_iter));
GITERR_CHECK_ALLOC(iter);
@@ -674,16 +676,18 @@ static int reference_path_available(
int force)
{
size_t i;
+ int error;
- if (packed_reload(backend) < 0)
- return -1;
+ if ((error = packed_reload(backend)) < 0)
+ return error;
if (!force) {
int exists;
- if (refdb_fs_backend__exists(
- &exists, (git_refdb_backend *)backend, new_ref) < 0)
- return -1;
+ if ((error = refdb_fs_backend__exists(
+ &exists, (git_refdb_backend *)backend, new_ref)) < 0) {
+ return error;
+ }
if (exists) {
giterr_set(GITERR_REFERENCE,
@@ -1164,8 +1168,7 @@ static int refdb_fs_backend__write(
assert(backend);
- error = reference_path_available(backend, ref->name, NULL, force);
- if (error < 0)
+ if ((error = reference_path_available(backend, ref->name, NULL, force)) < 0)
return error;
/* 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
* there maybe an obsolete/unused directory (or directory hierarchy) in the way.
*/
if (git_path_isdir(git_buf_cstr(&path))) {
- if ((git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY) < 0))
- error = -1;
- else if (git_path_isdir(git_buf_cstr(&path))) {
+ if ((error = git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_RMDIR_SKIP_NONEMPTY)) < 0) {
+ if (error == GIT_ENOTFOUND)
+ error = 0;
+ } else if (git_path_isdir(git_buf_cstr(&path))) {
giterr_set(GITERR_REFERENCE, "cannot create reflog at '%s', there are reflogs beneath that folder",
ref->name);
error = GIT_EDIRECTORY;
diff --git a/tests/threads/refdb.c b/tests/threads/refdb.c
index d8dc77ba5..ae1a935de 100644
--- a/tests/threads/refdb.c
+++ b/tests/threads/refdb.c
@@ -29,11 +29,14 @@ static void *iterate_refs(void *arg)
struct th_data *data = (struct th_data *) arg;
git_reference_iterator *i;
git_reference *ref;
- int count = 0;
+ int count = 0, error;
git_repository *repo;
cl_git_pass(git_repository_open(&repo, data->path));
- cl_git_pass(git_reference_iterator_new(&i, repo));
+ do {
+ error = git_reference_iterator_new(&i, repo);
+ } while (error == GIT_ELOCKED);
+ cl_git_pass(error);
for (count = 0; !git_reference_next(&ref, i); ++count) {
cl_assert(ref != NULL);
@@ -61,11 +64,17 @@ static void *create_refs(void *arg)
cl_git_pass(git_repository_open(&repo, data->path));
- cl_git_pass(git_reference_name_to_id(&head, repo, "HEAD"));
+ do {
+ error = git_reference_name_to_id(&head, repo, "HEAD");
+ } while (error == GIT_ELOCKED);
+ cl_git_pass(error);
for (i = 0; i < 10; ++i) {
p_snprintf(name, sizeof(name), "refs/heads/thread-%03d-%02d", data->id, i);
- cl_git_pass(git_reference_create(&ref[i], repo, name, &head, 0, NULL));
+ do {
+ error = git_reference_create(&ref[i], repo, name, &head, 0, NULL);
+ } while (error == GIT_ELOCKED);
+ cl_git_pass(error);
if (i == 5) {
git_refdb *refdb;