Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Try to atomically save config files.
  • Loading branch information
comex committed Oct 15, 2013
1 parent f3af8ee commit 72c1e14
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 4 deletions.
67 changes: 65 additions & 2 deletions Source/Core/Common/Src/FileUtil.cpp
Expand Up @@ -21,7 +21,9 @@
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <libgen.h>
#endif
#include <fcntl.h>

#if defined(__APPLE__)
#include <CoreFoundation/CFString.h>
Expand Down Expand Up @@ -242,16 +244,62 @@ bool Rename(const std::string &srcFilename, const std::string &destFilename)
INFO_LOG(COMMON, "Rename: %s --> %s",
srcFilename.c_str(), destFilename.c_str());
#ifdef _WIN32
if (_trename(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str()) == 0)
auto sf = UTF8ToTStr(srcFilename).c_str();
auto df = UTF8ToTStr(destFilename).c_str();
// The Internet seems torn about whether ReplaceFile is atomic or not.
// Hopefully it's atomic enough...
if (ReplaceFile(df, sf, NULL, REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL))
return true;
// Might have failed because the destination doesn't exist.
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
if (MoveFile(sf, df))
return true;
}
#else
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
#endif
return true;
#endif
ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s",
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
return false;
}

#ifndef _WIN32
static void FSyncPath(const char *path)
{
int fd = open(path, O_RDONLY);
if (fd != -1)
{
fsync(fd);
close(fd);
}
}
#endif

bool RenameSync(const std::string &srcFilename, const std::string &destFilename)
{
if (!Rename(srcFilename, destFilename))
return false;
#ifdef _WIN32
int fd = _topen(UTF8ToTStr(srcFilename).c_str(), _O_RDONLY);
if (fd != -1)
{
_commit(fd);
close(fd);
}
#else
char *path = strdup(srcFilename.c_str());
FSyncPath(path);
FSyncPath(dirname(path));
free(path);
path = strdup(destFilename.c_str());
FSyncPath(dirname(path));
free(path);
#endif
return true;
}

// copies file srcFilename to destFilename, returns true on success
bool Copy(const std::string &srcFilename, const std::string &destFilename)
{
Expand Down Expand Up @@ -627,6 +675,21 @@ bool SetCurrentDir(const std::string &directory)
return __chdir(directory.c_str()) == 0;
}

std::string GetTempFilenameForAtomicWrite(const std::string &path)
{
std::string abs = path;
#ifdef _WIN32
TCHAR absbuf[MAX_PATH];
if (_tfullpath(absbuf, UTF8ToTStr(path).c_str(), MAX_PATH) != NULL)
abs = TStrToUTF8(absbuf);
#else
char absbuf[PATH_MAX];
if (realpath(path.c_str(), absbuf) != NULL)
abs = absbuf;
#endif
return abs + ".xxx";
}

#if defined(__APPLE__)
std::string GetBundleDirectory()
{
Expand Down
6 changes: 6 additions & 0 deletions Source/Core/Common/Src/FileUtil.h
Expand Up @@ -97,6 +97,9 @@ bool DeleteDir(const std::string &filename);
// renames file srcFilename to destFilename, returns true on success
bool Rename(const std::string &srcFilename, const std::string &destFilename);

// ditto, but syncs the source file and, on Unix, syncs the directories after rename
bool RenameSync(const std::string &srcFilename, const std::string &destFilename);

// copies file srcFilename to destFilename, returns true on success
bool Copy(const std::string &srcFilename, const std::string &destFilename);

Expand All @@ -119,6 +122,9 @@ void CopyDir(const std::string &source_path, const std::string &dest_path);
// Set the current directory to given directory
bool SetCurrentDir(const std::string &directory);

// Get a filename that can hopefully be atomically renamed to the given path.
std::string GetTempFilenameForAtomicWrite(const std::string &path);

// Returns a pointer to a string with a Dolphin data dir in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
Expand Down
5 changes: 3 additions & 2 deletions Source/Core/Common/Src/IniFile.cpp
Expand Up @@ -391,7 +391,8 @@ bool IniFile::Load(const char* filename, bool keep_current_data)
bool IniFile::Save(const char* filename)
{
std::ofstream out;
OpenFStream(out, filename, std::ios::out);
std::string temp = File::GetTempFilenameForAtomicWrite(filename);
OpenFStream(out, temp, std::ios::out);

if (out.fail())
{
Expand Down Expand Up @@ -425,7 +426,7 @@ bool IniFile::Save(const char* filename)

out.close();

return true;
return File::RenameSync(temp, filename);
}


Expand Down

0 comments on commit 72c1e14

Please sign in to comment.