author | Josh Aas <joshmoz@gmail.com> |
Sat, 02 Oct 2010 00:11:24 -0400 | |
changeset 54891 | 861afa477ababd8b80b398e9eb3bd1ba30d1e199 |
parent 54890 | ec3316fdc36044df94d9baee2717cf16bf955850 |
child 54892 | 7a1028b9d42ffd7ec79595dfdcbf9e399dceeaf6 |
push id | 16061 |
push user | josh@mozilla.com |
push date | Sat, 02 Oct 2010 04:12:12 +0000 |
treeherder | mozilla-central@861afa477aba [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | rstrong, blocking-beta7 |
bugs | 600777 |
milestone | 2.0b7pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/toolkit/mozapps/update/test/unit/head_update.js.in +++ b/toolkit/mozapps/update/test/unit/head_update.js.in @@ -149,17 +149,17 @@ function runUpdate(aUpdatesDir, aUpdater var cwdPath = do_get_file("/", true).path; if (/ /.test(cwdPath)) cwdPath = '"' + cwdPath + '"'; var process = AUS_Cc["@mozilla.org/process/util;1"]. createInstance(AUS_Ci.nsIProcess); process.init(updateBin); - var args = [updatesDirPath, 0, cwdPath]; + var args = [updatesDirPath, cwdPath]; process.run(true, args, args.length); return process.exitValue; } /** * Sets up the bare bones XMLHttpRequest implementation below. * * @param callback
--- a/toolkit/mozapps/update/test/unit/test_0110_general.js +++ b/toolkit/mozapps/update/test/unit/test_0110_general.js @@ -82,22 +82,16 @@ var gTestFiles = [ compareContents : "ToBeDeleted\n", originalFile : null, compareFile : null, originalPerms : 0767, comparePerms : 0644 }]; function run_test() { - var isOSX = ("nsILocalFileMac" in Components.interfaces); - if (isOSX) { - dump("INFO | test_0110_general.js | Skipping test on mac, bug 599477") - return; - } - var testFile; // The directory the updates will be applied to is the current working // directory and not dist/bin. var testDir = do_get_file("mar_test", true); // The mar files were created with all files in a subdirectory named // mar_test... clear it out of the way if it exists and then create it. try { removeDirRecursive(testDir);
--- a/toolkit/mozapps/update/test/unit/test_0111_general.js +++ b/toolkit/mozapps/update/test/unit/test_0111_general.js @@ -100,22 +100,16 @@ var gTestFiles = [ compareContents : "Added\n", originalFile : null, compareFile : null, originalPerms : null, comparePerms : 0644 }]; function run_test() { - var isOSX = ("nsILocalFileMac" in Components.interfaces); - if (isOSX) { - dump("INFO | test_0111_general.js | Skipping test on mac, bug 599477") - return; - } - var testFile; // The directory the updates will be applied to is the current working // directory and not dist/bin. var testDir = do_get_file("mar_test", true); // The mar files were created with all files in a subdirectory named // mar_test... clear it out of the way if it exists and then create it. try { removeDirRecursive(testDir);
--- a/toolkit/mozapps/update/test/unit/test_0112_general.js +++ b/toolkit/mozapps/update/test/unit/test_0112_general.js @@ -82,22 +82,16 @@ var gTestFiles = [ compareContents : "ShouldNotBeDeleted\n", originalFile : null, compareFile : null, originalPerms : 0644, comparePerms : null }]; function run_test() { - var isOSX = ("nsILocalFileMac" in Components.interfaces); - if (isOSX) { - dump("INFO | test_0112_general.js | Skipping test on mac, bug 599477") - return; - } - var testFile; // The directory the updates will be applied to is the current working // directory and not dist/bin. var testDir = do_get_file("mar_test", true); // The mar files were created with all files in a subdirectory named // mar_test... clear it out of the way if it exists and then create it. try { removeDirRecursive(testDir);
--- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -1461,81 +1461,88 @@ UpdateThreadFunc(void *param) LOG(("calling QuitProgressUI\n")); QuitProgressUI(); } int NS_main(int argc, NS_tchar **argv) { InitProgressUI(&argc, &argv); - // The updater command line consists of the directory path containing the - // updater.mar file to process followed by the PID of the calling process. - // The updater will wait on the parent process to exit if the PID is non- - // zero. This is leveraged on platforms such as Windows where it is - // necessary for the parent process to exit before its executable image may - // be altered. -#ifndef WINCE - if (argc < 2) { - fprintf(stderr, "Usage: updater <dir-path> [parent-pid [working-dir callback args...]]\n"); + // To process an update the updater command line must at a minimum have the + // directory path containing the updater.mar file to process as the first argument + // and the directory to apply the update to as the second argument. When the + // updater is launched by another process the PID of the parent process should be + // provided in the optional third argument and the updater will wait on the parent + // process to exit if the value is non-zero and the process is present. This is + // necessary due to not being able to update files that are in use on Windows. The + // optional fourth argument is the callback's working directory and the optional + // fifth argument is the callback path. The callback is the application to launch + // after updating and it will be launched when these arguments are provided + // whether the update was successful or not. All remaining arguments are optional + // and are passed to the callback when it is launched. + if (argc < 3) { + fprintf(stderr, "Usage: updater update-dir apply-to-dir [wait-pid [callback-working-dir callback-path args...]]\n"); return 1; } -#else - if (argc < 4) { - fprintf(stderr, "Usage: updater <dir-path> parent-pid <working-dir> [callback args...]]\n"); + + // Change current directory to the directory where we need to apply the update. +#ifndef WINCE + if (NS_tchdir(argv[2]) != 0) { return 1; } #endif - if (argc > 2 ) { + // If there is a PID specified and it is not '0' then wait for the process to exit. + if (argc > 3) { #ifdef XP_WIN - __int64 pid = _wtoi64(argv[2]); + __int64 pid = _wtoi64(argv[3]); #else - int pid = atoi(argv[2]); + int pid = atoi(argv[3]); #endif - if (pid) { + if (pid != 0) { #ifdef XP_WIN HANDLE parent = OpenProcess(SYNCHRONIZE, FALSE, (DWORD) pid); // May return NULL if the parent process has already gone away. // Otherwise, wait for the parent process to exit before starting the // update. if (parent) { DWORD result = WaitForSingleObject(parent, 5000); CloseHandle(parent); if (result != WAIT_OBJECT_0) return 1; } // The process may be signaled before it releases the executable image. // This is a terrible hack, but it'll have to do for now :-( Sleep(50); #else - int status; - waitpid(pid, &status, 0); + waitpid(pid, NULL, 0); #endif } } - // The callback is the last N command line arguments starting from argOffset. - // The argument specified by argOffset is the callback executable and the - // argument prior to argOffset is the working directory. - const int argOffset = 4; + // The directory containing the update information. + gSourcePath = argv[1]; - gSourcePath = argv[1]; + // The callback is the remaining arguments starting at callbackIndex. + // The argument specified by callbackIndex is the callback executable and the + // argument prior to callbackIndex is the working directory. + const int callbackIndex = 5; #if defined(XP_WIN) && !defined(WINCE) // Launch a second instance of the updater with the runas verb on Windows // when write access is denied to the installation directory. HANDLE updateLockFileHandle; NS_tchar elevatedLockFilePath[MAXPATHLEN]; - if (argc > argOffset) { + if (argc > callbackIndex) { NS_tchar updateLockFilePath[MAXPATHLEN]; NS_tsnprintf(updateLockFilePath, sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]), - NS_T("%s.update_in_progress.lock"), argv[argOffset]); + NS_T("%s.update_in_progress.lock"), argv[callbackIndex]); // 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; @@ -1597,88 +1604,83 @@ int NS_main(int argc, NS_tchar **argv) if (result) { WaitForSingleObject(sinfo.hProcess, INFINITE); CloseHandle(sinfo.hProcess); } else { WriteStatusFile(ELEVATION_CANCELED); } - if (argc > argOffset) { - LaunchCallbackApp(argv[3], argc - argOffset, argv + argOffset); + if (argc > callbackIndex) { + LaunchCallbackApp(argv[4], argc - callbackIndex, argv + callbackIndex); } CloseHandle(elevatedFileHandle); return 0; } } #endif LogInit(); - LOG(("SOURCE DIRECTORY " LOG_S "\n", gSourcePath)); - - // The destination directory (the same as the working-dir argument) does not - // have to be specified when updating manually. - if (argc > argOffset - 1) { - LOG(("DESTINATION DIRECTORY " LOG_S "\n", argv[3])); - } + LOG(("SOURCE DIRECTORY " LOG_S "\n", argv[1])); + LOG(("DESTINATION DIRECTORY " LOG_S "\n", argv[2])); #ifdef WINCE // This is the working directory to apply the update and is required on WinCE // since it doesn't have the concept of a working directory. - gDestPath = argv[3]; + gDestPath = argv[2]; #endif #ifdef XP_WIN HANDLE callbackFile = INVALID_HANDLE_VALUE; NS_tchar callbackBackupPath[MAXPATHLEN]; - if (argc > argOffset) { + if (argc > callbackIndex) { // FindFirstFileW is used to get the callback's filename for comparison // with the callback's patch since it will return the correct case and the // long name instead of the 8.3 format name. HANDLE hFindFile; - hFindFile = FindFirstFileW(argv[argOffset], &gFFData); + hFindFile = FindFirstFileW(argv[callbackIndex], &gFFData); if (hFindFile == INVALID_HANDLE_VALUE) { - LOG(("NS_main: unable to find callback file: " LOG_S "\n", argv[argOffset])); + LOG(("NS_main: unable to find callback file: " LOG_S "\n", argv[callbackIndex])); LogFinish(); WriteStatusFile(WRITE_ERROR); EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1); - LaunchCallbackApp(argv[3], argc - argOffset, argv + argOffset); + LaunchCallbackApp(argv[4], argc - callbackIndex, argv + callbackIndex); return 1; } FindClose(hFindFile); // Make a copy of the callback executable. NS_tsnprintf(callbackBackupPath, sizeof(callbackBackupPath)/sizeof(callbackBackupPath[0]), - NS_T("%s" CALLBACK_BACKUP_EXT), argv[argOffset]); + NS_T("%s" CALLBACK_BACKUP_EXT), argv[callbackIndex]); NS_tremove(callbackBackupPath); - CopyFileW(argv[argOffset], callbackBackupPath, FALSE); + CopyFileW(argv[callbackIndex], callbackBackupPath, FALSE); // By opening a file handle to the callback executable, the OS will prevent // launching the process while it is being updated. - callbackFile = CreateFileW(argv[argOffset], + callbackFile = CreateFileW(argv[callbackIndex], #ifdef WINCE GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, #else DELETE | GENERIC_WRITE, 0, // no sharing! #endif NULL, OPEN_EXISTING, 0, NULL); // CreateFileW will fail if the callback executable is already in use. Since // it isn't possible to update write the status file and return. if (callbackFile == INVALID_HANDLE_VALUE) { LOG(("NS_main: file in use - failed to exclusively open executable " \ - "file: " LOG_S "\n", argv[argOffset])); + "file: " LOG_S "\n", argv[callbackIndex])); LogFinish(); WriteStatusFile(WRITE_ERROR); NS_tremove(callbackBackupPath); EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1); - LaunchCallbackApp(argv[3], argc - argOffset, argv + argOffset); + LaunchCallbackApp(argv[4], argc - callbackIndex, argv + callbackIndex); return 1; } } #endif BigBuffer = (char *)malloc(BigBufferSize); if (!BigBuffer) { LOG(("NS_main: failed to allocate default buffer of %i. Trying 1K " \ @@ -1691,58 +1693,59 @@ int NS_main(int argc, NS_tchar **argv) LOG(("NS_main: failed to allocate 1K buffer - exiting\n")); LogFinish(); WriteStatusFile(MEM_ERROR); #ifdef XP_WIN CloseHandle(callbackFile); NS_tremove(callbackBackupPath); EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1); #endif - LaunchCallbackApp(argv[3], argc - argOffset, argv + argOffset); + if (argc > callbackIndex) + LaunchCallbackApp(argv[4], argc - callbackIndex, argv + callbackIndex); return 1; } } // Run update process on a background thread. ShowProgressUI may return // before QuitProgressUI has been called, so wait for UpdateThreadFunc to // terminate. Thread t; if (t.Run(UpdateThreadFunc, NULL) == 0) { ShowProgressUI(); } t.Join(); #ifdef XP_WIN - if (argc > argOffset) { + if (argc > callbackIndex) { CloseHandle(callbackFile); // CopyFile will preserve the case of the destination file if it already // exists. - if (CopyFileW(callbackBackupPath, argv[argOffset], FALSE) != 0) { + if (CopyFileW(callbackBackupPath, argv[callbackIndex], FALSE) != 0) { NS_tremove(callbackBackupPath); } } #endif LogFinish(); free(BigBuffer); BigBuffer = NULL; - if (argc > argOffset) { + if (argc > callbackIndex) { #if defined(XP_WIN) && !defined(WINCE) if (gSucceeded) { - LaunchWinPostProcess(argv[argOffset]); + LaunchWinPostProcess(argv[callbackIndex]); } EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0); #endif #ifdef XP_MACOSX if (gSucceeded) { - LaunchMacPostProcess(argv[argOffset]); + LaunchMacPostProcess(argv[callbackIndex]); } #endif /* XP_MACOSX */ - LaunchCallbackApp(argv[3], argc - argOffset, argv + argOffset); + LaunchCallbackApp(argv[3], argc - callbackIndex, argv + callbackIndex); } return 0; } class ActionList { public:
--- a/toolkit/xre/nsUpdateDriver.cpp +++ b/toolkit/xre/nsUpdateDriver.cpp @@ -18,16 +18,17 @@ * The Initial Developer of the Original Code is Google Inc. * Portions created by the Initial Developer are Copyright (C) 2005 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Darin Fisher <darin@meer.net> * Ben Turner <mozilla@songbirdnest.com> * Robert Strong <robert.bugzilla@gmail.com> + * Josh Aas <josh@mozilla.com> * * 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 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your @@ -50,16 +51,17 @@ #include "prproces.h" #include "prlog.h" #include "prenv.h" #include "nsVersionComparator.h" #ifdef XP_MACOSX #include "nsILocalFileMac.h" #include "nsCommandLineServiceMac.h" +#include "MacLaunchHelper.h" #endif #if defined(XP_WIN) # include <direct.h> # include <process.h> # include <windows.h> # define getcwd(path, size) _getcwd(path, size) # define getpid() GetCurrentProcessId() @@ -74,17 +76,17 @@ // // We use execv to spawn the updater process on all UNIX systems except Mac OSX // since it is known to cause problems on the Mac. Windows has execv, but it // is a faked implementation that doesn't really replace the current process. // Instead it spawns a new process, so we gain nothing from using execv on // Windows. // // On platforms where we are not calling execv, we may need to make the -// udpaterfail executable wait for the calling process to exit. Otherwise, the +// updater executable wait for the calling process to exit. Otherwise, the // updater may have trouble modifying our executable image (because it might // still be in use). This is accomplished by passing our PID to the updater so // that it can wait for us to exit. This is not perfect as there is a race // condition that could bite us. It's possible that the calling process could // exit before the updater waits on the specified PID, and in the meantime a // new process with the same PID could be created. This situation is unlikely, // however, given the way most operating systems recycle PIDs. We'll take our // chances ;-) @@ -131,53 +133,40 @@ GetCurrentWorkingDir(char *buf, size_t s #else if(!getcwd(buf, size)) return NS_ERROR_FAILURE; #endif return NS_OK; } #if defined(XP_MACOSX) - // This is a copy of OS X's XRE_GetBinaryPath from nsAppRunner.cpp with the // gBinaryPath check removed so that the updater can reload the stub executable // instead of xulrunner-bin. See bug 349737. static nsresult GetXULRunnerStubPath(const char* argv0, nsILocalFile* *aResult) { - nsresult rv; - nsCOMPtr<nsILocalFile> lf; - - NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(lf)); - nsCOMPtr<nsILocalFileMac> lfm (do_QueryInterface(lf)); - if (!lfm) - return NS_ERROR_FAILURE; - // Works even if we're not bundled. - CFBundleRef appBundle = CFBundleGetMainBundle(); + CFBundleRef appBundle = ::CFBundleGetMainBundle(); if (!appBundle) return NS_ERROR_FAILURE; - CFURLRef bundleURL = CFBundleCopyExecutableURL(appBundle); + CFURLRef bundleURL = ::CFBundleCopyExecutableURL(appBundle); if (!bundleURL) return NS_ERROR_FAILURE; - FSRef fileRef; - if (!CFURLGetFSRef(bundleURL, &fileRef)) { - CFRelease(bundleURL); - return NS_ERROR_FAILURE; - } + nsCOMPtr<nsILocalFileMac> lfm; + nsresult rv = NS_NewLocalFileWithCFURL(bundleURL, PR_TRUE, getter_AddRefs(lfm)); - rv = lfm->InitWithFSRef(&fileRef); - CFRelease(bundleURL); + ::CFRelease(bundleURL); if (NS_FAILED(rv)) return rv; - NS_ADDREF(*aResult = lf); + NS_ADDREF(*aResult = static_cast<nsILocalFile*>(lfm.get())); return NS_OK; } #endif /* XP_MACOSX */ static PRBool GetFile(nsIFile *dir, const nsCSubstring &name, nsCOMPtr<nsILocalFile> &result) { nsresult rv; @@ -451,71 +440,58 @@ ApplyUpdate(nsIFile *greDir, nsIFile *up // we pass "0" which is then ignored by the updater. #if defined(USE_EXECV) NS_NAMED_LITERAL_CSTRING(pid, "0"); #else nsCAutoString pid; pid.AppendInt((PRInt32) getpid()); #endif - int argc = appArgc + 4; + int argc = appArgc + 5; char **argv = new char*[argc + 1]; if (!argv) return; argv[0] = (char*) updaterPath.get(); argv[1] = (char*) updateDirPath.get(); - argv[2] = (char*) pid.get(); + argv[2] = (char*) applyToDir.get(); + argv[3] = (char*) pid.get(); if (appArgc) { - argv[3] = workingDirPath; - argv[4] = (char*) appFilePath.get(); + argv[4] = workingDirPath; + argv[5] = (char*) appFilePath.get(); for (int i = 1; i < appArgc; ++i) - argv[4 + i] = appArgv[i]; - argv[4 + appArgc] = nsnull; + argv[5 + i] = appArgv[i]; + argc = 5 + appArgc; + argv[argc] = NULL; } else { - argv[3] = nsnull; - argc = 3; + argc = 4; + argv[4] = NULL; } if (gSafeMode) { PR_SetEnv("MOZ_SAFE_MODE_RESTART=1"); } LOG(("spawning updater process [%s]\n", updaterPath.get())); #if defined(USE_EXECV) - chdir(applyToDir.get()); execv(updaterPath.get(), argv); #elif defined(XP_WIN) - _wchdir(applyToDir.get()); - - if (!WinLaunchChild(updaterPathW.get(), appArgc + 4, argv)) + if (!WinLaunchChild(updaterPathW.get(), argc, argv)) return; _exit(0); +#elif defined(XP_MACOSX) + CommandLineServiceMac::SetupMacCommandLine(argc, argv, PR_TRUE); + // LaunchChildMac uses posix_spawnp and prefers the current + // architecture when launching. It doesn't require a + // null-terminated string but it doesn't matter if we pass one. + LaunchChildMac(argc, argv); + exit(0); #else - PRStatus status; - PRProcessAttr *attr; - - attr = PR_NewProcessAttr(); - if (!attr) - goto end; - - status = PR_ProcessAttrSetCurrentDirectory(attr, applyToDir.get()); - if (status != PR_SUCCESS) - goto end; - -#ifdef XP_MACOSX - CommandLineServiceMac::SetupMacCommandLine(argc, argv, PR_TRUE); -#endif - - PR_CreateProcessDetached(updaterPath.get(), argv, nsnull, attr); + PR_CreateProcessDetached(updaterPath.get(), argv, NULL, NULL); exit(0); - -end: - PR_DestroyProcessAttr(attr); - delete[] argv; #endif } nsresult ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir, int argc, char **argv, const char *&appVersion) { nsresult rv;