2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
2012-05-21 04:12:37 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "nsUpdateDriver.h"
|
|
|
|
#include "nsXULAppAPI.h"
|
|
|
|
#include "nsAppRunner.h"
|
2012-06-05 19:08:30 -07:00
|
|
|
#include "nsIFile.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsString.h"
|
|
|
|
#include "prproces.h"
|
|
|
|
#include "prlog.h"
|
2010-09-23 21:02:08 -07:00
|
|
|
#include "prenv.h"
|
2008-11-14 04:11:08 -08:00
|
|
|
#include "nsVersionComparator.h"
|
2012-05-22 07:50:04 -07:00
|
|
|
#include "nsXREDirProvider.h"
|
|
|
|
#include "SpecialSystemDirectory.h"
|
|
|
|
#include "nsDirectoryServiceDefs.h"
|
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
#include "nsIXULAppInfo.h"
|
|
|
|
#include "mozilla/Preferences.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef XP_MACOSX
|
|
|
|
#include "nsILocalFileMac.h"
|
|
|
|
#include "nsCommandLineServiceMac.h"
|
2010-10-01 21:11:24 -07:00
|
|
|
#include "MacLaunchHelper.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(XP_WIN)
|
|
|
|
# include <direct.h>
|
|
|
|
# include <process.h>
|
|
|
|
# include <windows.h>
|
2012-05-22 07:50:04 -07:00
|
|
|
# include <shlwapi.h>
|
2007-03-22 10:30:00 -07:00
|
|
|
# define getcwd(path, size) _getcwd(path, size)
|
|
|
|
# define getpid() GetCurrentProcessId()
|
|
|
|
#elif defined(XP_OS2)
|
|
|
|
# include <unistd.h>
|
|
|
|
# define INCL_DOSFILEMGR
|
|
|
|
# include <os2.h>
|
Bug 627277 - Remove (broken) BeOS support. r=biesi,dwitte,gavin,joe,jorendorff,josh,khuey,mfinkle,neil,Pike,roc,shaver,smontagu,taras
2011-02-19 11:10:24 -08:00
|
|
|
#elif defined(XP_UNIX)
|
2007-03-22 10:30:00 -07:00
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
|
|
// 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
|
2010-10-01 21:11:24 -07:00
|
|
|
// updater executable wait for the calling process to exit. Otherwise, the
|
2007-03-22 10:30:00 -07:00
|
|
|
// 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 ;-)
|
|
|
|
//
|
|
|
|
// A similar #define lives in updater.cpp and should be kept in sync with this.
|
|
|
|
//
|
|
|
|
#if defined(XP_UNIX) && !defined(XP_MACOSX)
|
|
|
|
#define USE_EXECV
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
static PRLogModuleInfo *sUpdateLog = PR_NewLogModule("updatedriver");
|
|
|
|
#endif
|
|
|
|
#define LOG(args) PR_LOG(sUpdateLog, PR_LOG_DEBUG, args)
|
|
|
|
|
|
|
|
#ifdef XP_WIN
|
|
|
|
static const char kUpdaterBin[] = "updater.exe";
|
|
|
|
#else
|
|
|
|
static const char kUpdaterBin[] = "updater";
|
|
|
|
#endif
|
|
|
|
static const char kUpdaterINI[] = "updater.ini";
|
|
|
|
#ifdef XP_MACOSX
|
|
|
|
static const char kUpdaterApp[] = "updater.app";
|
|
|
|
#endif
|
2009-02-24 08:53:36 -08:00
|
|
|
#if defined(XP_UNIX) && !defined(XP_MACOSX)
|
|
|
|
static const char kUpdaterPNG[] = "updater.png";
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
static nsresult
|
|
|
|
GetCurrentWorkingDir(char *buf, size_t size)
|
|
|
|
{
|
|
|
|
// Cannot use NS_GetSpecialDirectory because XPCOM is not yet initialized.
|
|
|
|
// This code is duplicated from xpcom/io/SpecialSystemDirectory.cpp:
|
|
|
|
|
|
|
|
#if defined(XP_OS2)
|
|
|
|
if (DosQueryPathInfo( ".", FIL_QUERYFULLNAME, buf, size))
|
|
|
|
return NS_ERROR_FAILURE;
|
2008-01-21 17:20:19 -08:00
|
|
|
#elif defined(XP_WIN)
|
2009-07-29 23:01:50 -07:00
|
|
|
wchar_t wpath[MAX_PATH];
|
|
|
|
if (!_wgetcwd(wpath, size))
|
2008-01-21 17:20:19 -08:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
NS_ConvertUTF16toUTF8 path(wpath);
|
|
|
|
strncpy(buf, path.get(), size);
|
2007-03-22 10:30:00 -07:00
|
|
|
#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
|
2012-06-05 19:08:30 -07:00
|
|
|
GetXULRunnerStubPath(const char* argv0, nsIFile* *aResult)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// Works even if we're not bundled.
|
2010-10-01 21:11:24 -07:00
|
|
|
CFBundleRef appBundle = ::CFBundleGetMainBundle();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!appBundle)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2010-10-01 21:11:24 -07:00
|
|
|
CFURLRef bundleURL = ::CFBundleCopyExecutableURL(appBundle);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!bundleURL)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2010-10-01 21:11:24 -07:00
|
|
|
nsCOMPtr<nsILocalFileMac> lfm;
|
2011-10-17 07:59:28 -07:00
|
|
|
nsresult rv = NS_NewLocalFileWithCFURL(bundleURL, true, getter_AddRefs(lfm));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-10-01 21:11:24 -07:00
|
|
|
::CFRelease(bundleURL);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
|
|
|
|
2012-06-05 19:08:30 -07:00
|
|
|
NS_ADDREF(*aResult = static_cast<nsIFile*>(lfm.get()));
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
#endif /* XP_MACOSX */
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool
|
2012-06-05 19:08:30 -07:00
|
|
|
GetFile(nsIFile *dir, const nsCSubstring &name, nsCOMPtr<nsIFile> &result)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
2008-11-14 04:11:08 -08:00
|
|
|
nsCOMPtr<nsIFile> file;
|
|
|
|
rv = dir->Clone(getter_AddRefs(file));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_FAILED(rv))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-11-14 04:11:08 -08:00
|
|
|
rv = file->AppendNative(name);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_FAILED(rv))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-11-14 04:11:08 -08:00
|
|
|
result = do_QueryInterface(file, &rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_SUCCEEDED(rv);
|
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool
|
2012-06-05 19:08:30 -07:00
|
|
|
GetStatusFile(nsIFile *dir, nsCOMPtr<nsIFile> &result)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
return GetFile(dir, NS_LITERAL_CSTRING("update.status"), result);
|
|
|
|
}
|
|
|
|
|
2012-05-22 07:50:04 -07:00
|
|
|
/**
|
|
|
|
* Get the contents of the update.status file.
|
|
|
|
*
|
|
|
|
* @param statusFile the status file object.
|
|
|
|
* @param buf the buffer holding the file contents
|
|
|
|
*
|
|
|
|
* @return true if successful, false otherwise.
|
|
|
|
*/
|
|
|
|
template <size_t Size>
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool
|
2012-06-05 19:08:30 -07:00
|
|
|
GetStatusFileContents(nsIFile *statusFile, char (&buf)[Size])
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-05-22 07:50:04 -07:00
|
|
|
// The buffer needs to be large enough to hold the known status codes
|
|
|
|
PR_STATIC_ASSERT(Size > 16);
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
PRFileDesc *fd = nullptr;
|
2010-12-07 12:06:22 -08:00
|
|
|
nsresult rv = statusFile->OpenNSPRFileDesc(PR_RDONLY, 0660, &fd);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_FAILED(rv))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
const int32_t n = PR_Read(fd, buf, Size);
|
2010-12-07 12:06:22 -08:00
|
|
|
PR_Close(fd);
|
|
|
|
|
2012-05-22 07:50:04 -07:00
|
|
|
return (n >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
eNoUpdateAction,
|
|
|
|
ePendingUpdate,
|
|
|
|
ePendingService,
|
|
|
|
eAppliedUpdate,
|
|
|
|
eAppliedService
|
|
|
|
} UpdateStatus;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a value indicating what needs to be done in order to handle an update.
|
|
|
|
*
|
|
|
|
* @param dir the directory in which we should look for an update.status file.
|
|
|
|
* @param statusFile the update.status file found in the directory.
|
|
|
|
*
|
|
|
|
* @return the update action to be performed.
|
|
|
|
*/
|
|
|
|
static UpdateStatus
|
2012-06-05 19:08:30 -07:00
|
|
|
GetUpdateStatus(nsIFile* dir, nsCOMPtr<nsIFile> &statusFile)
|
2012-05-22 07:50:04 -07:00
|
|
|
{
|
|
|
|
if (GetStatusFile(dir, statusFile)) {
|
|
|
|
char buf[32];
|
|
|
|
if (GetStatusFileContents(statusFile, buf)) {
|
|
|
|
const char kPending[] = "pending";
|
|
|
|
const char kPendingService[] = "pending-service";
|
|
|
|
const char kApplied[] = "applied";
|
|
|
|
const char kAppliedService[] = "applied-service";
|
|
|
|
if (!strncmp(buf, kPendingService, sizeof(kPendingService) - 1)) {
|
|
|
|
return ePendingService;
|
|
|
|
}
|
|
|
|
if (!strncmp(buf, kPending, sizeof(kPending) - 1)) {
|
|
|
|
return ePendingUpdate;
|
|
|
|
}
|
|
|
|
if (!strncmp(buf, kAppliedService, sizeof(kAppliedService) - 1)) {
|
|
|
|
return eAppliedService;
|
|
|
|
}
|
|
|
|
if (!strncmp(buf, kApplied, sizeof(kApplied) - 1)) {
|
|
|
|
return eAppliedUpdate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return eNoUpdateAction;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool
|
2012-06-05 19:08:30 -07:00
|
|
|
GetVersionFile(nsIFile *dir, nsCOMPtr<nsIFile> &result)
|
2008-11-14 04:11:08 -08:00
|
|
|
{
|
|
|
|
return GetFile(dir, NS_LITERAL_CSTRING("update.version"), result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compares the current application version with the update's application
|
|
|
|
// version.
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool
|
2012-06-05 19:08:30 -07:00
|
|
|
IsOlderVersion(nsIFile *versionFile, const char *appVersion)
|
2008-11-14 04:11:08 -08:00
|
|
|
{
|
2012-07-30 07:20:58 -07:00
|
|
|
PRFileDesc *fd = nullptr;
|
2010-12-07 12:06:22 -08:00
|
|
|
nsresult rv = versionFile->OpenNSPRFileDesc(PR_RDONLY, 0660, &fd);
|
2008-11-14 04:11:08 -08:00
|
|
|
if (NS_FAILED(rv))
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2008-11-14 04:11:08 -08:00
|
|
|
|
|
|
|
char buf[32];
|
2012-08-22 08:56:38 -07:00
|
|
|
const int32_t n = PR_Read(fd, buf, sizeof(buf));
|
2010-12-07 12:06:22 -08:00
|
|
|
PR_Close(fd);
|
|
|
|
|
|
|
|
if (n < 0)
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2008-11-14 04:11:08 -08:00
|
|
|
|
2010-12-07 12:06:22 -08:00
|
|
|
// Trim off the trailing newline
|
|
|
|
if (buf[n - 1] == '\n')
|
|
|
|
buf[n - 1] = '\0';
|
2009-06-15 12:48:30 -07:00
|
|
|
|
2008-11-14 04:11:08 -08:00
|
|
|
// If the update xml doesn't provide the application version the file will
|
|
|
|
// contain the string "null" and it is assumed that the update is not older.
|
|
|
|
const char kNull[] = "null";
|
|
|
|
if (strncmp(buf, kNull, sizeof(kNull) - 1) == 0)
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2008-11-14 04:11:08 -08:00
|
|
|
|
2012-04-18 20:22:29 -07:00
|
|
|
if (mozilla::Version(appVersion) > buf)
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2008-11-14 04:11:08 -08:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2008-11-14 04:11:08 -08:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool
|
2008-08-14 09:08:03 -07:00
|
|
|
CopyFileIntoUpdateDir(nsIFile *parentDir, const char *leafName, nsIFile *updateDir)
|
|
|
|
{
|
|
|
|
nsDependentCString leaf(leafName);
|
|
|
|
nsCOMPtr<nsIFile> file;
|
|
|
|
|
|
|
|
// Make sure there is not an existing file in the target location.
|
|
|
|
nsresult rv = updateDir->Clone(getter_AddRefs(file));
|
|
|
|
if (NS_FAILED(rv))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2008-08-14 09:08:03 -07:00
|
|
|
rv = file->AppendNative(leaf);
|
|
|
|
if (NS_FAILED(rv))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2012-05-22 07:50:04 -07:00
|
|
|
file->Remove(true);
|
2008-08-14 09:08:03 -07:00
|
|
|
|
|
|
|
// Now, copy into the target location.
|
|
|
|
rv = parentDir->Clone(getter_AddRefs(file));
|
|
|
|
if (NS_FAILED(rv))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2008-08-14 09:08:03 -07:00
|
|
|
rv = file->AppendNative(leaf);
|
|
|
|
if (NS_FAILED(rv))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2008-08-14 09:08:03 -07:00
|
|
|
rv = file->CopyToNative(updateDir, EmptyCString());
|
|
|
|
if (NS_FAILED(rv))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2008-08-14 09:08:03 -07:00
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2008-08-14 09:08:03 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
static bool
|
2007-03-22 10:30:00 -07:00
|
|
|
CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir,
|
|
|
|
nsCOMPtr<nsIFile> &updater)
|
|
|
|
{
|
2008-08-14 09:08:03 -07:00
|
|
|
// Copy the updater application from the GRE and the updater ini from the app
|
2007-03-22 10:30:00 -07:00
|
|
|
#if defined(XP_MACOSX)
|
2008-08-14 09:08:03 -07:00
|
|
|
if (!CopyFileIntoUpdateDir(greDir, kUpdaterApp, updateDir))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
#else
|
2008-08-14 09:08:03 -07:00
|
|
|
if (!CopyFileIntoUpdateDir(greDir, kUpdaterBin, updateDir))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2008-08-14 09:08:03 -07:00
|
|
|
CopyFileIntoUpdateDir(appDir, kUpdaterINI, updateDir);
|
2012-03-21 15:50:53 -07:00
|
|
|
#if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(ANDROID)
|
2009-02-24 08:53:36 -08:00
|
|
|
nsCOMPtr<nsIFile> iconDir;
|
|
|
|
appDir->Clone(getter_AddRefs(iconDir));
|
|
|
|
iconDir->AppendNative(NS_LITERAL_CSTRING("icons"));
|
|
|
|
if (!CopyFileIntoUpdateDir(iconDir, kUpdaterPNG, updateDir))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2009-02-24 08:53:36 -08:00
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
// Finally, return the location of the updater binary.
|
2008-08-14 09:08:03 -07:00
|
|
|
nsresult rv = updateDir->Clone(getter_AddRefs(updater));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_FAILED(rv))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
#if defined(XP_MACOSX)
|
|
|
|
rv = updater->AppendNative(NS_LITERAL_CSTRING(kUpdaterApp));
|
|
|
|
rv |= updater->AppendNative(NS_LITERAL_CSTRING("Contents"));
|
|
|
|
rv |= updater->AppendNative(NS_LITERAL_CSTRING("MacOS"));
|
|
|
|
if (NS_FAILED(rv))
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
rv = updater->AppendNative(NS_LITERAL_CSTRING(kUpdaterBin));
|
|
|
|
return NS_SUCCEEDED(rv);
|
|
|
|
}
|
|
|
|
|
2012-05-22 07:50:04 -07:00
|
|
|
/**
|
|
|
|
* Switch an existing application directory to an updated version which has been
|
|
|
|
* previously constructed in the background.
|
|
|
|
*
|
|
|
|
* @param greDir the GRE dir
|
|
|
|
* @param updateDir the update root dir
|
|
|
|
* @param statusFile the update.status file
|
|
|
|
* @param appDir the app dir
|
|
|
|
* @param appArgc the number of args to the application
|
|
|
|
* @param appArgv the args to the application, used for restarting if needed
|
|
|
|
*/
|
|
|
|
static void
|
2012-06-05 19:08:30 -07:00
|
|
|
SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
|
2012-05-22 07:50:04 -07:00
|
|
|
nsIFile *appDir, int appArgc, char **appArgv)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// Steps:
|
|
|
|
// - copy updater into temp dir
|
|
|
|
// - run updater with the correct arguments
|
|
|
|
|
2012-06-05 19:08:30 -07:00
|
|
|
nsCOMPtr<nsIFile> tmpDir;
|
2012-05-22 07:50:04 -07:00
|
|
|
GetSpecialSystemDirectory(OS_TemporaryDirectory,
|
|
|
|
getter_AddRefs(tmpDir));
|
|
|
|
if (!tmpDir) {
|
|
|
|
LOG(("failed getting a temp dir\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to create our own new temp directory in case there is already an
|
|
|
|
// updater binary in the OS temporary location which we cannot write to.
|
|
|
|
// Note that we don't check for errors here, as if this directory can't
|
|
|
|
// be created, the following CopyUpdaterIntoUpdateDir call will fail.
|
|
|
|
tmpDir->Append(NS_LITERAL_STRING("MozUpdater"));
|
|
|
|
tmpDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0755);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIFile> updater;
|
|
|
|
if (!CopyUpdaterIntoUpdateDir(greDir, appDir, tmpDir, updater)) {
|
|
|
|
LOG(("failed copying updater\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to use the value returned from XRE_GetBinaryPath when attempting
|
|
|
|
// to restart the running application.
|
2012-06-05 19:08:30 -07:00
|
|
|
nsCOMPtr<nsIFile> appFile;
|
2012-05-22 07:50:04 -07:00
|
|
|
|
|
|
|
#if defined(XP_MACOSX)
|
|
|
|
// On OS X we need to pass the location of the xulrunner-stub executable
|
|
|
|
// rather than xulrunner-bin. See bug 349737.
|
|
|
|
GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile));
|
|
|
|
#else
|
|
|
|
XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!appFile)
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef XP_WIN
|
|
|
|
nsAutoString appFilePathW;
|
|
|
|
rv = appFile->GetPath(appFilePathW);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
NS_ConvertUTF16toUTF8 appFilePath(appFilePathW);
|
|
|
|
|
|
|
|
nsAutoString updaterPathW;
|
|
|
|
rv = updater->GetPath(updaterPathW);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
NS_ConvertUTF16toUTF8 updaterPath(updaterPathW);
|
|
|
|
|
|
|
|
#else
|
|
|
|
nsCAutoString appFilePath;
|
|
|
|
rv = appFile->GetNativePath(appFilePath);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsCAutoString updaterPath;
|
|
|
|
rv = updater->GetNativePath(updaterPath);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Get the directory to which the update will be applied. On Mac OSX we need
|
|
|
|
// to apply the update to the Updated.app directory under the Foo.app
|
|
|
|
// directory which is the parent of the parent of the appDir. On other
|
|
|
|
// platforms we will just apply to the appDir/updated.
|
2012-06-05 19:08:30 -07:00
|
|
|
nsCOMPtr<nsIFile> updatedDir;
|
2012-05-22 07:50:04 -07:00
|
|
|
#if defined(XP_MACOSX)
|
|
|
|
nsCAutoString applyToDir;
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIFile> parentDir1, parentDir2;
|
|
|
|
rv = appDir->GetParent(getter_AddRefs(parentDir1));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
rv = parentDir1->GetParent(getter_AddRefs(parentDir2));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
if (!GetFile(parentDir2, NS_LITERAL_CSTRING("Updated.app"), updatedDir))
|
|
|
|
return;
|
|
|
|
rv = updatedDir->GetNativePath(applyToDir);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir))
|
|
|
|
return;
|
|
|
|
#if defined(XP_WIN)
|
|
|
|
nsAutoString applyToDirW;
|
|
|
|
rv = updatedDir->GetPath(applyToDirW);
|
|
|
|
|
|
|
|
NS_ConvertUTF16toUTF8 applyToDir(applyToDirW);
|
|
|
|
#else
|
|
|
|
nsCAutoString applyToDir;
|
|
|
|
rv = updatedDir->GetNativePath(applyToDir);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Make sure that the updated directory exists
|
|
|
|
bool updatedDirExists = false;
|
|
|
|
updatedDir->Exists(&updatedDirExists);
|
|
|
|
if (!updatedDirExists) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(XP_WIN)
|
|
|
|
nsAutoString updateDirPathW;
|
|
|
|
rv = updateDir->GetPath(updateDirPathW);
|
|
|
|
|
|
|
|
NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW);
|
|
|
|
#else
|
|
|
|
nsCAutoString updateDirPath;
|
|
|
|
rv = updateDir->GetNativePath(updateDirPath);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Get the current working directory.
|
|
|
|
char workingDirPath[MAXPATHLEN];
|
|
|
|
rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Construct the PID argument for this process. If we are using execv, then
|
|
|
|
// we pass "0" which is then ignored by the updater.
|
|
|
|
#if defined(USE_EXECV)
|
|
|
|
nsCAutoString pid("0");
|
|
|
|
#else
|
|
|
|
nsCAutoString pid;
|
2012-08-22 08:56:38 -07:00
|
|
|
pid.AppendInt((int32_t) getpid());
|
2012-05-22 07:50:04 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Append a special token to the PID in order to let the updater know that it
|
|
|
|
// just needs to replace the update directory.
|
|
|
|
pid.AppendASCII("/replace");
|
|
|
|
|
|
|
|
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*) applyToDir.get();
|
|
|
|
argv[3] = (char*) pid.get();
|
|
|
|
if (appArgc) {
|
|
|
|
argv[4] = workingDirPath;
|
|
|
|
argv[5] = (char*) appFilePath.get();
|
|
|
|
for (int i = 1; i < appArgc; ++i)
|
|
|
|
argv[5 + i] = appArgv[i];
|
|
|
|
argc = 5 + appArgc;
|
|
|
|
argv[argc] = NULL;
|
|
|
|
} else {
|
|
|
|
argc = 4;
|
|
|
|
argv[4] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gSafeMode) {
|
|
|
|
PR_SetEnv("MOZ_SAFE_MODE_RESTART=1");
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG(("spawning updater process for replacing [%s]\n", updaterPath.get()));
|
|
|
|
|
|
|
|
#if defined(USE_EXECV)
|
|
|
|
execv(updaterPath.get(), argv);
|
|
|
|
#elif defined(XP_WIN)
|
|
|
|
// Switch the application using updater.exe
|
|
|
|
if (!WinLaunchChild(updaterPathW.get(), argc, argv)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_exit(0);
|
|
|
|
#elif defined(XP_MACOSX)
|
|
|
|
CommandLineServiceMac::SetupMacCommandLine(argc, argv, 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
|
|
|
|
PR_CreateProcessDetached(updaterPath.get(), argv, NULL, NULL);
|
|
|
|
exit(0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Apply an update, possibly in the background.
|
|
|
|
*
|
|
|
|
* @param greDir the GRE dir
|
|
|
|
* @param updateDir the update root dir
|
|
|
|
* @param statusFile the update.status file
|
|
|
|
* @param appDir the app dir
|
|
|
|
* @param appArgc the number of args to the application
|
|
|
|
* @param appArgv the args to the application, used for restarting if needed
|
|
|
|
* @param restart if true, apply the update in the foreground and restart the
|
|
|
|
* application when done. otherwise, apply the update in the
|
|
|
|
* background and don't restart the application.
|
|
|
|
* @param outpid out parameter holding the handle to the updater application for
|
|
|
|
* background updates.
|
|
|
|
*/
|
2007-03-22 10:30:00 -07:00
|
|
|
static void
|
2012-06-05 19:08:30 -07:00
|
|
|
ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
|
2012-05-22 07:50:04 -07:00
|
|
|
nsIFile *appDir, int appArgc, char **appArgv, bool restart,
|
|
|
|
ProcessType *outpid)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-01-18 08:27:44 -08:00
|
|
|
nsresult rv;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Steps:
|
|
|
|
// - mark update as 'applying'
|
|
|
|
// - copy updater into update dir
|
|
|
|
// - run updater w/ appDir as the current working dir
|
|
|
|
|
|
|
|
nsCOMPtr<nsIFile> updater;
|
|
|
|
if (!CopyUpdaterIntoUpdateDir(greDir, appDir, updateDir, updater)) {
|
|
|
|
LOG(("failed copying updater\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to use the value returned from XRE_GetBinaryPath when attempting
|
|
|
|
// to restart the running application.
|
2012-06-05 19:08:30 -07:00
|
|
|
nsCOMPtr<nsIFile> appFile;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#if defined(XP_MACOSX)
|
|
|
|
// On OS X we need to pass the location of the xulrunner-stub executable
|
|
|
|
// rather than xulrunner-bin. See bug 349737.
|
|
|
|
GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile));
|
|
|
|
#else
|
|
|
|
XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!appFile)
|
|
|
|
return;
|
2008-01-18 08:27:44 -08:00
|
|
|
|
|
|
|
#ifdef XP_WIN
|
|
|
|
nsAutoString appFilePathW;
|
|
|
|
rv = appFile->GetPath(appFilePathW);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
NS_ConvertUTF16toUTF8 appFilePath(appFilePathW);
|
|
|
|
|
|
|
|
nsAutoString updaterPathW;
|
|
|
|
rv = updater->GetPath(updaterPathW);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
NS_ConvertUTF16toUTF8 updaterPath(updaterPathW);
|
|
|
|
|
|
|
|
#else
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCAutoString appFilePath;
|
2008-01-18 08:27:44 -08:00
|
|
|
rv = appFile->GetNativePath(appFilePath);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsCAutoString updaterPath;
|
|
|
|
rv = updater->GetNativePath(updaterPath);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
2008-01-18 08:27:44 -08:00
|
|
|
#endif
|
2007-12-31 07:15:43 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Get the directory to which the update will be applied. On Mac OSX we need
|
2012-05-22 07:50:04 -07:00
|
|
|
// to apply the update to the Updated.app directory under the Foo.app
|
|
|
|
// directory which is the parent of the parent of the appDir. On other
|
|
|
|
// platforms we will just apply to the appDir/updated.
|
2012-06-05 19:08:30 -07:00
|
|
|
nsCOMPtr<nsIFile> updatedDir;
|
2007-03-22 10:30:00 -07:00
|
|
|
#if defined(XP_MACOSX)
|
2008-01-18 08:27:44 -08:00
|
|
|
nsCAutoString applyToDir;
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIFile> parentDir1, parentDir2;
|
|
|
|
rv = appDir->GetParent(getter_AddRefs(parentDir1));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
rv = parentDir1->GetParent(getter_AddRefs(parentDir2));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
2012-05-22 07:50:04 -07:00
|
|
|
if (restart) {
|
|
|
|
// Use the correct directory if we're not applying the update in the
|
|
|
|
// background.
|
|
|
|
rv = parentDir2->GetNativePath(applyToDir);
|
|
|
|
} else {
|
|
|
|
if (!GetFile(parentDir2, NS_LITERAL_CSTRING("Updated.app"), updatedDir))
|
|
|
|
return;
|
|
|
|
rv = updatedDir->GetNativePath(applyToDir);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-05-22 07:50:04 -07:00
|
|
|
#else
|
|
|
|
if (restart) {
|
|
|
|
// Use the correct directory if we're not applying the update in the
|
|
|
|
// background.
|
|
|
|
updatedDir = do_QueryInterface(appDir);
|
|
|
|
} else if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#if defined(XP_WIN)
|
2010-10-03 12:47:00 -07:00
|
|
|
nsAutoString applyToDirW;
|
2012-05-22 07:50:04 -07:00
|
|
|
rv = updatedDir->GetPath(applyToDirW);
|
2010-10-03 12:47:00 -07:00
|
|
|
|
|
|
|
NS_ConvertUTF16toUTF8 applyToDir(applyToDirW);
|
2007-03-22 10:30:00 -07:00
|
|
|
#else
|
2008-01-18 08:27:44 -08:00
|
|
|
nsCAutoString applyToDir;
|
2012-05-22 07:50:04 -07:00
|
|
|
rv = updatedDir->GetNativePath(applyToDir);
|
|
|
|
#endif
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
2008-01-21 17:20:19 -08:00
|
|
|
#if defined(XP_WIN)
|
|
|
|
nsAutoString updateDirPathW;
|
|
|
|
rv = updateDir->GetPath(updateDirPathW);
|
|
|
|
|
|
|
|
NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW);
|
|
|
|
#else
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCAutoString updateDirPath;
|
|
|
|
rv = updateDir->GetNativePath(updateDirPath);
|
2008-01-21 17:20:19 -08:00
|
|
|
#endif
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Get the current working directory.
|
|
|
|
char workingDirPath[MAXPATHLEN];
|
|
|
|
rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
2012-01-04 20:19:15 -08:00
|
|
|
// We used to write out "Applying" to the update.status file here.
|
|
|
|
// Instead we do this from within the updater application now.
|
|
|
|
// This is so that we don't overwrite the status of pending-service
|
|
|
|
// in the Windows case. This change was made for all platforms so
|
|
|
|
// that it stays consistent across all OS.
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Construct the PID argument for this process. If we are using execv, then
|
|
|
|
// we pass "0" which is then ignored by the updater.
|
2012-05-22 07:50:04 -07:00
|
|
|
nsCAutoString pid;
|
|
|
|
if (!restart) {
|
|
|
|
// Signal the updater application that it should apply the update in the
|
|
|
|
// background.
|
|
|
|
pid.AssignASCII("-1");
|
|
|
|
} else {
|
2007-03-22 10:30:00 -07:00
|
|
|
#if defined(USE_EXECV)
|
2012-05-22 07:50:04 -07:00
|
|
|
pid.AssignASCII("0");
|
2007-03-22 10:30:00 -07:00
|
|
|
#else
|
2012-08-22 08:56:38 -07:00
|
|
|
pid.AppendInt((int32_t) getpid());
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
2012-05-22 07:50:04 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-10-01 21:11:24 -07:00
|
|
|
int argc = appArgc + 5;
|
2007-03-22 10:30:00 -07:00
|
|
|
char **argv = new char*[argc + 1];
|
|
|
|
if (!argv)
|
|
|
|
return;
|
|
|
|
argv[0] = (char*) updaterPath.get();
|
|
|
|
argv[1] = (char*) updateDirPath.get();
|
2010-10-01 21:11:24 -07:00
|
|
|
argv[2] = (char*) applyToDir.get();
|
|
|
|
argv[3] = (char*) pid.get();
|
2012-05-22 07:50:04 -07:00
|
|
|
if (restart && appArgc) {
|
2010-10-01 21:11:24 -07:00
|
|
|
argv[4] = workingDirPath;
|
|
|
|
argv[5] = (char*) appFilePath.get();
|
2007-03-22 10:30:00 -07:00
|
|
|
for (int i = 1; i < appArgc; ++i)
|
2010-10-01 21:11:24 -07:00
|
|
|
argv[5 + i] = appArgv[i];
|
|
|
|
argc = 5 + appArgc;
|
|
|
|
argv[argc] = NULL;
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2010-10-01 21:11:24 -07:00
|
|
|
argc = 4;
|
|
|
|
argv[4] = NULL;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2010-09-23 21:02:08 -07:00
|
|
|
if (gSafeMode) {
|
|
|
|
PR_SetEnv("MOZ_SAFE_MODE_RESTART=1");
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
LOG(("spawning updater process [%s]\n", updaterPath.get()));
|
|
|
|
|
|
|
|
#if defined(USE_EXECV)
|
2012-05-22 07:50:04 -07:00
|
|
|
// Don't use execv for background updates.
|
|
|
|
if (restart) {
|
|
|
|
execv(updaterPath.get(), argv);
|
|
|
|
} else {
|
|
|
|
*outpid = PR_CreateProcess(updaterPath.get(), argv, NULL, NULL);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
#elif defined(XP_WIN)
|
2012-01-04 20:19:15 -08:00
|
|
|
// Launch the update using updater.exe
|
2012-05-22 07:50:04 -07:00
|
|
|
if (!WinLaunchChild(updaterPathW.get(), argc, argv, NULL, outpid)) {
|
2012-01-04 20:19:15 -08:00
|
|
|
return;
|
2012-01-04 20:19:14 -08:00
|
|
|
}
|
|
|
|
|
2012-05-22 07:50:04 -07:00
|
|
|
if (restart) {
|
|
|
|
// We are going to process an update so we should exit now
|
|
|
|
_exit(0);
|
|
|
|
}
|
2010-10-01 21:11:24 -07:00
|
|
|
#elif defined(XP_MACOSX)
|
2011-10-17 07:59:28 -07:00
|
|
|
CommandLineServiceMac::SetupMacCommandLine(argc, argv, true);
|
2010-10-01 21:11:24 -07:00
|
|
|
// 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.
|
2012-05-22 07:50:04 -07:00
|
|
|
LaunchChildMac(argc, argv, 0, outpid);
|
|
|
|
if (restart) {
|
|
|
|
exit(0);
|
|
|
|
}
|
2010-10-01 21:11:24 -07:00
|
|
|
#else
|
2012-05-22 07:50:04 -07:00
|
|
|
*outpid = PR_CreateProcess(updaterPath.get(), argv, NULL, NULL);
|
|
|
|
if (restart) {
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wait for a process until it terminates. This call is blocking.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
WaitForProcess(ProcessType pt)
|
|
|
|
{
|
|
|
|
#if defined(XP_WIN)
|
|
|
|
WaitForSingleObject(pt, INFINITE);
|
|
|
|
CloseHandle(pt);
|
|
|
|
#elif defined(XP_MACOSX)
|
|
|
|
waitpid(pt, 0, 0);
|
|
|
|
#else
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t exitCode;
|
2012-05-22 07:50:04 -07:00
|
|
|
PR_WaitProcess(pt, &exitCode);
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir,
|
2012-05-22 07:50:04 -07:00
|
|
|
int argc, char **argv, const char *appVersion,
|
|
|
|
bool restart, ProcessType *pid)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIFile> updatesDir;
|
|
|
|
rv = updRootDir->Clone(getter_AddRefs(updatesDir));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
2010-12-07 12:06:05 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
rv = updatesDir->AppendNative(NS_LITERAL_CSTRING("updates"));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
|
|
|
|
2010-08-17 17:09:07 -07:00
|
|
|
rv = updatesDir->AppendNative(NS_LITERAL_CSTRING("0"));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
2012-01-04 20:19:14 -08:00
|
|
|
|
2012-05-22 07:50:04 -07:00
|
|
|
ProcessType dummyPID; // this will only be used for MOZ_UPDATE_BACKGROUND
|
2012-01-04 20:19:14 -08:00
|
|
|
const char *processingUpdates = PR_GetEnv("MOZ_PROCESS_UPDATES");
|
|
|
|
if (processingUpdates && *processingUpdates) {
|
|
|
|
// Enable the tests to request us to use a different update root directory
|
|
|
|
const char *updRootOverride = PR_GetEnv("MOZ_UPDATE_ROOT_OVERRIDE");
|
|
|
|
if (updRootOverride && *updRootOverride) {
|
2012-06-05 19:08:30 -07:00
|
|
|
nsCOMPtr<nsIFile> overrideDir;
|
2012-01-04 20:19:14 -08:00
|
|
|
nsCAutoString path(updRootOverride);
|
|
|
|
rv = NS_NewNativeLocalFile(path, false, getter_AddRefs(overrideDir));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
updatesDir = do_QueryInterface(overrideDir);
|
|
|
|
}
|
|
|
|
// Enable the tests to request us to use a different app directory
|
|
|
|
const char *appDirOverride = PR_GetEnv("MOZ_UPDATE_APPDIR_OVERRIDE");
|
|
|
|
if (appDirOverride && *appDirOverride) {
|
2012-06-05 19:08:30 -07:00
|
|
|
nsCOMPtr<nsIFile> overrideDir;
|
2012-01-04 20:19:14 -08:00
|
|
|
nsCAutoString path(appDirOverride);
|
|
|
|
rv = NS_NewNativeLocalFile(path, false, getter_AddRefs(overrideDir));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
NS_ADDREF(appDir = overrideDir);
|
|
|
|
}
|
2012-05-22 07:50:04 -07:00
|
|
|
// Enable the tests to request us to perform a background update
|
|
|
|
const char *backgroundUpdate = PR_GetEnv("MOZ_UPDATE_BACKGROUND");
|
|
|
|
if (backgroundUpdate && *backgroundUpdate) {
|
|
|
|
restart = false;
|
|
|
|
pid = &dummyPID;
|
|
|
|
}
|
2012-01-04 20:19:14 -08:00
|
|
|
}
|
2010-08-17 17:09:07 -07:00
|
|
|
|
2012-06-05 19:08:30 -07:00
|
|
|
nsCOMPtr<nsIFile> statusFile;
|
2012-05-22 07:50:04 -07:00
|
|
|
UpdateStatus status = GetUpdateStatus(updatesDir, statusFile);
|
|
|
|
switch (status) {
|
|
|
|
case ePendingUpdate:
|
|
|
|
case ePendingService: {
|
2012-06-05 19:08:30 -07:00
|
|
|
nsCOMPtr<nsIFile> versionFile;
|
2010-08-17 17:09:07 -07:00
|
|
|
// Remove the update if the update application version file doesn't exist
|
|
|
|
// or if the update's application version is less than the current
|
|
|
|
// application version.
|
2012-01-18 14:10:38 -08:00
|
|
|
if (!GetVersionFile(updatesDir, versionFile) ||
|
|
|
|
IsOlderVersion(versionFile, appVersion)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
updatesDir->Remove(true);
|
2010-08-17 17:09:07 -07:00
|
|
|
} else {
|
2012-05-22 07:50:04 -07:00
|
|
|
ApplyUpdate(greDir, updatesDir, statusFile,
|
|
|
|
appDir, argc, argv, restart, pid);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-05-22 07:50:04 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eAppliedUpdate:
|
|
|
|
case eAppliedService:
|
|
|
|
// An update was applied in the background, so we need to switch to using
|
|
|
|
// it now.
|
|
|
|
SwitchToUpdatedApp(greDir, updatesDir, statusFile,
|
|
|
|
appDir, argc, argv);
|
|
|
|
break;
|
|
|
|
case eNoUpdateAction:
|
|
|
|
// We don't need to do any special processing here, we'll just continue to
|
|
|
|
// startup the application.
|
|
|
|
break;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-05-22 07:50:04 -07:00
|
|
|
|
|
|
|
NS_IMPL_THREADSAFE_ISUPPORTS1(nsUpdateProcessor, nsIUpdateProcessor)
|
|
|
|
|
|
|
|
nsUpdateProcessor::nsUpdateProcessor()
|
|
|
|
: mUpdaterPID(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsUpdateProcessor::ProcessUpdate(nsIUpdate* aUpdate)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIFile> greDir, appDir, updRoot;
|
|
|
|
nsCAutoString appVersion;
|
|
|
|
int argc;
|
|
|
|
char **argv;
|
|
|
|
|
|
|
|
NS_ENSURE_ARG_POINTER(aUpdate);
|
|
|
|
|
2012-05-25 12:52:54 -07:00
|
|
|
nsCAutoString binPath;
|
2012-05-22 07:50:04 -07:00
|
|
|
nsXREDirProvider* dirProvider = nsXREDirProvider::GetSingleton();
|
|
|
|
if (dirProvider) { // Normal code path
|
|
|
|
// Check for and process any available updates
|
|
|
|
bool persistent;
|
|
|
|
nsresult rv = dirProvider->GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
|
|
|
|
getter_AddRefs(updRoot));
|
|
|
|
// XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
updRoot = dirProvider->GetAppDir();
|
|
|
|
|
|
|
|
greDir = dirProvider->GetGREDir();
|
|
|
|
appDir = dirProvider->GetAppDir();
|
|
|
|
appVersion = gAppData->version;
|
|
|
|
argc = gRestartArgc;
|
|
|
|
argv = gRestartArgv;
|
|
|
|
} else {
|
|
|
|
// In the xpcshell environment, the usual XRE_main is not run, so things
|
|
|
|
// like dirProvider and gAppData do not exist. This code path accesses
|
|
|
|
// XPCOM (which is not available in the previous code path) in order to get
|
|
|
|
// the same information.
|
|
|
|
nsCOMPtr<nsIProperties> ds =
|
|
|
|
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
|
|
|
|
if (!ds) {
|
|
|
|
NS_ABORT(); // There's nothing which we can do if this fails!
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv = ds->Get(NS_GRE_DIR, NS_GET_IID(nsIFile),
|
|
|
|
getter_AddRefs(greDir));
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the GRE dir");
|
|
|
|
appDir = greDir;
|
|
|
|
|
|
|
|
rv = ds->Get(XRE_UPDATE_ROOT_DIR, NS_GET_IID(nsIFile),
|
|
|
|
getter_AddRefs(updRoot));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
updRoot = appDir;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIXULAppInfo> appInfo =
|
|
|
|
do_GetService("@mozilla.org/xre/app-info;1");
|
|
|
|
if (appInfo) {
|
|
|
|
rv = appInfo->GetVersion(appVersion);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
} else {
|
|
|
|
appVersion = MOZ_APP_VERSION;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need argv[0] to point to the current executable's name. The rest of
|
|
|
|
// the entries in this array will be ignored if argc<2. Therefore, for
|
|
|
|
// xpcshell, we only fill out that item, and leave the rest empty.
|
|
|
|
argc = 1;
|
|
|
|
nsCOMPtr<nsIFile> binary;
|
|
|
|
rv = ds->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile),
|
|
|
|
getter_AddRefs(binary));
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the binary path");
|
|
|
|
binary->GetNativePath(binPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the parameters to the BackgroundUpdateInfo structure shared with the
|
|
|
|
// watcher thread.
|
|
|
|
mInfo.mGREDir = greDir;
|
|
|
|
mInfo.mAppDir = appDir;
|
|
|
|
mInfo.mUpdateRoot = updRoot;
|
|
|
|
mInfo.mArgc = argc;
|
|
|
|
mInfo.mArgv = new char*[argc];
|
2012-05-25 12:52:54 -07:00
|
|
|
if (dirProvider) {
|
|
|
|
for (int i = 0; i < argc; ++i) {
|
|
|
|
const size_t length = strlen(argv[i]);
|
|
|
|
mInfo.mArgv[i] = new char[length + 1];
|
|
|
|
strcpy(mInfo.mArgv[i], argv[i]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(argc == 1); // see above
|
|
|
|
const size_t length = binPath.Length();
|
|
|
|
mInfo.mArgv[0] = new char[length + 1];
|
|
|
|
strcpy(mInfo.mArgv[0], binPath.get());
|
2012-05-22 07:50:04 -07:00
|
|
|
}
|
|
|
|
mInfo.mAppVersion = appVersion;
|
|
|
|
|
|
|
|
mUpdate = aUpdate;
|
|
|
|
|
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
|
|
|
return NS_NewThread(getter_AddRefs(mProcessWatcher),
|
|
|
|
NS_NewRunnableMethod(this, &nsUpdateProcessor::StartBackgroundUpdate));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsUpdateProcessor::StartBackgroundUpdate()
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(!NS_IsMainThread(), "main thread");
|
|
|
|
|
|
|
|
nsresult rv = ProcessUpdates(mInfo.mGREDir,
|
|
|
|
mInfo.mAppDir,
|
|
|
|
mInfo.mUpdateRoot,
|
|
|
|
mInfo.mArgc,
|
|
|
|
mInfo.mArgv,
|
2012-05-25 12:52:54 -07:00
|
|
|
mInfo.mAppVersion.get(),
|
2012-05-22 07:50:04 -07:00
|
|
|
false,
|
|
|
|
&mUpdaterPID);
|
|
|
|
NS_ENSURE_SUCCESS(rv, );
|
|
|
|
|
|
|
|
if (mUpdaterPID) {
|
|
|
|
// Track the state of the background updater process
|
|
|
|
rv = NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, &nsUpdateProcessor::WaitForProcess));
|
|
|
|
NS_ENSURE_SUCCESS(rv, );
|
|
|
|
} else {
|
|
|
|
// Failed to launch the background updater process for some reason.
|
|
|
|
// We need to shutdown the current thread as there isn't anything more for
|
|
|
|
// us to do...
|
|
|
|
rv = NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsUpdateProcessor::ShutdownWatcherThread));
|
|
|
|
NS_ENSURE_SUCCESS(rv, );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsUpdateProcessor::ShutdownWatcherThread()
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
|
|
|
mProcessWatcher->Shutdown();
|
2012-07-30 07:20:58 -07:00
|
|
|
mProcessWatcher = nullptr;
|
|
|
|
mUpdate = nullptr;
|
2012-05-22 07:50:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsUpdateProcessor::WaitForProcess()
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(!NS_IsMainThread(), "main thread");
|
|
|
|
::WaitForProcess(mUpdaterPID);
|
|
|
|
NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsUpdateProcessor::UpdateDone));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsUpdateProcessor::UpdateDone()
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIUpdateManager> um =
|
|
|
|
do_GetService("@mozilla.org/updates/update-manager;1");
|
|
|
|
if (um) {
|
|
|
|
um->RefreshUpdateStatus(mUpdate);
|
|
|
|
}
|
|
|
|
|
|
|
|
ShutdownWatcherThread();
|
|
|
|
}
|
|
|
|
|