1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-05 12:10:55 +00:00

Make Windows' safe save more resilient

This commit is contained in:
Pedro J. Estébanez
2023-08-25 18:28:35 +02:00
parent 6758a7f8c0
commit 49177b6eeb

View File

@@ -175,32 +175,27 @@ void FileAccessWindows::_close() {
f = nullptr; f = nullptr;
if (!save_path.is_empty()) { if (!save_path.is_empty()) {
bool rename_error = true;
int attempts = 4;
while (rename_error && attempts) {
// This workaround of trying multiple times is added to deal with paranoid Windows // 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 // antiviruses that love reading just written files even if they are not executable, thus
// locking the file and preventing renaming from happening. // locking the file and preventing renaming from happening.
#ifdef UWP_ENABLED bool rename_error = true;
// UWP has no PathFileExists, so we check attributes instead const Char16String &path_utf16 = path.utf16();
DWORD fileAttr; const Char16String &save_path_utf16 = save_path.utf16();
for (int i = 0; i < 1000; i++) {
fileAttr = GetFileAttributesW((LPCWSTR)(save_path.utf16().get_data())); if (ReplaceFileW((LPCWSTR)(save_path_utf16.get_data()), (LPCWSTR)(path_utf16.get_data()), nullptr, REPLACEFILE_IGNORE_MERGE_ERRORS | REPLACEFILE_IGNORE_ACL_ERRORS, nullptr, nullptr)) {
if (INVALID_FILE_ATTRIBUTES == fileAttr) { rename_error = false;
#else
if (!PathFileExistsW((LPCWSTR)(save_path.utf16().get_data()))) {
#endif
// Creating new file
rename_error = _wrename((LPCWSTR)(path.utf16().get_data()), (LPCWSTR)(save_path.utf16().get_data())) != 0;
} else { } else {
// Atomic replace for existing file // Either the target exists and is locked (temporarily, hopefully)
rename_error = !ReplaceFileW((LPCWSTR)(save_path.utf16().get_data()), (LPCWSTR)(path.utf16().get_data()), nullptr, 2 | 4, nullptr, nullptr); // or it doesn't exist; let's assume the latter before re-trying.
rename_error = _wrename((LPCWSTR)(path_utf16.get_data()), (LPCWSTR)(save_path_utf16.get_data())) != 0;
} }
if (rename_error) {
attempts--; if (!rename_error) {
OS::get_singleton()->delay_usec(100000); // wait 100msec and try again break;
} }
OS::get_singleton()->delay_usec(1000);
} }
if (rename_error) { if (rename_error) {