Make WriteFile replace rather than overwrite
This preserves old file if writing the new one fails for some reason.
This commit is contained in:
parent
163203b321
commit
a7d8ecc6e3
@ -1,5 +1,6 @@
|
|||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
#include "tpt-rand.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -186,9 +187,14 @@ bool RemoveFile(ByteString filename)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenameFile(ByteString filename, ByteString newFilename)
|
bool RenameFile(ByteString filename, ByteString newFilename, bool replace)
|
||||||
{
|
{
|
||||||
#ifdef WIN
|
#ifdef WIN
|
||||||
|
if (replace)
|
||||||
|
{
|
||||||
|
// TODO: we rely on errno but errors from this are available through GetLastError(); fix
|
||||||
|
return MoveFileExW(WinWiden(filename).c_str(), WinWiden(newFilename).c_str(), MOVEFILE_REPLACE_EXISTING);
|
||||||
|
}
|
||||||
return _wrename(WinWiden(filename).c_str(), WinWiden(newFilename).c_str()) == 0;
|
return _wrename(WinWiden(filename).c_str(), WinWiden(newFilename).c_str()) == 0;
|
||||||
#else
|
#else
|
||||||
return rename(filename.c_str(), newFilename.c_str()) == 0;
|
return rename(filename.c_str(), newFilename.c_str()) == 0;
|
||||||
@ -335,16 +341,43 @@ bool ReadFile(std::vector<char> &fileData, ByteString filename)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteFile(std::vector<char> fileData, ByteString filename, bool replaceAtomically)
|
bool WriteFile(const std::vector<char> &fileData, ByteString filename)
|
||||||
{
|
{
|
||||||
// TODO: replaceAtomically
|
auto replace = FileExists(filename);
|
||||||
std::ofstream f(filename, std::ios::binary);
|
auto writeFileName = filename;
|
||||||
if (f) f.write(&fileData[0], fileData.size());
|
if (replace)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
writeFileName = ByteString::Build(filename, ".temp.", random_gen() % 100000);
|
||||||
|
if (!FileExists(writeFileName))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::ofstream f(writeFileName, std::ios::binary);
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
f.write(&fileData[0], fileData.size());
|
||||||
|
}
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
std::cerr << "WriteFile: " << filename << ": " << strerror(errno) << std::endl;
|
std::cerr << "WriteFile: " << filename << ": " << strerror(errno) << std::endl;
|
||||||
|
if (replace)
|
||||||
|
{
|
||||||
|
RemoveFile(writeFileName);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (replace)
|
||||||
|
{
|
||||||
|
if (!RenameFile(writeFileName, filename, true))
|
||||||
|
{
|
||||||
|
RemoveFile(writeFileName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ namespace Platform
|
|||||||
* @return true on success
|
* @return true on success
|
||||||
*/
|
*/
|
||||||
bool RemoveFile(ByteString filename);
|
bool RemoveFile(ByteString filename);
|
||||||
bool RenameFile(ByteString filename, ByteString newFilename);
|
bool RenameFile(ByteString filename, ByteString newFilename, bool replace = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true on success
|
* @return true on success
|
||||||
@ -35,7 +35,7 @@ namespace Platform
|
|||||||
std::vector<ByteString> DirectorySearch(ByteString directory, ByteString search, std::vector<ByteString> extensions);
|
std::vector<ByteString> DirectorySearch(ByteString directory, ByteString search, std::vector<ByteString> extensions);
|
||||||
|
|
||||||
bool ReadFile(std::vector<char> &fileData, ByteString filename);
|
bool ReadFile(std::vector<char> &fileData, ByteString filename);
|
||||||
bool WriteFile(std::vector<char> fileData, ByteString filename, bool replaceAtomically = false); // TODO: Revisit call sites, remove default.
|
bool WriteFile(const std::vector<char> &fileData, ByteString filename);
|
||||||
|
|
||||||
ByteString WinNarrow(const std::wstring &source);
|
ByteString WinNarrow(const std::wstring &source);
|
||||||
std::wstring WinWiden(const ByteString &source);
|
std::wstring WinWiden(const ByteString &source);
|
||||||
|
@ -47,7 +47,7 @@ void Prefs::Write()
|
|||||||
Json::StreamWriterBuilder wbuilder;
|
Json::StreamWriterBuilder wbuilder;
|
||||||
wbuilder["indentation"] = "\t";
|
wbuilder["indentation"] = "\t";
|
||||||
ByteString data = Json::writeString(wbuilder, root);
|
ByteString data = Json::writeString(wbuilder, root);
|
||||||
if (!Platform::WriteFile(std::vector<char>(data.begin(), data.end()), path, true))
|
if (!Platform::WriteFile(std::vector<char>(data.begin(), data.end()), path))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user