Browse Source

Attempt renaming multiple times on safe file save, and make the behavior optional. Fixes #14339.

Juan Linietsky 7 năm trước cách đây
mục cha
commit
e56b3439a5
2 tập tin đã thay đổi với 26 bổ sung15 xóa
  1. 25 14
      drivers/windows/file_access_windows.cpp
  2. 1 1
      editor/editor_node.cpp

+ 25 - 14
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 <windows.h>
 
@@ -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 = "";

+ 1 - 1
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