diff --git a/UI/win-update/updater/updater.cpp b/UI/win-update/updater/updater.cpp index 1bda84a135b724d349829df2d829a3319beecd88..ced9b8e7665db0482f0b20bb31d4cbb49a4c74f3 100644 --- a/UI/win-update/updater/updater.cpp +++ b/UI/win-update/updater/updater.cpp @@ -786,6 +786,41 @@ static void UpdateWithPatchIfAvailable(const char *name, const char *hash, } } +static bool MoveInUseFileAway(update_t &file) +{ + _TCHAR deleteMeName[MAX_PATH]; + _TCHAR randomStr[MAX_PATH]; + + BYTE junk[40]; + BYTE hash[BLAKE2_HASH_LENGTH]; + + CryptGenRandom(hProvider, sizeof(junk), junk); + blake2b(hash, sizeof(hash), junk, sizeof(junk), NULL, 0); + HashToString(hash, randomStr); + randomStr[8] = 0; + + StringCbCopy(deleteMeName, sizeof(deleteMeName), + file.outputPath.c_str()); + + StringCbCat(deleteMeName, sizeof(deleteMeName), L"."); + StringCbCat(deleteMeName, sizeof(deleteMeName), randomStr); + StringCbCat(deleteMeName, sizeof(deleteMeName), L".deleteme"); + + if (MoveFile(file.outputPath.c_str(), deleteMeName)) { + + if (MyCopyFile(deleteMeName, file.outputPath.c_str())) { + MoveFileEx(deleteMeName, NULL, + MOVEFILE_DELAY_UNTIL_REBOOT); + + return true; + } else { + MoveFile(deleteMeName, file.outputPath.c_str()); + } + } + + return false; +} + static bool UpdateFile(update_t &file) { wchar_t oldFileRenamedPath[MAX_PATH]; @@ -838,6 +873,9 @@ static bool UpdateFile(update_t &file) int error_code; bool installed_ok; + bool already_tried_to_move = false; + + retryAfterMovingFile: if (file.patchable) { error_code = ApplyPatch(file.tempPath.c_str(), @@ -877,15 +915,23 @@ static bool UpdateFile(update_t &file) int is_sharing_violation = (error_code == ERROR_SHARING_VIOLATION); - if (is_sharing_violation) + if (is_sharing_violation) { + if (!already_tried_to_move) { + already_tried_to_move = true; + + if (MoveInUseFileAway(file)) + goto retryAfterMovingFile; + } + Status(L"Update failed: %s is still in use. " L"Close all " L"programs and try again.", curFileName); - else + } else { Status(L"Update failed: Couldn't update %s " L"(error %d)", curFileName, GetLastError()); + } file.state = STATE_INSTALL_FAILED; return false;