summaryrefslogtreecommitdiff
path: root/src/fileops.c
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2017-03-22 20:29:22 +0000
committerGitHub <noreply@github.com>2017-03-22 20:29:22 +0000
commit6fd6c67824d2caad9f8716a676820d8319f79a9d (patch)
tree00393d0a78fe42c3c007ca71e8da50374781d437 /src/fileops.c
parent7e53e8ce454b31e933b7ad6df90ffdfdc678cd81 (diff)
parent1c04a96b25da048221f31ecee0227d960dc00489 (diff)
downloadlibgit2-6fd6c67824d2caad9f8716a676820d8319f79a9d.tar.gz
Merge pull request #4030 from libgit2/ethomson/fsync
fsync all the things
Diffstat (limited to 'src/fileops.c')
-rw-r--r--src/fileops.c53
1 files changed, 50 insertions, 3 deletions
diff --git a/src/fileops.c b/src/fileops.c
index acb3b87e3..28f414f23 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -236,10 +236,16 @@ int git_futils_readbuffer(git_buf *buf, const char *path)
int git_futils_writebuffer(
const git_buf *buf, const char *path, int flags, mode_t mode)
{
- int fd, error = 0;
+ int fd, do_fsync = 0, error = 0;
- if (flags <= 0)
+ if (!flags)
flags = O_CREAT | O_TRUNC | O_WRONLY;
+
+ if ((flags & O_FSYNC) != 0)
+ do_fsync = 1;
+
+ flags &= ~O_FSYNC;
+
if (!mode)
mode = GIT_FILEMODE_BLOB;
@@ -254,8 +260,19 @@ int git_futils_writebuffer(
return error;
}
- if ((error = p_close(fd)) < 0)
+ if (do_fsync && (error = p_fsync(fd)) < 0) {
+ giterr_set(GITERR_OS, "could not fsync '%s'", path);
+ p_close(fd);
+ return error;
+ }
+
+ if ((error = p_close(fd)) < 0) {
giterr_set(GITERR_OS, "error while closing '%s'", path);
+ return error;
+ }
+
+ if (do_fsync && (flags & O_CREAT))
+ error = git_futils_fsync_parent(path);
return error;
}
@@ -1108,3 +1125,33 @@ void git_futils_filestamp_set_from_stat(
memset(stamp, 0, sizeof(*stamp));
}
}
+
+int git_futils_fsync_dir(const char *path)
+{
+#ifdef GIT_WIN32
+ GIT_UNUSED(path);
+ return 0;
+#else
+ int fd, error = -1;
+
+ if ((fd = p_open(path, O_RDONLY)) < 0) {
+ giterr_set(GITERR_OS, "failed to open directory '%s' for fsync", path);
+ return -1;
+ }
+
+ if ((error = p_fsync(fd)) < 0)
+ giterr_set(GITERR_OS, "failed to fsync directory '%s'", path);
+
+ p_close(fd);
+ return error;
+#endif
+}
+
+int git_futils_fsync_parent(const char *path)
+{
+ char *parent = git_path_dirname(path);
+ int error = git_futils_fsync_dir(parent);
+
+ git__free(parent);
+ return error;
+}