summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2015-12-31 14:51:42 +0000
committerCarlos Martín Nieto <cmn@dwim.me>2016-11-14 11:35:38 +0100
commit40ffa07f4ff3616acb814ff3ef93df7206f5b5c5 (patch)
treea6c7f356f629eaeb1ff4faedcfcddfb6feb91d28
parent26416f6d20044d693ddfb57d719ee5183c065fc5 (diff)
downloadlibgit2-40ffa07f4ff3616acb814ff3ef93df7206f5b5c5.tar.gz
sortedcache: check file size after opening the file
Checking the size before we open the file descriptor can lead to the file being replaced from under us when renames aren't quite atomic, so we can end up reading too little of the file, leading to us thinking the file is corrupted.
-rw-r--r--src/sortedcache.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/src/sortedcache.c b/src/sortedcache.c
index 5c2a167a7..ed4199b71 100644
--- a/src/sortedcache.c
+++ b/src/sortedcache.c
@@ -200,6 +200,7 @@ void git_sortedcache_runlock(git_sortedcache *sc)
int git_sortedcache_lockandload(git_sortedcache *sc, git_buf *buf)
{
int error, fd;
+ struct stat st;
if ((error = git_sortedcache_wlock(sc)) < 0)
return error;
@@ -207,19 +208,26 @@ int git_sortedcache_lockandload(git_sortedcache *sc, git_buf *buf)
if ((error = git_futils_filestamp_check(&sc->stamp, sc->path)) <= 0)
goto unlock;
- if (!git__is_sizet(sc->stamp.size)) {
- giterr_set(GITERR_INVALID, "Unable to load file larger than size_t");
+ if ((fd = git_futils_open_ro(sc->path)) < 0) {
+ error = fd;
+ goto unlock;
+ }
+
+ if (p_fstat(fd, &st) < 0) {
+ giterr_set(GITERR_OS, "failed to stat file");
error = -1;
goto unlock;
}
- if ((fd = git_futils_open_ro(sc->path)) < 0) {
- error = fd;
+ if (!git__is_sizet(st.st_size)) {
+ giterr_set(GITERR_INVALID, "Unable to load file larger than size_t");
+ error = -1;
+ (void)p_close(fd);
goto unlock;
}
if (buf)
- error = git_futils_readbuffer_fd(buf, fd, (size_t)sc->stamp.size);
+ error = git_futils_readbuffer_fd(buf, fd, (size_t)st.st_size);
(void)p_close(fd);