mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
Try to atomically save config files.
This commit is contained in:
@ -21,7 +21,9 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <libgen.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#include <CoreFoundation/CFString.h>
|
#include <CoreFoundation/CFString.h>
|
||||||
@ -242,16 +244,62 @@ bool Rename(const std::string &srcFilename, const std::string &destFilename)
|
|||||||
INFO_LOG(COMMON, "Rename: %s --> %s",
|
INFO_LOG(COMMON, "Rename: %s --> %s",
|
||||||
srcFilename.c_str(), destFilename.c_str());
|
srcFilename.c_str(), destFilename.c_str());
|
||||||
#ifdef _WIN32
|
#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
|
#else
|
||||||
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
|
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
|
#endif
|
||||||
ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s",
|
ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s",
|
||||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||||
return false;
|
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
|
// copies file srcFilename to destFilename, returns true on success
|
||||||
bool Copy(const std::string &srcFilename, const std::string &destFilename)
|
bool Copy(const std::string &srcFilename, const std::string &destFilename)
|
||||||
{
|
{
|
||||||
@ -627,6 +675,21 @@ bool SetCurrentDir(const std::string &directory)
|
|||||||
return __chdir(directory.c_str()) == 0;
|
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__)
|
#if defined(__APPLE__)
|
||||||
std::string GetBundleDirectory()
|
std::string GetBundleDirectory()
|
||||||
{
|
{
|
||||||
|
@ -97,6 +97,9 @@ bool DeleteDir(const std::string &filename);
|
|||||||
// renames file srcFilename to destFilename, returns true on success
|
// renames file srcFilename to destFilename, returns true on success
|
||||||
bool Rename(const std::string &srcFilename, const std::string &destFilename);
|
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
|
// copies file srcFilename to destFilename, returns true on success
|
||||||
bool Copy(const std::string &srcFilename, const std::string &destFilename);
|
bool Copy(const std::string &srcFilename, const std::string &destFilename);
|
||||||
|
|
||||||
@ -119,6 +122,9 @@ void CopyDir(const std::string &source_path, const std::string &dest_path);
|
|||||||
// Set the current directory to given directory
|
// Set the current directory to given directory
|
||||||
bool SetCurrentDir(const std::string &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
|
// 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).
|
// directory. To be used in "multi-user" mode (that is, installed).
|
||||||
const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
|
const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
|
||||||
|
@ -391,7 +391,8 @@ bool IniFile::Load(const char* filename, bool keep_current_data)
|
|||||||
bool IniFile::Save(const char* filename)
|
bool IniFile::Save(const char* filename)
|
||||||
{
|
{
|
||||||
std::ofstream out;
|
std::ofstream out;
|
||||||
OpenFStream(out, filename, std::ios::out);
|
std::string temp = File::GetTempFilenameForAtomicWrite(filename);
|
||||||
|
OpenFStream(out, temp, std::ios::out);
|
||||||
|
|
||||||
if (out.fail())
|
if (out.fail())
|
||||||
{
|
{
|
||||||
@ -425,7 +426,7 @@ bool IniFile::Save(const char* filename)
|
|||||||
|
|
||||||
out.close();
|
out.close();
|
||||||
|
|
||||||
return true;
|
return File::RenameSync(temp, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user