mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 09:33:25 -08:00
[Installer] Recover payload files when previous uninstaller is missing or fails to launch (#7682)
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 cover (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Desktop / Prune caches (push) Waiting to run
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 cover (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Desktop / Prune caches (push) Waiting to run
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com>
This commit is contained in:
parent
06da7f815a
commit
9e50c5ad6e
1 changed files with 98 additions and 21 deletions
|
|
@ -15,10 +15,14 @@ Var ReinstallMode
|
||||||
Var GuardDir
|
Var GuardDir
|
||||||
Var OldUninstallString
|
Var OldUninstallString
|
||||||
Var OldInstallDir
|
Var OldInstallDir
|
||||||
; What ExecWait reported for the previous version's uninstaller (empty when it could not be
|
; What ExecWait reported for the previous version's uninstaller, or "missing" /
|
||||||
; started at all). Read by WaitForOldPayloadToDisappear: an uninstaller that ran in place
|
; "launch-failed" when RunOldUninstaller could not start it. Read by WaitForOldPayloadToDisappear: an uninstaller that ran in place
|
||||||
; (_?=) and failed or was cancelled will not remove anything more, however long we wait.
|
; (_?=) and failed or was cancelled will not remove anything more, however long we wait.
|
||||||
Var OldUninstallExit
|
Var OldUninstallExit
|
||||||
|
; Executable path parsed out of $OldUninstallString by ResolveOldUninstallExe. Used to
|
||||||
|
; tell an uninstaller that is missing or cannot be started ("missing" / "launch-failed"
|
||||||
|
; in $OldUninstallExit) from one that ran and failed.
|
||||||
|
Var OldUninstallExe
|
||||||
; Set to 1 by RemoveOldPayloadLeftovers only when every leftover it is responsible for is
|
; Set to 1 by RemoveOldPayloadLeftovers only when every leftover it is responsible for is
|
||||||
; gone; WaitForOldPayloadToDisappear aborts while it is still 0.
|
; gone; WaitForOldPayloadToDisappear aborts while it is still 0.
|
||||||
Var OldPayloadRemoved
|
Var OldPayloadRemoved
|
||||||
|
|
@ -397,6 +401,61 @@ ${If} $ReinstallMode = 1
|
||||||
${EndIf}
|
${EndIf}
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
|
; Sets $OldUninstallExe to the executable named in $OldUninstallString (everything up to
|
||||||
|
; and including the first ".exe", without a leading quote), or "" when there is none.
|
||||||
|
Function ResolveOldUninstallExe
|
||||||
|
Push $R7
|
||||||
|
Push $R8
|
||||||
|
StrLen $R8 $OldUninstallString
|
||||||
|
StrCpy $R7 0
|
||||||
|
roue_loop:
|
||||||
|
${If} $R7 >= $R8
|
||||||
|
StrCpy $OldUninstallExe ""
|
||||||
|
Goto roue_out
|
||||||
|
${EndIf}
|
||||||
|
StrCpy $OldUninstallExe $OldUninstallString 4 $R7
|
||||||
|
${If} $OldUninstallExe == ".exe"
|
||||||
|
IntOp $R7 $R7 + 4
|
||||||
|
StrCpy $OldUninstallExe $OldUninstallString $R7
|
||||||
|
StrCpy $R8 $OldUninstallExe 1
|
||||||
|
${If} $R8 == '"'
|
||||||
|
StrCpy $OldUninstallExe $OldUninstallExe "" 1
|
||||||
|
${EndIf}
|
||||||
|
Goto roue_out
|
||||||
|
${EndIf}
|
||||||
|
IntOp $R7 $R7 + 1
|
||||||
|
Goto roue_loop
|
||||||
|
roue_out:
|
||||||
|
Pop $R8
|
||||||
|
Pop $R7
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
; Runs "$OldUninstallString _?=$OldInstallDir" in place and sets $OldUninstallExit:
|
||||||
|
; the uninstaller's own exit code when it ran, "missing" when the executable the
|
||||||
|
; registry names does not exist, "launch-failed" when ExecWait could not start it.
|
||||||
|
; The last two used to leave the code empty, which WaitForOldPayloadToDisappear read
|
||||||
|
; as a cancelled uninstall and aborted on, although nobody had cancelled anything.
|
||||||
|
; Uses $R5 for the exit code, as the callers did before.
|
||||||
|
Function RunOldUninstaller
|
||||||
|
Call ResolveOldUninstallExe
|
||||||
|
StrCpy $R5 ""
|
||||||
|
${If} $OldUninstallExe == ""
|
||||||
|
${OrIfNot} ${FileExists} "$OldUninstallExe"
|
||||||
|
StrCpy $OldUninstallExit "missing"
|
||||||
|
!insertmacro CockLog "old uninstall: uninstaller '$OldUninstallExe' does not exist (command '$OldUninstallString')"
|
||||||
|
Return
|
||||||
|
${EndIf}
|
||||||
|
ClearErrors
|
||||||
|
ExecWait '$OldUninstallString _?=$OldInstallDir' $R5
|
||||||
|
${If} ${Errors}
|
||||||
|
${OrIf} $R5 == ""
|
||||||
|
StrCpy $OldUninstallExit "launch-failed"
|
||||||
|
!insertmacro CockLog "old uninstall: could not start '$OldUninstallString _?=$OldInstallDir'"
|
||||||
|
Return
|
||||||
|
${EndIf}
|
||||||
|
StrCpy $OldUninstallExit $R5
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
Function AutoUninstallIfNeeded
|
Function AutoUninstallIfNeeded
|
||||||
|
|
||||||
SetShellVarContext all
|
SetShellVarContext all
|
||||||
|
|
@ -421,10 +480,9 @@ StrCpy $OldInstallDir $INSTDIR
|
||||||
StrCmp $R0 "" done32
|
StrCmp $R0 "" done32
|
||||||
DetailPrint "Removing previous version (32-bit)..."
|
DetailPrint "Removing previous version (32-bit)..."
|
||||||
Call BackupUserDataBeforeUninstall
|
Call BackupUserDataBeforeUninstall
|
||||||
StrCpy $R5 ""
|
StrCpy $OldUninstallString $R0
|
||||||
ExecWait '$R0 _?=$OldInstallDir' $R5
|
Call RunOldUninstaller
|
||||||
StrCpy $OldUninstallExit $R5
|
!insertmacro CockLog "uninstall (32-bit): exit=$OldUninstallExit"
|
||||||
!insertmacro CockLog "uninstall (32-bit): exit=$R5"
|
|
||||||
Call WaitForOldPayloadToDisappear
|
Call WaitForOldPayloadToDisappear
|
||||||
Call RestoreUserDataAfterUninstall
|
Call RestoreUserDataAfterUninstall
|
||||||
|
|
||||||
|
|
@ -438,12 +496,11 @@ ${If} ${RunningX64}
|
||||||
StrCpy $OldInstallDir $INSTDIR
|
StrCpy $OldInstallDir $INSTDIR
|
||||||
!insertmacro CockLog "uninstall (64-bit): '$R0 _?=$OldInstallDir'"
|
!insertmacro CockLog "uninstall (64-bit): '$R0 _?=$OldInstallDir'"
|
||||||
StrCmp $R0 "" done64
|
StrCmp $R0 "" done64
|
||||||
StrCpy $R5 ""
|
|
||||||
DetailPrint "Removing previous version (64-bit)..."
|
DetailPrint "Removing previous version (64-bit)..."
|
||||||
Call BackupUserDataBeforeUninstall
|
Call BackupUserDataBeforeUninstall
|
||||||
ExecWait '$R0 _?=$OldInstallDir' $R5
|
StrCpy $OldUninstallString $R0
|
||||||
StrCpy $OldUninstallExit $R5
|
Call RunOldUninstaller
|
||||||
!insertmacro CockLog "uninstall (64-bit): exit=$R5"
|
!insertmacro CockLog "uninstall (64-bit): exit=$OldUninstallExit"
|
||||||
Call WaitForOldPayloadToDisappear
|
Call WaitForOldPayloadToDisappear
|
||||||
Call RestoreUserDataAfterUninstall
|
Call RestoreUserDataAfterUninstall
|
||||||
|
|
||||||
|
|
@ -471,6 +528,28 @@ Function WaitForOldPayloadToDisappear
|
||||||
${If} $OldInstallDir == ""
|
${If} $OldInstallDir == ""
|
||||||
Return
|
Return
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
; The registered uninstaller could not be run at all (missing, or ExecWait could not
|
||||||
|
; start it): nothing is going to empty the directory, so waiting is pointless and
|
||||||
|
; aborting as "cancelled" was wrong. Remove the previous payload the same way the
|
||||||
|
; skipped-files recovery below does, and abort - naming why - only if that fails.
|
||||||
|
${If} $OldUninstallExit == "missing"
|
||||||
|
${OrIf} $OldUninstallExit == "launch-failed"
|
||||||
|
${IfNot} ${FileExists} "$OldInstallDir\*.*"
|
||||||
|
!insertmacro CockLog "old uninstall: uninstaller $OldUninstallExit and $OldInstallDir is already gone"
|
||||||
|
Return
|
||||||
|
${EndIf}
|
||||||
|
!insertmacro CockLog "old uninstall: uninstaller $OldUninstallExit ('$OldUninstallString'); removing $OldInstallDir payload directly"
|
||||||
|
Call AppendUninstallerLog
|
||||||
|
Call RemoveOldPayloadLeftovers
|
||||||
|
${If} $OldPayloadRemoved != "1"
|
||||||
|
StrCpy $AbortReason \
|
||||||
|
"The previous version in $OldInstallDir could not be removed: its uninstaller ($OldUninstallExe) could not be run ($OldUninstallExit), and removing the files directly failed.$\r$\n$\r$\nStill in use by: $HolderOutput$\r$\n$\r$\nClose anything still using those files and run this installer again."
|
||||||
|
Call RestoreUserDataAfterUninstall
|
||||||
|
Call AbortInstall
|
||||||
|
${EndIf}
|
||||||
|
!insertmacro CockLog "old uninstall: continuing after removing the payload of an uninstaller that could not run"
|
||||||
|
Return
|
||||||
|
${EndIf}
|
||||||
StrCpy $R2 0
|
StrCpy $R2 0
|
||||||
old_uninstall_wait:
|
old_uninstall_wait:
|
||||||
IfFileExists "$OldInstallDir\cockatrice.exe" 0 old_uninstall_gone
|
IfFileExists "$OldInstallDir\cockatrice.exe" 0 old_uninstall_gone
|
||||||
|
|
@ -481,8 +560,9 @@ ${If} $R2 > 60
|
||||||
; separate log; copy it here so the report sent from AbortInstall carries it.
|
; separate log; copy it here so the report sent from AbortInstall carries it.
|
||||||
Call AppendUninstallerLog
|
Call AppendUninstallerLog
|
||||||
${If} $OldUninstallExit != "0"
|
${If} $OldUninstallExit != "0"
|
||||||
; Cancelled, failed, or could not be started at all (empty code): the old version
|
; Cancelled or failed with a non-zero exit code (an uninstaller that could not be
|
||||||
; was not meant to be removed, so nothing is deleted on its behalf.
|
; started is handled above): the old version was not meant to be removed, so
|
||||||
|
; nothing is deleted on its behalf.
|
||||||
StrCpy $AbortReason \
|
StrCpy $AbortReason \
|
||||||
"The previous version in $OldInstallDir is still there because its uninstaller was cancelled or failed (exit code '$OldUninstallExit').$\r$\n$\r$\nClose anything still using those files and run this installer again."
|
"The previous version in $OldInstallDir is still there because its uninstaller was cancelled or failed (exit code '$OldUninstallExit').$\r$\n$\r$\nClose anything still using those files and run this installer again."
|
||||||
; The backup was taken before the uninstaller ran; an abort must not leave the
|
; The backup was taken before the uninstaller ran; an abort must not leave the
|
||||||
|
|
@ -524,7 +604,8 @@ ${EndIf}
|
||||||
Return
|
Return
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
; Called when the old uninstaller exited successfully but left its payload behind.
|
; Called when the old uninstaller exited successfully but left its payload behind, or
|
||||||
|
; could not be run at all (missing or not startable) and the payload is still there.
|
||||||
; Frees the files the same way the guard does (close, then offer to end), deletes what
|
; Frees the files the same way the guard does (close, then offer to end), deletes what
|
||||||
; the uninstaller skipped, and on failure records which files survived and who holds
|
; the uninstaller skipped, and on failure records which files survived and who holds
|
||||||
; them in $HolderOutput, for the abort message. Sets $OldPayloadRemoved to 1 only when
|
; them in $HolderOutput, for the abort message. Sets $OldPayloadRemoved to 1 only when
|
||||||
|
|
@ -2046,10 +2127,8 @@ ${If} $PortableMode = 0
|
||||||
!insertmacro CockLog "componentsPagePre: old 32-bit uninstall '$OldUninstallString _?=$OldInstallDir' (oldDir=$OldInstallDir InstDir=$INSTDIR)"
|
!insertmacro CockLog "componentsPagePre: old 32-bit uninstall '$OldUninstallString _?=$OldInstallDir' (oldDir=$OldInstallDir InstDir=$INSTDIR)"
|
||||||
ClearErrors
|
ClearErrors
|
||||||
Call BackupUserDataBeforeUninstall
|
Call BackupUserDataBeforeUninstall
|
||||||
StrCpy $R5 ""
|
Call RunOldUninstaller
|
||||||
ExecWait "$OldUninstallString _?=$OldInstallDir" $R5
|
!insertmacro CockLog "componentsPagePre: old 32-bit uninstall exit=$OldUninstallExit"
|
||||||
StrCpy $OldUninstallExit $R5
|
|
||||||
!insertmacro CockLog "componentsPagePre: old 32-bit uninstall exit=$R5"
|
|
||||||
Call WaitForOldPayloadToDisappear
|
Call WaitForOldPayloadToDisappear
|
||||||
Call RestoreUserDataAfterUninstall
|
Call RestoreUserDataAfterUninstall
|
||||||
|
|
||||||
|
|
@ -2084,10 +2163,8 @@ ${If} $PortableMode = 0
|
||||||
!insertmacro CockLog "componentsPagePre: old 64-bit uninstall '$OldUninstallString _?=$OldInstallDir' (oldDir=$OldInstallDir InstDir=$INSTDIR)"
|
!insertmacro CockLog "componentsPagePre: old 64-bit uninstall '$OldUninstallString _?=$OldInstallDir' (oldDir=$OldInstallDir InstDir=$INSTDIR)"
|
||||||
ClearErrors
|
ClearErrors
|
||||||
Call BackupUserDataBeforeUninstall
|
Call BackupUserDataBeforeUninstall
|
||||||
StrCpy $R5 ""
|
Call RunOldUninstaller
|
||||||
ExecWait "$OldUninstallString _?=$OldInstallDir" $R5
|
!insertmacro CockLog "componentsPagePre: old 64-bit uninstall exit=$OldUninstallExit"
|
||||||
StrCpy $OldUninstallExit $R5
|
|
||||||
!insertmacro CockLog "componentsPagePre: old 64-bit uninstall exit=$R5"
|
|
||||||
Call WaitForOldPayloadToDisappear
|
Call WaitForOldPayloadToDisappear
|
||||||
Call RestoreUserDataAfterUninstall
|
Call RestoreUserDataAfterUninstall
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue