From af74371f6d67f0f0acc57e894004d944742b3854 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Tue, 2 Jul 2013 19:49:45 -0700 Subject: [PATCH] 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. --- aegisub/libaegisub/common/io.cpp | 13 ++++++++++++- aegisub/libaegisub/include/libaegisub/util.h | 5 +++++ aegisub/libaegisub/unix/util.cpp | 6 ++++++ aegisub/libaegisub/windows/util_win.cpp | 6 ++++++ aegisub/src/subtitles_provider_libass.cpp | 9 ++------- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/aegisub/libaegisub/common/io.cpp b/aegisub/libaegisub/common/io.cpp index db5728daf..2baac82c0 100644 --- a/aegisub/libaegisub/common/io.cpp +++ b/aegisub/libaegisub/common/io.cpp @@ -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 - fs::Rename(tmp_name, file_name); + 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 diff --git a/aegisub/libaegisub/include/libaegisub/util.h b/aegisub/libaegisub/include/libaegisub/util.h index 602522617..26dd2970d 100644 --- a/aegisub/libaegisub/include/libaegisub/util.h +++ b/aegisub/libaegisub/include/libaegisub/util.h @@ -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 diff --git a/aegisub/libaegisub/unix/util.cpp b/aegisub/libaegisub/unix/util.cpp index 65c4a7c3a..c7d62701f 100644 --- a/aegisub/libaegisub/unix/util.cpp +++ b/aegisub/libaegisub/unix/util.cpp @@ -20,6 +20,8 @@ #include "libaegisub/util.h" +#include + 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)); +} + } } diff --git a/aegisub/libaegisub/windows/util_win.cpp b/aegisub/libaegisub/windows/util_win.cpp index 07283bd7f..dbac2819d 100644 --- a/aegisub/libaegisub/windows/util_win.cpp +++ b/aegisub/libaegisub/windows/util_win.cpp @@ -23,6 +23,8 @@ #include "libaegisub/charset_conv_win.h" +#include + #define WIN32_LEAN_AND_MEAN #include @@ -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 diff --git a/aegisub/src/subtitles_provider_libass.cpp b/aegisub/src/subtitles_provider_libass.cpp index 8f9922f58..700b4004d 100644 --- a/aegisub/src/subtitles_provider_libass.cpp +++ b/aegisub/src/subtitles_provider_libass.cpp @@ -50,13 +50,12 @@ #include #include +#include #include #include -#include #include #include -#include namespace { std::unique_ptr 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;