Retry commits of file writes for up to a second to work around AV scanning
Poorly-written antivirus software briefly lock newly written files to scan them for viruses, which makes the rename from the temp file to actual file fail. Work around this by retrying the rename up to ten times. Closes #1620.
This commit is contained in:
parent
b77ca808d0
commit
af74371f6d
5 changed files with 31 additions and 8 deletions
|
@ -64,7 +64,18 @@ Save::Save(fs::path const& file, bool binary)
|
|||
|
||||
Save::~Save() {
|
||||
fp->close(); // Need to close before rename on Windows to unlock the file
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
try {
|
||||
fs::Rename(tmp_name, file_name);
|
||||
return;
|
||||
}
|
||||
catch (agi::fs::FileSystemError const&) {
|
||||
// Retry up to ten times in case it's just locked by a poorly-written antivirus scanner
|
||||
if (i == 9)
|
||||
throw;
|
||||
util::sleep_for(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
|
|
|
@ -70,5 +70,10 @@ namespace agi {
|
|||
}
|
||||
#endif
|
||||
|
||||
/// A thin wrapper around this_thread::sleep_for that uses std::thread on
|
||||
/// Windows (to avoid having to compile boost.thread) and boost::thread
|
||||
/// elsewhere (because libstcc++ 4.7 is missing it).
|
||||
void sleep_for(int ms);
|
||||
|
||||
} // namespace util
|
||||
} // namespace agi
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include "libaegisub/util.h"
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
namespace agi { namespace util {
|
||||
|
||||
timeval time_log() {
|
||||
|
@ -30,4 +32,8 @@ timeval time_log() {
|
|||
|
||||
void SetThreadName(const char *) { }
|
||||
|
||||
void sleep_for(int ms) {
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
#include "libaegisub/charset_conv_win.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
|
@ -99,5 +101,9 @@ void SetThreadName(LPCSTR szThreadName) {
|
|||
__except (EXCEPTION_CONTINUE_EXECUTION) {}
|
||||
}
|
||||
|
||||
void sleep_for(int ms) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace agi
|
||||
|
|
|
@ -50,13 +50,12 @@
|
|||
|
||||
#include <libaegisub/dispatch.h>
|
||||
#include <libaegisub/log.h>
|
||||
#include <libaegisub/util.h>
|
||||
|
||||
#include <boost/gil/gil_all.hpp>
|
||||
#include <boost/range/algorithm_ext/push_back.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
namespace {
|
||||
std::unique_ptr<agi::dispatch::Queue> cache_queue;
|
||||
|
@ -104,11 +103,7 @@ LibassSubtitlesProvider::LibassSubtitlesProvider(std::string)
|
|||
progress.Run([=](agi::ProgressSink *ps) {
|
||||
ps->SetIndeterminate();
|
||||
while (!*done && !ps->IsCancelled())
|
||||
#ifdef _MSC_VER
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
#else
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(250));
|
||||
#endif
|
||||
agi::util::sleep_for(250);
|
||||
});
|
||||
|
||||
ass_renderer = *renderer;
|
||||
|
|
Loading…
Reference in a new issue