From 9f1827dc2484be34bbbb3c01720d662635254882 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Mon, 18 Aug 2014 15:51:37 +0200 Subject: [PATCH] Make app setting file writes durable The atomic write replaces the old with the new file, but unless we sync the parent directory, that replacement is not permanent yet. --- src/linkapp.cpp | 12 +++++++++++- src/utilities.cpp | 25 +++++++++++++++++++++++++ src/utilities.h | 6 ++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/linkapp.cpp b/src/linkapp.cpp index 000971a..aa12194 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -348,7 +348,17 @@ bool LinkApp::save() { if (out.tellp() > 0) { DEBUG("Saving app settings: %s\n", file.c_str()); - return writeStringToFile(file, out.str()); + if (writeStringToFile(file, out.str())) { + string dir = parentDir(file); + if (!syncDir(dir)) { + ERROR("Failed to sync dir: %s\n", dir.c_str()); + // Note: Even if syncDir fails, the app settings have been + // written, so have save() return true. + } + return true; + } else { + return false; + } } else { DEBUG("Empty app settings: %s\n", file.c_str()); return unlink(file.c_str()) == 0 || errno == ENOENT; diff --git a/src/utilities.cpp b/src/utilities.cpp index e66ca15..7663778 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -112,6 +112,31 @@ bool writeStringToFile(string const& filename, string const& data) { return ok; } +constexpr int dirOpenFlags = +#ifdef O_DIRECTORY + O_DIRECTORY | O_RDONLY; // Linux specific +#else + O_RDONLY; +#endif + +bool syncDir(string const& dirname) +{ + int fd = open(dirname.c_str(), dirOpenFlags); + if (fd < 0) { + return false; + } + + bool ok = fsync(fd) == 0; + + while (close(fd)) { + if (errno != EINTR) { + return false; + } + } + + return ok; +} + string parentDir(string const& dir) { // Note that size() is unsigned, so for short strings the '- 2' wraps // around and as a result the entire string is searched, which is fine. diff --git a/src/utilities.h b/src/utilities.h index a4873d2..0fc76b2 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -57,6 +57,12 @@ std::string readFileAsString(std::string const& filename); */ bool writeStringToFile(std::string const& filename, std::string const& data); +/** + * Tells the file system to commit the given directory to disk. + * @return True iff the sync was successful. + */ +bool syncDir(std::string const& dirname); + std::string strreplace(std::string orig, const std::string &search, const std::string &replace); std::string cmdclean(std::string cmdline);