diff --git a/browser/installer/windows/nsis/updater_append.ini b/browser/installer/windows/nsis/updater_append.ini new file mode 100644 index 000000000000..af7742c12c66 --- /dev/null +++ b/browser/installer/windows/nsis/updater_append.ini @@ -0,0 +1,12 @@ + +; IMPORTANT: This file should always start with a newline in case a locale +; provided updater.ini does not end with a newline. +; Application to launch after an update has been successfully applied. This +; must be in the same directory or a sub-directory of the directory of the +; application executable that initiated the software update. +[PostUpdateWin] +; ExeRelPath is the path to the PostUpdateWin executable relative to the +; application executable. +ExeRelPath=uninstall\helper.exe +; ExeArg is the argument to pass to the PostUpdateWin exe +ExeArg=/PostUpdate diff --git a/browser/locales/Makefile.in b/browser/locales/Makefile.in index ba79cabf160e..d3627f8dbfc0 100644 --- a/browser/locales/Makefile.in +++ b/browser/locales/Makefile.in @@ -293,7 +293,8 @@ endif ifdef MOZ_UPDATER libs:: $(addprefix $(LOCALE_SRCDIR)/,updater/updater.ini) ifeq ($(OS_ARCH),WINNT) - iconv -f UTF-8 -t $(WIN_INSTALLER_CHARSET) $< > $(FINAL_TARGET)/updater.ini + cat $< $(srcdir)/../installer/windows/nsis/updater_append.ini | \ + iconv -f UTF-8 -t $(WIN_INSTALLER_CHARSET) > $(FINAL_TARGET)/updater.ini else ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) $(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/updater.app/Contents/MacOS diff --git a/toolkit/mozapps/installer/windows/nsis/common.nsh b/toolkit/mozapps/installer/windows/nsis/common.nsh index 8b0795302f60..e6f32095895b 100755 --- a/toolkit/mozapps/installer/windows/nsis/common.nsh +++ b/toolkit/mozapps/installer/windows/nsis/common.nsh @@ -389,11 +389,11 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack !macroend !macro GetParentDir - Exch $R0 - Push $R1 - Push $R2 - Push $R3 - StrLen $R3 $R0 + Exch $R0 + Push $R1 + Push $R2 + Push $R3 + StrLen $R3 $R0 ${DoWhile} 1 > 0 IntOp $R1 $R1 - 1 ${If} $R1 <= -$R3 @@ -1071,6 +1071,9 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack /** * Writes a registry string using SHCTX and the supplied params and logs the * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. + * + * Define NO_LOG to prevent all logging when calling this from the uninstaller. + * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * This will only be used for logging. @@ -1176,6 +1179,9 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack /** * Writes a registry dword using SHCTX and the supplied params and logs the * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. + * + * Define NO_LOG to prevent all logging when calling this from the uninstaller. + * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * This will only be used for logging. @@ -1280,6 +1286,9 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack /** * Writes a registry string to HKCR using the supplied params and logs the * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. + * + * Define NO_LOG to prevent all logging when calling this from the uninstaller. + * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * This will only be used for logging. @@ -1398,6 +1407,9 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack * Creates a registry key. This will log the actions to the install and * uninstall logs. Alternatively you can set a registry value to create the key * and then delete the value. + * + * Define NO_LOG to prevent all logging when calling this from the uninstaller. + * * @param _ROOT * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). * @param _KEY @@ -1899,103 +1911,104 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack */ !macro GetPathFromString - !ifndef ${_MOZFUNC_UN}GetPathFromString - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - !define ${_MOZFUNC_UN}GetPathFromString "!insertmacro ${_MOZFUNC_UN}GetPathFromStringCall" + !ifndef ${_MOZFUNC_UN}GetPathFromString + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}GetPathFromString "!insertmacro ${_MOZFUNC_UN}GetPathFromStringCall" - Function ${_MOZFUNC_UN}GetPathFromString - Exch $R8 - Push $R7 - Push $R6 - ClearErrors + Function ${_MOZFUNC_UN}GetPathFromString + Exch $R8 + Push $R7 + Push $R6 + ClearErrors - StrCpy $R9 $R8 - StrCpy $R6 0 ; Set the counter to 0. + StrCpy $R9 $R8 + StrCpy $R6 0 ; Set the counter to 0. - ClearErrors - ; Handle quoted paths with arguments. - StrCpy $R7 $R9 1 ; Copy the first char. - StrCmp $R7 '"' +2 +1 ; Is it a "? - StrCmp $R7 "'" +1 +9 ; Is it a '? - StrCpy $R9 $R9 "" 1 ; Remove the first char. - IntOp $R6 $R6 + 1 ; Increment the counter. - StrCpy $R7 $R9 1 $R6 ; Starting from the counter copy the next char. - StrCmp $R7 "" end ; Are there no more chars? - StrCmp $R7 '"' +2 +1 ; Is it a " char? - StrCmp $R7 "'" +1 -4 ; Is it a ' char? - StrCpy $R9 $R9 $R6 ; Copy chars up to the counter. - GoTo end + ClearErrors + ; Handle quoted paths with arguments. + StrCpy $R7 $R9 1 ; Copy the first char. + StrCmp $R7 '"' +2 +1 ; Is it a "? + StrCmp $R7 "'" +1 +9 ; Is it a '? + StrCpy $R9 $R9 "" 1 ; Remove the first char. + IntOp $R6 $R6 + 1 ; Increment the counter. + StrCpy $R7 $R9 1 $R6 ; Starting from the counter copy the next char. + StrCmp $R7 "" end ; Are there no more chars? + StrCmp $R7 '"' +2 +1 ; Is it a " char? + StrCmp $R7 "'" +1 -4 ; Is it a ' char? + StrCpy $R9 $R9 $R6 ; Copy chars up to the counter. + GoTo end - ; Handle DefaultIcon paths. DefaultIcon paths are not quoted and end with - ; a , and a number. - IntOp $R6 $R6 - 1 ; Decrement the counter. - StrCpy $R7 $R9 1 $R6 ; Copy one char from the end minus the counter. - StrCmp $R7 '' +4 ; Are there no more chars? - StrCmp $R7 ',' +1 -3 ; Is it a , char? - StrCpy $R9 $R9 $R6 ; Copy chars up to the end minus the counter. - GoTo end + ; Handle DefaultIcon paths. DefaultIcon paths are not quoted and end with + ; a , and a number. + IntOp $R6 $R6 - 1 ; Decrement the counter. + StrCpy $R7 $R9 1 $R6 ; Copy one char from the end minus the counter. + StrCmp $R7 '' +4 ; Are there no more chars? + StrCmp $R7 ',' +1 -3 ; Is it a , char? + StrCpy $R9 $R9 $R6 ; Copy chars up to the end minus the counter. + GoTo end - ; Handle unquoted paths with arguments. An unquoted path with arguments - ; must be an 8dot3 path. - StrCpy $R6 -1 ; Set the counter to -1 so it will start at 0. - IntOp $R6 $R6 + 1 ; Increment the counter. - StrCpy $R7 $R9 1 $R6 ; Starting from the counter copy the next char. - StrCmp $R7 "" end ; Are there no more chars? - StrCmp $R7 " " +1 -3 ; Is it a space char? - StrCpy $R9 $R9 $R6 ; Copy chars up to the counter. + ; Handle unquoted paths with arguments. An unquoted path with arguments + ; must be an 8dot3 path. + StrCpy $R6 -1 ; Set the counter to -1 so it will start at 0. + IntOp $R6 $R6 + 1 ; Increment the counter. + StrCpy $R7 $R9 1 $R6 ; Starting from the counter copy the next char. + StrCmp $R7 "" end ; Are there no more chars? + StrCmp $R7 " " +1 -3 ; Is it a space char? + StrCpy $R9 $R9 $R6 ; Copy chars up to the counter. - end: + end: - Pop $R6 - Pop $R7 - Exch $R8 - Push $R9 - FunctionEnd + Pop $R6 + Pop $R7 + Exch $R8 + Push $R9 + FunctionEnd - !verbose pop - !endif + !verbose pop + !endif !macroend !macro GetPathFromStringCall _STRING _RESULT - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - Push "${_STRING}" - Call GetPathFromString - Pop ${_RESULT} - !verbose pop + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_STRING}" + Call GetPathFromString + Pop ${_RESULT} + !verbose pop !macroend !macro un.GetPathFromStringCall _STRING _RESULT - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - Push "${_STRING}" - Call un.GetPathFromString - Pop ${_RESULT} - !verbose pop + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_STRING}" + Call un.GetPathFromString + Pop ${_RESULT} + !verbose pop !macroend !macro un.GetPathFromString - !ifndef un.GetPathFromString - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - !undef _MOZFUNC_UN - !define _MOZFUNC_UN "un." + !ifndef un.GetPathFromString + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." - !insertmacro GetPathFromString + !insertmacro GetPathFromString - !undef _MOZFUNC_UN - !define _MOZFUNC_UN - !verbose pop - !endif + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif !macroend /** * If present removes the VirtualStore directory for this installation. Uses the * program files directory path and the current install location to determine * the sub-directory in the VirtualStore directory. -*/ + */ !macro CleanVirtualStore + !ifndef ${_MOZFUNC_UN}CleanVirtualStore !verbose push !verbose ${_MOZFUNC_VERBOSE} @@ -2046,30 +2059,155 @@ Exch $R9 ; exchange the new $R9 value with the top of the stack !macroend !macro CleanVirtualStoreCall - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - Call CleanVirtualStore - !verbose pop + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call CleanVirtualStore + !verbose pop !macroend !macro un.CleanVirtualStoreCall - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - Call un.CleanVirtualStore - !verbose pop + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.CleanVirtualStore + !verbose pop !macroend !macro un.CleanVirtualStore - !ifndef un.CleanVirtualStore - !verbose push - !verbose ${_MOZFUNC_VERBOSE} - !undef _MOZFUNC_UN - !define _MOZFUNC_UN "un." + !ifndef un.CleanVirtualStore + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." - !insertmacro CleanVirtualStore + !insertmacro CleanVirtualStore - !undef _MOZFUNC_UN - !define _MOZFUNC_UN - !verbose pop - !endif + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Updates the uninstall.log with new files added by software update. + * + * Requires FileJoin, LineFind, TextCompare, and TrimNewLines. + * + * IMPORTANT! The LineFind docs claim that it uses all registers except $R0-$R3. + * Though it appears that this is not true all registers besides + * $R0-$R3 may be overwritten so protect yourself! + */ +!macro UpdateUninstallLog + + !ifndef ${_MOZFUNC_UN}UpdateUninstallLog + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}UpdateUninstallLog "!insertmacro ${_MOZFUNC_UN}UpdateUninstallLogCall" + + Function ${_MOZFUNC_UN}UpdateUninstallLog + Push $R3 + Push $R2 + Push $R1 + Push $R0 + + ClearErrors + + GetFullPathName $R3 "$INSTDIR\uninstall" + IfFileExists "$R3\uninstall.update" +2 0 + Return + + ${${_MOZFUNC_UN}LineFind} "$R3\uninstall.update" "" "1:-1" "${_MOZFUNC_UN}CleanupUpdateLog" + + GetTempFileName $R2 "$R3" + FileOpen $R1 $R2 w + ${${_MOZFUNC_UN}TextCompare} "$R3\uninstall.update" "$R3\uninstall.log" "SlowDiff" "${_MOZFUNC_UN}CreateUpdateDiff" + FileClose $R1 + + IfErrors +2 0 + ${${_MOZFUNC_UN}FileJoin} "$R3\uninstall.log" "$R2" "$R3\uninstall.log" + + ${DeleteFile} "$R2" + + ClearErrors + + Pop $R0 + Pop $R1 + Pop $R2 + Pop $R3 + FunctionEnd + + ; This callback MUST use labels vs. relative line numbers. + Function ${_MOZFUNC_UN}CleanupUpdateLog + StrCpy $R2 "$R9" 12 + StrCmp "$R2" "EXECUTE ADD " 0 skip + StrCpy $R9 "$R9" "" 12 + + Push $R6 + Push $R5 + Push $R4 + StrCpy $R4 "" ; Initialize to an empty string. + StrCpy $R6 -1 ; Set the counter to -1 so it will start at 0. + + loop: + IntOp $R6 $R6 + 1 ; Increment the counter. + StrCpy $R5 $R9 1 $R6 ; Starting from the counter copy the next char. + StrCmp $R5 "" copy ; Are there no more chars? + StrCmp $R5 "/" 0 +2 ; Is the char a /? + StrCpy $R5 "\" ; Replace the char with a \. + + StrCpy $R4 "$R4$R5" + GoTo loop + + copy: + StrCpy $R9 "File: \$R4" + Pop $R6 + Pop $R5 + Pop $R4 + GoTo end + + skip: + StrCpy $0 "SkipWrite" + + end: + Push $0 + FunctionEnd + + Function ${_MOZFUNC_UN}CreateUpdateDiff + ${${_MOZFUNC_UN}TrimNewLines} "$9" "$9" + StrCmp $9 "" +2 0 + FileWrite $R1 "$9$\r$\n" + + Push 0 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro UpdateUninstallLogCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call UpdateUninstallLog + !verbose pop +!macroend + +!macro un.UpdateUninstallLogCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.UpdateUninstallLog + !verbose pop +!macroend + +!macro un.UpdateUninstallLog + !ifndef un.UpdateUninstallLog + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro UpdateUninstallLog + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif !macroend diff --git a/toolkit/mozapps/update/src/Makefile.in b/toolkit/mozapps/update/src/Makefile.in index 67deb003b3fe..e498ca252880 100644 --- a/toolkit/mozapps/update/src/Makefile.in +++ b/toolkit/mozapps/update/src/Makefile.in @@ -42,7 +42,7 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -MODULE = extensions +MODULE = update ifdef MOZ_UPDATER DIRS = updater diff --git a/toolkit/mozapps/update/src/nsPostUpdateWin.js b/toolkit/mozapps/update/src/nsPostUpdateWin.js index 1b8d893fab84..d68c181fbfbb 100644 --- a/toolkit/mozapps/update/src/nsPostUpdateWin.js +++ b/toolkit/mozapps/update/src/nsPostUpdateWin.js @@ -589,6 +589,16 @@ nsPostUpdateWin.prototype = { }, run: function() { + // When uninstall/uninstall.update exists the uninstaller has already + // updated the uninstall.log with the files added by software update. + var updateUninstallFile = getFile(KEY_APPDIR); + updateUninstallFile.append("uninstall"); + updateUninstallFile.append("uninstall.update"); + if (updateUninstallFile.exists()) { + LOG("nothing to do, uninstall.log has already been updated"); + return; + } + try { installLogWriter = new InstallLogWriter(); try { diff --git a/toolkit/mozapps/update/src/updater/updater.cpp b/toolkit/mozapps/update/src/updater/updater.cpp index fab554475c4a..d9c5e0a0592f 100644 --- a/toolkit/mozapps/update/src/updater/updater.cpp +++ b/toolkit/mozapps/update/src/updater/updater.cpp @@ -263,6 +263,7 @@ private: static char* gSourcePath; static ArchiveReader gArchiveReader; +static bool gSucceeded = FALSE; static const char kWhitespace[] = " \t"; static const char kNL[] = "\r\n"; @@ -1006,6 +1007,61 @@ PatchIfFile::Finish(int status) #ifdef XP_WIN #include "nsWindowsRestart.cpp" + +static void +LaunchWinPostProcess(const char *appExe) +{ + // Launch helper.exe to perform post processing (e.g. registry and log file + // modifications) for the update. + char inifile[MAXPATHLEN]; + strcpy(inifile, appExe); + + char *slash = strrchr(inifile, '\\'); + if (!slash) + return; + + strcpy(slash + 1, "updater.ini"); + + char exefile[MAXPATHLEN]; + char exearg[MAXPATHLEN]; + if (!GetPrivateProfileString("PostUpdateWin", "ExeRelPath", NULL, exefile, + sizeof(exefile), inifile)) + return; + + if (!GetPrivateProfileString("PostUpdateWin", "ExeArg", NULL, exearg, + sizeof(exearg), inifile)) + return; + + char exefullpath[MAXPATHLEN]; + strcpy(exefullpath, appExe); + + slash = strrchr(exefullpath, '\\'); + strcpy(slash + 1, exefile); + + char dlogFile[MAXPATHLEN]; + strcpy(dlogFile, exefullpath); + + slash = strrchr(dlogFile, '\\'); + strcpy(slash + 1, "uninstall.update"); + + char slogFile[MAXPATHLEN]; + snprintf(slogFile, MAXPATHLEN, "%s/update.log", gSourcePath); + + // We want to launch the post update helper app to update the Windows + // registry even if there is a failure with removing the uninstall.update + // file or copying the update.log file. + ensure_remove(dlogFile); + copy_file(slogFile, dlogFile); + + static int argc = 2; + static char **argv = (char**) malloc(sizeof(char*) * (argc + 1)); + argv[0] = "argv0ignoredbywinlaunchchild"; + argv[1] = exearg; + argv[2] = "\0"; + + WinLaunchChild(exefullpath, argc, argv, 1); + free(argv); +} #endif static void @@ -1144,6 +1200,9 @@ int main(int argc, char **argv) #ifdef XP_WIN if (exefile) CloseHandle(exefile); + + if (gSucceeded) + LaunchWinPostProcess(argv[4]); #endif // The callback to execute is given as the last N arguments of our command @@ -1251,6 +1310,9 @@ ActionList::Finish(int status) a = a->mNext; } + if (status == OK) + gSucceeded = TRUE; + UpdateProgressUI(100.0f); }