diff options
author | Patrick Steinhardt <ps@pks.im> | 2019-02-15 10:15:39 +0100 |
---|---|---|
committer | Patrick Steinhardt <ps@pks.im> | 2019-02-15 11:22:38 +0100 |
commit | 8c77343871c1d8c6a2cc1149143d3577c0ccfc43 (patch) | |
tree | 12081605103f7b9bd885322f997c80533f8dcc6c | |
parent | bda0839734bad8351e1dbc9c7beb8ae1f00d831e (diff) | |
download | libgit2-8c77343871c1d8c6a2cc1149143d3577c0ccfc43.tar.gz |
refdb_fs: fix potential race with ref repacking in `exists` callback
When repacking references, git.git will first update the packed refs and only
afterwards delete any existing loose references that have now been moved to the
new packed refs file. Due to this, there is a potential for racing if one first
reads the packfile (which has not been updated yet) and only then trying to read
the loose reference (which has just been deleted). In this case, one will
incorrectly fail to lookup the reference and it will be reported as missing.
Naturally, this is exactly what we've been doing in `refdb_fs_backend__exists`.
Fix the race by reversing the lookup: we will now first check if the loose
reference exists and only afterwards refresh the packed file.
-rw-r--r-- | src/refdb_fs.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/src/refdb_fs.c b/src/refdb_fs.c index d582cb8a2..7d987b4cd 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -333,15 +333,27 @@ static int refdb_fs_backend__exists( assert(backend); - if ((error = packed_reload(backend)) < 0 || - (error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0) - return error; + *exists = 0; + + if ((error = git_buf_joinpath(&ref_path, backend->gitpath, ref_name)) < 0) + goto out; + + if (git_path_isfile(ref_path.ptr)) { + *exists = 1; + goto out; + } + + if ((error = packed_reload(backend)) < 0) + goto out; - *exists = git_path_isfile(ref_path.ptr) || - (git_sortedcache_lookup(backend->refcache, ref_name) != NULL); + if (git_sortedcache_lookup(backend->refcache, ref_name) != NULL) { + *exists = 1; + goto out; + } +out: git_buf_dispose(&ref_path); - return 0; + return error; } static const char *loose_parse_symbolic(git_buf *file_content) |