Use MoveFileEx to rename files on Windows (not rename)
parent
29877dfb45
commit
c95734654c
|
@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "porting.h"
|
||||||
|
|
||||||
namespace fs
|
namespace fs
|
||||||
{
|
{
|
||||||
|
@ -698,22 +699,37 @@ bool safeWriteToFile(const std::string &path, const std::string &content)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rename_success = false;
|
||||||
|
|
||||||
// Move the finished temporary file over the real file
|
// Move the finished temporary file over the real file
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
// When creating the file, it can cause Windows Search indexer, virus scanners and other apps
|
||||||
|
// to query the file. This can make the move file call below fail.
|
||||||
|
// We retry up to 5 times, with a 1ms sleep between, before we consider the whole operation failed
|
||||||
|
int number_attempts = 0;
|
||||||
|
while (number_attempts < 5) {
|
||||||
|
rename_success = MoveFileEx(tmp_file.c_str(), path.c_str(),
|
||||||
|
MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
|
||||||
|
if (rename_success)
|
||||||
|
break;
|
||||||
|
sleep_ms(1);
|
||||||
|
++number_attempts;
|
||||||
|
}
|
||||||
|
#else
|
||||||
// On POSIX compliant systems rename() is specified to be able to swap the
|
// On POSIX compliant systems rename() is specified to be able to swap the
|
||||||
// file in place of the destination file, making this a truly error-proof
|
// file in place of the destination file, making this a truly error-proof
|
||||||
// transaction.
|
// transaction.
|
||||||
// However, on Windows, the target file has to be removed first.
|
rename_success = rename(tmp_file.c_str(), path.c_str()) == 0;
|
||||||
remove(path.c_str());
|
|
||||||
#endif
|
#endif
|
||||||
if(rename(tmp_file.c_str(), path.c_str())) {
|
if (!rename_success) {
|
||||||
|
warningstream << "Failed to write to file: " << path.c_str() << std::endl;
|
||||||
// Remove the temporary file because moving it over the target file
|
// Remove the temporary file because moving it over the target file
|
||||||
// failed.
|
// failed.
|
||||||
remove(tmp_file.c_str());
|
remove(tmp_file.c_str());
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Rename(const std::string &from, const std::string &to)
|
bool Rename(const std::string &from, const std::string &to)
|
||||||
|
|
Loading…
Reference in New Issue