From e56b3439a5e8bf56c4b843e044a96f1446564745 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 12 Jan 2018 17:03:08 -0300 Subject: [PATCH] Attempt renaming multiple times on safe file save, and make the behavior optional. Fixes #14339. --- drivers/windows/file_access_windows.cpp | 39 ++++++++++++++++--------- editor/editor_node.cpp | 2 +- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index dbffac8ebd8..832d75b17d5 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -31,6 +31,7 @@ #ifdef WINDOWS_ENABLED #include "file_access_windows.h" +#include "os/os.h" #include "shlwapi.h" #include @@ -115,25 +116,35 @@ void FileAccessWindows::close() { //_wunlink(save_path.c_str()); //unlink if exists //int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str()); - bool rename_error; + bool rename_error = true; + int attempts = 4; + while (rename_error && attempts) { + // This workaround of trying multiple times is added to deal with paranoid Windows + // antiviruses that love reading just written files even if they are not executable, thus + // locking the file and preventing renaming from happening. #ifdef UWP_ENABLED - // UWP has no PathFileExists, so we check attributes instead - DWORD fileAttr; + // UWP has no PathFileExists, so we check attributes instead + DWORD fileAttr; - fileAttr = GetFileAttributesW(save_path.c_str()); - if (INVALID_FILE_ATTRIBUTES == fileAttr) { + fileAttr = GetFileAttributesW(save_path.c_str()); + if (INVALID_FILE_ATTRIBUTES == fileAttr) { #else - if (!PathFileExistsW(save_path.c_str())) { + if (!PathFileExistsW(save_path.c_str())) { #endif - //creating new file - rename_error = _wrename((save_path + ".tmp").c_str(), save_path.c_str()) != 0; - } else { - //atomic replace for existing file - rename_error = !ReplaceFileW(save_path.c_str(), (save_path + ".tmp").c_str(), NULL, 2 | 4, NULL, NULL); - } - if (rename_error && close_fail_notify) { - close_fail_notify(save_path); + //creating new file + rename_error = _wrename((save_path + ".tmp").c_str(), save_path.c_str()) != 0; + } else { + //atomic replace for existing file + rename_error = !ReplaceFileW(save_path.c_str(), (save_path + ".tmp").c_str(), NULL, 2 | 4, NULL, NULL); + } + if (rename_error && close_fail_notify) { + close_fail_notify(save_path); + } + if (rename_error) { + attempts--; + OS::get_singleton()->delay_usec(1000000); //wait 100msec and try again + } } save_path = ""; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 2b62faf2180..7a83a5ede12 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -4749,7 +4749,7 @@ EditorNode::EditorNode() { scene_distraction = false; script_distraction = false; - FileAccess::set_backup_save(true); + FileAccess::set_backup_save(EDITOR_DEF("filesystem/on_save/safe_save_on_backup_then_rename", true)); TranslationServer::get_singleton()->set_enabled(false); // load settings