diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2016-03-10 22:01:09 +0100 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2016-11-14 11:35:38 +0100 |
commit | ce5553d48b8ba3510dd5032dfbfd161fb801cd77 (patch) | |
tree | 0d8cd5183cc431db35de00cc1b236b807183dea5 | |
parent | 7c32d874503ee43206cb5d2a8e65dbe23f18eaca (diff) | |
download | libgit2-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.c | 4 | ||||
-rw-r--r-- | src/refdb.c | 6 | ||||
-rw-r--r-- | src/refdb_fs.c | 38 | ||||
-rw-r--r-- | tests/threads/refdb.c | 17 |
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; |