diff --git a/toolkit/mozapps/update/src/updater/updater.cpp b/toolkit/mozapps/update/src/updater/updater.cpp index b04446435ee4..d6d74609e0da 100644 --- a/toolkit/mozapps/update/src/updater/updater.cpp +++ b/toolkit/mozapps/update/src/updater/updater.cpp @@ -21,6 +21,7 @@ * * Contributor(s): * Darin Fisher + * Robert Strong * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -1101,7 +1102,7 @@ LaunchWinPostProcess(const WCHAR *appExe) L"\0" }; - WinLaunchChild(exefullpath, argc, argv, 1); + WinLaunchChild(exefullpath, argc, argv, 0); free(argv); } #endif @@ -1120,7 +1121,7 @@ LaunchCallbackApp(const NS_tchar *workingDir, int argc, NS_tchar **argv) #elif defined(XP_MACOSX) LaunchChild(argc, argv); #elif defined(XP_WIN) - WinLaunchChild(argv[0], argc, argv, -1); + WinLaunchChild(argv[0], argc, argv, 0); #else # warning "Need implementaton of LaunchCallbackApp" #endif @@ -1212,6 +1213,91 @@ int NS_main(int argc, NS_tchar **argv) #endif } +#ifdef XP_WIN + // Launch a second instance of the updater with the runas verb on Windows + // when write access is denied to the installation directory. + + NS_tchar updateLockFilePath[MAXPATHLEN]; + NS_tsnprintf(updateLockFilePath, MAXPATHLEN, + NS_T("%s/update_in_progress.lock"), argv[3]); + + // The update_in_progress.lock file should only exist during an update. In + // case it exists attempt to remove it and exit if that fails to prevent + // simultaneous updates occurring. + if (!_waccess(updateLockFilePath, F_OK) && + NS_tremove(updateLockFilePath) != 0) { + fprintf(stderr, "Update already in progress! Exiting\n"); + return 1; + } + + HANDLE updateLockFileHandle; + updateLockFileHandle = CreateFileW(updateLockFilePath, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_ALWAYS, + FILE_FLAG_DELETE_ON_CLOSE, + NULL); + + NS_tchar elevatedLockFilePath[MAXPATHLEN]; + NS_tsnprintf(elevatedLockFilePath, MAXPATHLEN, + NS_T("%s/update_elevated.lock"), argv[1]); + + if (updateLockFileHandle == INVALID_HANDLE_VALUE) { + if (!_waccess(elevatedLockFilePath, F_OK) && + NS_tremove(elevatedLockFilePath) != 0) { + fprintf(stderr, "Update already elevated! Exiting\n"); + return 1; + } + + HANDLE elevatedFileHandle; + elevatedFileHandle = CreateFileW(elevatedLockFilePath, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_ALWAYS, + FILE_FLAG_DELETE_ON_CLOSE, + NULL); + + if (elevatedFileHandle == INVALID_HANDLE_VALUE) { + fprintf(stderr, "Unable to create elevated lock file! Exiting\n"); + return 1; + } + + PRUnichar *cmdLine = MakeCommandLine(argc - 1, argv + 1); + if (!cmdLine) { + CloseHandle(elevatedFileHandle); + return 1; + } + + SHELLEXECUTEINFO sinfo; + memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO)); + sinfo.cbSize = sizeof(SHELLEXECUTEINFO); + sinfo.fMask = SEE_MASK_NOASYNC | + SEE_MASK_FLAG_NO_UI | + SEE_MASK_NOCLOSEPROCESS; + sinfo.hwnd = NULL; + sinfo.lpFile = argv[0]; + sinfo.lpParameters = cmdLine; + sinfo.lpVerb = L"runas"; + sinfo.nShow = SW_SHOWNORMAL; + + BOOL result = ShellExecuteEx(&sinfo); + free(cmdLine); + + if (result) { + WaitForSingleObject(sinfo.hProcess, INFINITE); + CloseHandle(sinfo.hProcess); + } + + if (argc > 4) + LaunchCallbackApp(argv[3], argc - 4, argv + 4); + + CloseHandle(elevatedFileHandle); + return 0; + } +#endif + gSourcePath = argv[1]; LogInit(); @@ -1229,6 +1315,12 @@ int NS_main(int argc, NS_tchar **argv) #ifdef XP_WIN if (gSucceeded && argc > 4) LaunchWinPostProcess(argv[4]); + CloseHandle(updateLockFileHandle); + // If elevated return early and let the process that launched this process + // launch the callback application. + if (!_waccess(elevatedLockFilePath, F_OK) && + NS_tremove(elevatedLockFilePath) != 0) + return 0; #endif // The callback to execute is given as the last N arguments of our command diff --git a/toolkit/mozapps/update/src/updater/updater.exe.manifest b/toolkit/mozapps/update/src/updater/updater.exe.manifest index 4c50f9dc1567..8bea07a34b22 100644 --- a/toolkit/mozapps/update/src/updater/updater.exe.manifest +++ b/toolkit/mozapps/update/src/updater/updater.exe.manifest @@ -19,4 +19,12 @@ /> + + + + + + + + diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 67916fdca587..79f0c136c7bf 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -1544,8 +1544,7 @@ int OS2LaunchChild(const char *aExePath, int aArgc, char **aArgv) // blank command line instead of being launched with the same command line that // it was initially started with. static nsresult LaunchChild(nsINativeAppSupport* aNative, - PRBool aBlankCommandLine = PR_FALSE, - int needElevation = 0) + PRBool aBlankCommandLine = PR_FALSE) { aNative->Quit(); // release DDE mutex, if we're holding it @@ -1573,7 +1572,7 @@ static nsresult LaunchChild(nsINativeAppSupport* aNative, if (NS_FAILED(rv)) return rv; - if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, needElevation)) + if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, 0)) return NS_ERROR_FAILURE; #else @@ -3275,7 +3274,7 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) MOZ_gdk_display_close(display); #endif - rv = LaunchChild(nativeApp, appInitiatedRestart, upgraded ? -1 : 0); + rv = LaunchChild(nativeApp, appInitiatedRestart); #ifdef MOZ_CRASHREPORTER if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER) diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp index 8084e07f2bf8..4e2dfb3855bb 100644 --- a/toolkit/xre/nsUpdateDriver.cpp +++ b/toolkit/xre/nsUpdateDriver.cpp @@ -474,7 +474,7 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsILocalFile *statusFile, #elif defined(XP_WIN) _wchdir(applyToDir.get()); - if (!WinLaunchChild(updaterPathW.get(), appArgc + 4, argv, 1)) + if (!WinLaunchChild(updaterPathW.get(), appArgc + 4, argv, 0)) return; _exit(0); #else