Mac v2 signing - Bug 1064523 - Create staging directory outside of the Mac bundle. r=bbondy

This commit is contained in:
Robert Strong 2014-09-29 11:52:08 -07:00
parent 19489bfb24
commit cddf6a2d9d
4 changed files with 379 additions and 397 deletions

View File

@ -35,7 +35,7 @@ BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath,
/* /*
* Read the update.status file and sets isApplying to true if * Read the update.status file and sets isApplying to true if
* the status is set to applying * the status is set to applying.
* *
* @param updateDirPath The directory where update.status is stored * @param updateDirPath The directory where update.status is stored
* @param isApplying Out parameter for specifying if the status * @param isApplying Out parameter for specifying if the status
@ -82,15 +82,51 @@ IsStatusApplying(LPCWSTR updateDirPath, BOOL &isApplying)
/** /**
* Determines whether we're staging an update. * Determines whether we're staging an update.
* *
* @param argc The argc value normally sent to updater.exe * @param argc The argc value normally sent to updater.exe
* @param argv The argv value normally sent to updater.exe * @param argv The argv value normally sent to updater.exe
* @param boolean True if we're staging an update * @return boolean True if we're staging an update
*/ */
static bool static bool
IsUpdateBeingStaged(int argc, LPWSTR *argv) IsUpdateBeingStaged(int argc, LPWSTR *argv)
{ {
// PID will be set to -1 if we're supposed to stage an update. // PID will be set to -1 if we're supposed to stage an update.
return argc == 4 && !wcscmp(argv[3], L"-1"); return argc == 4 && !wcscmp(argv[3], L"-1") ||
argc == 5 && !wcscmp(argv[4], L"-1");
}
/**
* Determines whether the param only contains digits.
*
* @param str The string to check
* @param boolean True if the param only contains digits
*/
static bool
IsDigits(WCHAR *str)
{
while (*str) {
if (!iswdigit(*str++)) {
return FALSE;
}
}
return TRUE;
}
/**
* Determines whether the command line contains just the directory to apply the
* update to (old command line) or if it contains the installation directory and
* the directory to apply the update to.
*
* @param argc The argc value normally sent to updater.exe
* @param argv The argv value normally sent to updater.exe
* @param boolean True if the command line contains just the directory to apply
* the update to
*/
static bool
IsOldCommandline(int argc, LPWSTR *argv)
{
return argc == 4 && !wcscmp(argv[3], L"-1") ||
!wcscmp(argv[3], L"0/replace") ||
IsDigits(argv[3]);
} }
/** /**
@ -103,19 +139,29 @@ IsUpdateBeingStaged(int argc, LPWSTR *argv)
static BOOL static BOOL
GetInstallationDir(int argcTmp, LPWSTR *argvTmp, WCHAR aResultDir[MAX_PATH + 1]) GetInstallationDir(int argcTmp, LPWSTR *argvTmp, WCHAR aResultDir[MAX_PATH + 1])
{ {
if (argcTmp < 2) { int index = 3;
if (IsOldCommandline(argcTmp, argvTmp)) {
index = 2;
}
if (argcTmp < index) {
return FALSE; return FALSE;
} }
wcsncpy(aResultDir, argvTmp[2], MAX_PATH); wcsncpy(aResultDir, argvTmp[2], MAX_PATH);
WCHAR* backSlash = wcsrchr(aResultDir, L'\\'); WCHAR* backSlash = wcsrchr(aResultDir, L'\\');
// Make sure that the path does not include trailing backslashes // Make sure that the path does not include trailing backslashes
if (backSlash && (backSlash[1] == L'\0')) { if (backSlash && (backSlash[1] == L'\0')) {
*backSlash = L'\0'; *backSlash = L'\0';
} }
bool backgroundUpdate = IsUpdateBeingStaged(argcTmp, argvTmp);
bool replaceRequest = (argcTmp >= 4 && wcsstr(argvTmp[3], L"/replace")); // The new command line's argv[2] is always the installation directory.
if (backgroundUpdate || replaceRequest) { if (index == 2) {
return PathRemoveFileSpecW(aResultDir); bool backgroundUpdate = IsUpdateBeingStaged(argcTmp, argvTmp);
bool replaceRequest = (argcTmp >= 4 && wcsstr(argvTmp[3], L"/replace"));
if (backgroundUpdate || replaceRequest) {
return PathRemoveFileSpecW(aResultDir);
}
} }
return TRUE; return TRUE;
} }
@ -145,11 +191,16 @@ StartUpdateProcess(int argc,
// updater.exe update-dir apply [wait-pid [callback-dir callback-path args]] // updater.exe update-dir apply [wait-pid [callback-dir callback-path args]]
LPWSTR cmdLine = MakeCommandLine(argc, argv); LPWSTR cmdLine = MakeCommandLine(argc, argv);
int index = 3;
if (IsOldCommandline(argc, argv)) {
index = 2;
}
// If we're about to start the update process from session 0, // If we're about to start the update process from session 0,
// then we should not show a GUI. This only really needs to be done // then we should not show a GUI. This only really needs to be done
// on Vista and higher, but it's better to keep everything consistent // on Vista and higher, but it's better to keep everything consistent
// across all OS if it's of no harm. // across all OS if it's of no harm.
if (argc >= 2 ) { if (argc >= index) {
// Setting the desktop to blank will ensure no GUI is displayed // Setting the desktop to blank will ensure no GUI is displayed
si.lpDesktop = L""; si.lpDesktop = L"";
si.dwFlags |= STARTF_USESHOWWINDOW; si.dwFlags |= STARTF_USESHOWWINDOW;
@ -247,9 +298,9 @@ StartUpdateProcess(int argc,
MoveFileExW(updaterINITemp, updaterINI, MOVEFILE_REPLACE_EXISTING); MoveFileExW(updaterINITemp, updaterINI, MOVEFILE_REPLACE_EXISTING);
// Only run the PostUpdate if the update was successful // Only run the PostUpdate if the update was successful
if (updateWasSuccessful && argc > 2) { if (updateWasSuccessful && argc > index) {
LPCWSTR updateInfoDir = argv[1]; LPCWSTR updateInfoDir = argv[1];
bool backgroundUpdate = IsUpdateBeingStaged(argc, argv); bool stagingUpdate = IsUpdateBeingStaged(argc, argv);
// Launch the PostProcess with admin access in session 0. This is // Launch the PostProcess with admin access in session 0. This is
// actually launching the post update process but it takes in the // actually launching the post update process but it takes in the
@ -261,7 +312,7 @@ StartUpdateProcess(int argc,
// Note that we don't need to do this if we're just staging the // Note that we don't need to do this if we're just staging the
// update in the background, as the PostUpdate step runs when // update in the background, as the PostUpdate step runs when
// performing the replacing in that case. // performing the replacing in that case.
if (!backgroundUpdate) { if (!stagingUpdate) {
LOG(("Launching post update process as the service in session 0.")); LOG(("Launching post update process as the service in session 0."));
if (!LaunchWinPostProcess(installDir, updateInfoDir, true, nullptr)) { if (!LaunchWinPostProcess(installDir, updateInfoDir, true, nullptr)) {
LOG_WARN(("The post update process could not be launched." LOG_WARN(("The post update process could not be launched."

View File

@ -612,7 +612,17 @@ XPCOMUtils.defineLazyGetter(this, "gCanApplyUpdates", function aus_gCanApplyUpda
var updateTestFile = getUpdateFile([FILE_PERMS_TEST]); var updateTestFile = getUpdateFile([FILE_PERMS_TEST]);
LOG("gCanApplyUpdates - testing write access " + updateTestFile.path); LOG("gCanApplyUpdates - testing write access " + updateTestFile.path);
testWriteAccess(updateTestFile, false); testWriteAccess(updateTestFile, false);
#ifdef XP_WIN #ifdef XP_MACOSX
// Check that the application bundle can be written to.
var appDirTestFile = getAppBaseDir();
appDirTestFile.append(FILE_PERMS_TEST);
LOG("gCanApplyUpdates - testing write access " + appDirTestFile.path);
if (appDirTestFile.exists()) {
appDirTestFile.remove(false)
}
appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
appDirTestFile.remove(false);
#elifdef XP_WIN
var sysInfo = Cc["@mozilla.org/system-info;1"]. var sysInfo = Cc["@mozilla.org/system-info;1"].
getService(Ci.nsIPropertyBag2); getService(Ci.nsIPropertyBag2);
@ -997,7 +1007,7 @@ function getUpdatesDir() {
/** /**
* Get the Active Updates directory inside the directory where we apply the * Get the Active Updates directory inside the directory where we apply the
* background updates. * staged update.
* @return The active updates directory inside the updated directory, as a * @return The active updates directory inside the updated directory, as a
* nsIFile object. * nsIFile object.
*/ */

View File

@ -268,8 +268,9 @@ private:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static NS_tchar* gSourcePath; static NS_tchar* gPatchDirPath;
static NS_tchar gDestinationPath[MAXPATHLEN]; static NS_tchar gInstallDirPath[MAXPATHLEN];
static NS_tchar gWorkingDirPath[MAXPATHLEN];
static ArchiveReader gArchiveReader; static ArchiveReader gArchiveReader;
static bool gSucceeded = false; static bool gSucceeded = false;
static bool sStagedUpdate = false; static bool sStagedUpdate = false;
@ -1369,7 +1370,7 @@ PatchFile::Prepare()
mPatchIndex = sPatchIndex++; mPatchIndex = sPatchIndex++;
NS_tsnprintf(spath, sizeof(spath)/sizeof(spath[0]), NS_tsnprintf(spath, sizeof(spath)/sizeof(spath[0]),
NS_T("%s/updating/%d.patch"), gDestinationPath, mPatchIndex); NS_T("%s/updating/%d.patch"), gWorkingDirPath, mPatchIndex);
NS_tremove(spath); NS_tremove(spath);
@ -1781,7 +1782,7 @@ WriteStatusFile(const char* aStatus)
{ {
NS_tchar filename[MAXPATHLEN]; NS_tchar filename[MAXPATHLEN];
NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]), NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
NS_T("%s/update.status"), gSourcePath); NS_T("%s/update.status"), gPatchDirPath);
// Make sure that the directory for the update status file exists // Make sure that the directory for the update status file exists
if (ensure_parent_dir(filename)) if (ensure_parent_dir(filename))
@ -1832,7 +1833,7 @@ IsUpdateStatusPendingService()
{ {
NS_tchar filename[MAXPATHLEN]; NS_tchar filename[MAXPATHLEN];
NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]), NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
NS_T("%s/update.status"), gSourcePath); NS_T("%s/update.status"), gPatchDirPath);
AutoFile file(NS_tfopen(filename, NS_T("rb"))); AutoFile file(NS_tfopen(filename, NS_T("rb")));
if (file == nullptr) if (file == nullptr)
@ -1866,7 +1867,7 @@ IsUpdateStatusSucceeded(bool &isSucceeded)
isSucceeded = false; isSucceeded = false;
NS_tchar filename[MAXPATHLEN]; NS_tchar filename[MAXPATHLEN];
NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]), NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
NS_T("%s/update.status"), gSourcePath); NS_T("%s/update.status"), gPatchDirPath);
AutoFile file(NS_tfopen(filename, NS_T("rb"))); AutoFile file(NS_tfopen(filename, NS_T("rb")));
if (file == nullptr) if (file == nullptr)
@ -1882,36 +1883,6 @@ IsUpdateStatusSucceeded(bool &isSucceeded)
} }
#endif #endif
/*
* Get the application installation directory.
*
* @param installDir Out parameter for specifying the installation directory.
* @return true if successful, false otherwise.
*/
template <size_t N>
static bool
GetInstallationDir(NS_tchar (&installDir)[N])
{
NS_tsnprintf(installDir, N, NS_T("%s"), gDestinationPath);
if (!sStagedUpdate && !sReplaceRequest) {
// no need to do any further processing
return true;
}
NS_tchar *slash = (NS_tchar *) NS_tstrrchr(installDir, NS_SLASH);
// Make sure we're not looking at a trailing slash
if (slash && slash[1] == NS_T('\0')) {
*slash = NS_T('\0');
slash = (NS_tchar *) NS_tstrrchr(installDir, NS_SLASH);
}
if (slash) {
*slash = NS_T('\0');
} else {
return false;
}
return true;
}
/* /*
* Copy the entire contents of the application installation directory to the * Copy the entire contents of the application installation directory to the
* destination directory for the update process. * destination directory for the update process.
@ -1921,32 +1892,24 @@ GetInstallationDir(NS_tchar (&installDir)[N])
static int static int
CopyInstallDirToDestDir() CopyInstallDirToDestDir()
{ {
// First extract the installation directory from gSourcePath by going two
// levels above it. This is effectively skipping over "updates/0".
NS_tchar installDir[MAXPATHLEN];
if (!GetInstallationDir(installDir)) {
return NO_INSTALLDIR_ERROR;
}
// These files should not be copied over to the updated app // These files should not be copied over to the updated app
#ifdef XP_WIN #ifdef XP_WIN
#define SKIPLIST_COUNT 3 #define SKIPLIST_COUNT 3
#elif XP_MACOSX
#define SKIPLIST_COUNT 0
#else #else
#define SKIPLIST_COUNT 2 #define SKIPLIST_COUNT 2
#endif #endif
copy_recursive_skiplist<SKIPLIST_COUNT> skiplist; copy_recursive_skiplist<SKIPLIST_COUNT> skiplist;
#ifdef XP_MACOSX #ifndef XP_MACOSX
skiplist.append(0, installDir, NS_T("Updated.app")); skiplist.append(0, gInstallDirPath, NS_T("updated"));
skiplist.append(1, installDir, NS_T("Contents/MacOS/updates/0")); skiplist.append(1, gInstallDirPath, NS_T("updates/0"));
#else
skiplist.append(0, installDir, NS_T("updated"));
skiplist.append(1, installDir, NS_T("updates/0"));
#ifdef XP_WIN #ifdef XP_WIN
skiplist.append(2, installDir, NS_T("updated.update_in_progress.lock")); skiplist.append(2, gInstallDirPath, NS_T("updated.update_in_progress.lock"));
#endif #endif
#endif #endif
return ensure_copy_recursive(installDir, gDestinationPath, skiplist); return ensure_copy_recursive(gInstallDirPath, gWorkingDirPath, skiplist);
} }
/* /*
@ -1959,54 +1922,50 @@ static int
ProcessReplaceRequest() ProcessReplaceRequest()
{ {
// The replacement algorithm is like this: // The replacement algorithm is like this:
// 1. Move sourceDir to tmpDir. In case of failure, abort. // 1. Move destDir to tmpDir. In case of failure, abort.
// 2. Move newDir to sourceDir. In case of failure, revert step 1 and abort. // 2. Move newDir to destDir. In case of failure, revert step 1 and abort.
// 3. Delete tmpDir (or defer it to the next reboot). // 3. Delete tmpDir (or defer it to the next reboot).
NS_tchar installDir[MAXPATHLEN];
if (!GetInstallationDir(installDir)) {
return NO_INSTALLDIR_ERROR;
}
#ifdef XP_MACOSX #ifdef XP_MACOSX
NS_tchar sourceDir[MAXPATHLEN]; NS_tchar destDir[MAXPATHLEN];
NS_tsnprintf(sourceDir, sizeof(sourceDir)/sizeof(sourceDir[0]), NS_tsnprintf(destDir, sizeof(destDir)/sizeof(destDir[0]),
NS_T("%s/Contents"), installDir); NS_T("%s/Contents"), gInstallDirPath);
#elif XP_WIN #elif XP_WIN
// Windows preserves the case of the file/directory names. We use the // Windows preserves the case of the file/directory names. We use the
// GetLongPathName API in order to get the correct case for the directory // GetLongPathName API in order to get the correct case for the directory
// name, so that if the user has used a different case when launching the // name, so that if the user has used a different case when launching the
// application, the installation directory's name does not change. // application, the installation directory's name does not change.
NS_tchar sourceDir[MAXPATHLEN]; NS_tchar destDir[MAXPATHLEN];
if (!GetLongPathNameW(installDir, sourceDir, sizeof(sourceDir)/sizeof(sourceDir[0]))) { if (!GetLongPathNameW(gInstallDirPath, destDir, sizeof(destDir)/sizeof(destDir[0]))) {
return NO_INSTALLDIR_ERROR; return NO_INSTALLDIR_ERROR;
} }
#else #else
NS_tchar* sourceDir = installDir; NS_tchar* destDir = gInstallDirPath;
#endif #endif
NS_tchar tmpDir[MAXPATHLEN]; NS_tchar tmpDir[MAXPATHLEN];
NS_tsnprintf(tmpDir, sizeof(tmpDir)/sizeof(tmpDir[0]), NS_tsnprintf(tmpDir, sizeof(tmpDir)/sizeof(tmpDir[0]),
NS_T("%s.bak"), sourceDir); NS_T("%s.bak"), destDir);
NS_tchar newDir[MAXPATHLEN]; NS_tchar newDir[MAXPATHLEN];
NS_tsnprintf(newDir, sizeof(newDir)/sizeof(newDir[0]), NS_tsnprintf(newDir, sizeof(newDir)/sizeof(newDir[0]),
#ifdef XP_MACOSX #ifdef XP_MACOSX
NS_T("%s/Updated.app/Contents"), NS_T("%s/Contents"),
gWorkingDirPath);
#else #else
NS_T("%s.bak/updated"), NS_T("%s.bak/updated"),
gInstallDirPath);
#endif #endif
installDir);
// First try to remove the possibly existing temp directory, because if this // First try to remove the possibly existing temp directory, because if this
// directory exists, we will fail to rename sourceDir. // directory exists, we will fail to rename destDir.
// No need to error check here because if this fails, we will fail in the // No need to error check here because if this fails, we will fail in the
// next step anyways. // next step anyways.
ensure_remove_recursive(tmpDir); ensure_remove_recursive(tmpDir);
LOG(("Begin moving sourceDir (" LOG_S ") to tmpDir (" LOG_S ")", LOG(("Begin moving destDir (" LOG_S ") to tmpDir (" LOG_S ")",
sourceDir, tmpDir)); destDir, tmpDir));
int rv = rename_file(sourceDir, tmpDir, true); int rv = rename_file(destDir, tmpDir, true);
#ifdef XP_WIN #ifdef XP_WIN
// On Windows, if Firefox is launched using the shortcut, it will hold a handle // On Windows, if Firefox is launched using the shortcut, it will hold a handle
// to its installation directory open, which might not get released in time. // to its installation directory open, which might not get released in time.
@ -2015,30 +1974,30 @@ ProcessReplaceRequest()
const int max_retries = 10; const int max_retries = 10;
int retries = 0; int retries = 0;
while (rv == WRITE_ERROR && (retries++ < max_retries)) { while (rv == WRITE_ERROR && (retries++ < max_retries)) {
LOG(("PerformReplaceRequest: sourceDir rename attempt %d failed. " \ LOG(("PerformReplaceRequest: destDir rename attempt %d failed. " \
"File: " LOG_S ". Last error: %d, err: %d", retries, "File: " LOG_S ". Last error: %d, err: %d", retries,
sourceDir, GetLastError(), rv)); destDir, GetLastError(), rv));
Sleep(100); Sleep(100);
rv = rename_file(sourceDir, tmpDir, true); rv = rename_file(destDir, tmpDir, true);
} }
#endif #endif
if (rv) { if (rv) {
LOG(("Moving sourceDir to tmpDir failed, err: %d", rv)); LOG(("Moving destDir to tmpDir failed, err: %d", rv));
return rv; return rv;
} }
LOG(("Begin moving newDir (" LOG_S ") to sourceDir (" LOG_S ")", LOG(("Begin moving newDir (" LOG_S ") to destDir (" LOG_S ")",
newDir, sourceDir)); newDir, destDir));
rv = rename_file(newDir, sourceDir, true); rv = rename_file(newDir, destDir, true);
if (rv) { if (rv) {
LOG(("Moving newDir to sourceDir failed, err: %d", rv)); LOG(("Moving newDir to destDir failed, err: %d", rv));
LOG(("Now, try to move tmpDir back to sourceDir")); LOG(("Now, try to move tmpDir back to destDir"));
ensure_remove_recursive(sourceDir); ensure_remove_recursive(destDir);
int rv2 = rename_file(tmpDir, sourceDir, true); int rv2 = rename_file(tmpDir, destDir, true);
if (rv2) { if (rv2) {
LOG(("Moving tmpDir back to sourceDir failed, err: %d", rv2)); LOG(("Moving tmpDir back to destDir failed, err: %d", rv2));
} }
return rv; return rv;
} }
@ -2058,39 +2017,11 @@ ProcessReplaceRequest()
} }
#ifdef XP_MACOSX #ifdef XP_MACOSX
// On OS X, we need to copy anything else left over inside the Updated.app // On OS X, we we need to remove the staging directory after its Contents
// directory, and then we need to get rid of it as it's no longer going to // directory has been moved.
// be useful.
NS_tchar updatedAppDir[MAXPATHLEN]; NS_tchar updatedAppDir[MAXPATHLEN];
NS_tsnprintf(updatedAppDir, sizeof(updatedAppDir)/sizeof(updatedAppDir[0]), NS_tsnprintf(updatedAppDir, sizeof(updatedAppDir)/sizeof(updatedAppDir[0]),
NS_T("%s/Updated.app"), installDir); NS_T("%s/Updated.app"), gPatchDirPath);
NS_tDIR *dir = NS_topendir(updatedAppDir);
if (dir) {
NS_tdirent *entry;
while ((entry = NS_treaddir(dir)) != 0) {
if (NS_tstrcmp(entry->d_name, NS_T(".")) &&
NS_tstrcmp(entry->d_name, NS_T(".."))) {
NS_tchar childSrcPath[MAXPATHLEN];
NS_tsnprintf(childSrcPath, sizeof(childSrcPath)/sizeof(childSrcPath[0]),
NS_T("%s/%s"), updatedAppDir, entry->d_name);
NS_tchar childDstPath[MAXPATHLEN];
NS_tsnprintf(childDstPath, sizeof(childDstPath)/sizeof(childDstPath[0]),
NS_T("%s/%s"), installDir, entry->d_name);
ensure_remove_recursive(childDstPath);
rv = rename_file(childSrcPath, childDstPath, true);
if (rv) {
LOG(("Moving " LOG_S " to " LOG_S " failed, err: %d",
childSrcPath, childDstPath, errno));
}
}
}
NS_tclosedir(dir);
} else {
LOG(("Updated.app dir can't be found: " LOG_S ", err: %d",
updatedAppDir, errno));
}
ensure_remove_recursive(updatedAppDir); ensure_remove_recursive(updatedAppDir);
#endif #endif
@ -2144,11 +2075,11 @@ GetUpdateFileName(NS_tchar *fileName, int maxChars)
NS_tchar linkFileName[MAXPATHLEN]; NS_tchar linkFileName[MAXPATHLEN];
NS_tsnprintf(linkFileName, sizeof(linkFileName)/sizeof(linkFileName[0]), NS_tsnprintf(linkFileName, sizeof(linkFileName)/sizeof(linkFileName[0]),
NS_T("%s/update.link"), gSourcePath); NS_T("%s/update.link"), gPatchDirPath);
AutoFile linkFile(NS_tfopen(linkFileName, NS_T("rb"))); AutoFile linkFile(NS_tfopen(linkFileName, NS_T("rb")));
if (linkFile == nullptr) { if (linkFile == nullptr) {
NS_tsnprintf(fileName, maxChars, NS_tsnprintf(fileName, maxChars,
NS_T("%s/update.mar"), gSourcePath); NS_T("%s/update.mar"), gPatchDirPath);
return OK; return OK;
} }
@ -2174,7 +2105,7 @@ GetUpdateFileName(NS_tchar *fileName, int maxChars)
#else #else
// We currently only support update.link files under GONK // We currently only support update.link files under GONK
NS_tsnprintf(fileName, maxChars, NS_tsnprintf(fileName, maxChars,
NS_T("%s/update.mar"), gSourcePath); NS_T("%s/update.mar"), gPatchDirPath);
#endif #endif
return OK; return OK;
} }
@ -2199,19 +2130,11 @@ UpdateThreadFunc(void *param)
} }
if (rv == OK) { if (rv == OK) {
NS_tchar installDir[MAXPATHLEN];
if (sStagedUpdate) {
if (!GetInstallationDir(installDir)) {
rv = NO_INSTALLDIR_ERROR;
}
} else {
NS_tstrcpy(installDir, gDestinationPath);
}
if (rv == OK) { if (rv == OK) {
NS_tchar updateSettingsPath[MAX_TEXT_LEN]; NS_tchar updateSettingsPath[MAX_TEXT_LEN];
NS_tsnprintf(updateSettingsPath, NS_tsnprintf(updateSettingsPath,
sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]), sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]),
NS_T("%s/update-settings.ini"), installDir); NS_T("%s/update-settings.ini"), gWorkingDirPath);
MARChannelStringTable MARStrings; MARChannelStringTable MARStrings;
if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) { if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) {
// If we can't read from update-settings.ini then we shouldn't impose // If we can't read from update-settings.ini then we shouldn't impose
@ -2234,7 +2157,7 @@ UpdateThreadFunc(void *param)
gArchiveReader.Close(); gArchiveReader.Close();
NS_tchar updatingDir[MAXPATHLEN]; NS_tchar updatingDir[MAXPATHLEN];
NS_tsnprintf(updatingDir, sizeof(updatingDir)/sizeof(updatingDir[0]), NS_tsnprintf(updatingDir, sizeof(updatingDir)/sizeof(updatingDir[0]),
NS_T("%s/updating"), gDestinationPath); NS_T("%s/updating"), gWorkingDirPath);
ensure_remove_recursive(updatingDir); ensure_remove_recursive(updatingDir);
} }
} }
@ -2252,23 +2175,11 @@ UpdateThreadFunc(void *param)
// bypass this fallback, and is used in the updater tests. // bypass this fallback, and is used in the updater tests.
// The only special thing which we should do here is to remove the // The only special thing which we should do here is to remove the
// staged directory as it won't be useful any more. // staged directory as it won't be useful any more.
NS_tchar installDir[MAXPATHLEN]; ensure_remove_recursive(gWorkingDirPath);
if (GetInstallationDir(installDir)) { WriteStatusFile(sUsingService ? "pending-service" : "pending");
NS_tchar stageDir[MAXPATHLEN]; char processUpdates[] = "MOZ_PROCESS_UPDATES=";
NS_tsnprintf(stageDir, sizeof(stageDir)/sizeof(stageDir[0]), putenv(processUpdates); // We need to use -process-updates again in the tests
#ifdef XP_MACOSX reportRealResults = false; // pretend success
NS_T("%s/Updated.app"),
#else
NS_T("%s/updated"),
#endif
installDir);
ensure_remove_recursive(stageDir);
WriteStatusFile(sUsingService ? "pending-service" : "pending");
char processUpdates[] = "MOZ_PROCESS_UPDATES=";
putenv(processUpdates); // We need to use -process-updates again in the tests
reportRealResults = false; // pretend success
}
} }
if (reportRealResults) { if (reportRealResults) {
@ -2342,14 +2253,14 @@ int NS_main(int argc, NS_tchar **argv)
} }
// The directory containing the update information. // The directory containing the update information.
gSourcePath = argv[1]; gPatchDirPath = argv[1];
// The directory we're going to update to. // The directory we're going to update to.
// We copy this string because we need to remove trailing slashes. The C++ // We copy this string because we need to remove trailing slashes. The C++
// standard says that it's always safe to write to strings pointed to by argv // standard says that it's always safe to write to strings pointed to by argv
// elements, but I don't necessarily believe it. // elements, but I don't necessarily believe it.
NS_tstrncpy(gDestinationPath, argv[2], MAXPATHLEN); NS_tstrncpy(gInstallDirPath, argv[2], MAXPATHLEN);
gDestinationPath[MAXPATHLEN - 1] = NS_T('\0'); gInstallDirPath[MAXPATHLEN - 1] = NS_T('\0');
NS_tchar *slash = NS_tstrrchr(gDestinationPath, NS_SLASH); NS_tchar *slash = NS_tstrrchr(gInstallDirPath, NS_SLASH);
if (slash && !slash[1]) { if (slash && !slash[1]) {
*slash = NS_T('\0'); *slash = NS_T('\0');
} }
@ -2395,23 +2306,34 @@ int NS_main(int argc, NS_tchar **argv)
#else #else
int pid = 0; int pid = 0;
#endif #endif
if (argc > 3) { if (argc > 4) {
#ifdef XP_WIN #ifdef XP_WIN
pid = _wtoi64(argv[3]); pid = _wtoi64(argv[4]);
#else #else
pid = atoi(argv[3]); pid = atoi(argv[4]);
#endif #endif
if (pid == -1) { if (pid == -1) {
// This is a signal from the parent process that the updater should stage // This is a signal from the parent process that the updater should stage
// the update. // the update.
sStagedUpdate = true; sStagedUpdate = true;
} else if (NS_tstrstr(argv[3], NS_T("/replace"))) { } else if (NS_tstrstr(argv[4], NS_T("/replace"))) {
// We're processing a request to replace the application with a staged // We're processing a request to replace the application with a staged
// update. // update.
sReplaceRequest = true; sReplaceRequest = true;
} }
} }
// The directory we're going to update to.
// We copy this string because we need to remove trailing slashes. The C++
// standard says that it's always safe to write to strings pointed to by argv
// elements, but I don't necessarily believe it.
NS_tstrncpy(gWorkingDirPath, argv[3], MAXPATHLEN);
gWorkingDirPath[MAXPATHLEN - 1] = NS_T('\0');
slash = NS_tstrrchr(gWorkingDirPath, NS_SLASH);
if (slash && !slash[1]) {
*slash = NS_T('\0');
}
if (getenv("MOZ_OS_UPDATE")) { if (getenv("MOZ_OS_UPDATE")) {
sIsOSUpdate = true; sIsOSUpdate = true;
putenv(const_cast<char*>("MOZ_OS_UPDATE=")); putenv(const_cast<char*>("MOZ_OS_UPDATE="));
@ -2420,28 +2342,22 @@ int NS_main(int argc, NS_tchar **argv)
if (sReplaceRequest) { if (sReplaceRequest) {
// If we're attempting to replace the application, try to append to the // If we're attempting to replace the application, try to append to the
// log generated when staging the staged update. // log generated when staging the staged update.
NS_tchar installDir[MAXPATHLEN];
if (!GetInstallationDir(installDir)) {
fprintf(stderr, "Could not get the installation directory\n");
return 1;
}
#ifdef XP_WIN #ifdef XP_WIN
NS_tchar* logDir = gSourcePath; NS_tchar* logDir = gPatchDirPath;
#else
#ifdef XP_MACOSX
NS_tchar* logDir = gPatchDirPath;
#else #else
NS_tchar logDir[MAXPATHLEN]; NS_tchar logDir[MAXPATHLEN];
NS_tsnprintf(logDir, sizeof(logDir)/sizeof(logDir[0]), NS_tsnprintf(logDir, sizeof(logDir)/sizeof(logDir[0]),
#ifdef XP_MACOSX
NS_T("%s/Updated.app/Contents/MacOS/updates"),
#else
NS_T("%s/updated/updates"), NS_T("%s/updated/updates"),
gInstallDirPath);
#endif #endif
installDir);
#endif #endif
LogInitAppend(logDir, NS_T("last-update.log"), NS_T("update.log")); LogInitAppend(logDir, NS_T("last-update.log"), NS_T("update.log"));
} else { } else {
LogInit(gSourcePath, NS_T("update.log")); LogInit(gPatchDirPath, NS_T("update.log"));
} }
if (!WriteStatusFile("applying")) { if (!WriteStatusFile("applying")) {
@ -2455,6 +2371,10 @@ int NS_main(int argc, NS_tchar **argv)
LOG(("Performing a replace request")); LOG(("Performing a replace request"));
} }
LOG(("PATCH DIRECTORY " LOG_S, gPatchDirPath));
LOG(("INSTALLATION DIRECTORY " LOG_S, gInstallDirPath));
LOG(("WORKING DIRECTORY " LOG_S, gWorkingDirPath));
#ifdef MOZ_WIDGET_GONK #ifdef MOZ_WIDGET_GONK
const char *prioEnv = getenv("MOZ_UPDATER_PRIO"); const char *prioEnv = getenv("MOZ_UPDATER_PRIO");
if (prioEnv) { if (prioEnv) {
@ -2522,7 +2442,7 @@ int NS_main(int argc, NS_tchar **argv)
// The callback is the remaining arguments starting at callbackIndex. // The callback is the remaining arguments starting at callbackIndex.
// The argument specified by callbackIndex is the callback executable and the // The argument specified by callbackIndex is the callback executable and the
// argument prior to callbackIndex is the working directory. // argument prior to callbackIndex is the working directory.
const int callbackIndex = 5; const int callbackIndex = 6;
#if defined(XP_WIN) #if defined(XP_WIN)
sUsingService = getenv("MOZ_USING_SERVICE") != nullptr; sUsingService = getenv("MOZ_USING_SERVICE") != nullptr;
@ -2543,17 +2463,15 @@ int NS_main(int argc, NS_tchar **argv)
NS_tchar updateLockFilePath[MAXPATHLEN]; NS_tchar updateLockFilePath[MAXPATHLEN];
if (sStagedUpdate) { if (sStagedUpdate) {
// When staging an update, the lock file is: // When staging an update, the lock file is:
// $INSTALLDIR\updated.update_in_progress.lock // <install_dir>\updated.update_in_progress.lock
NS_tsnprintf(updateLockFilePath, NS_tsnprintf(updateLockFilePath,
sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]), sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]),
NS_T("%s.update_in_progress.lock"), gDestinationPath); NS_T("%s/updated.update_in_progress.lock"), gInstallDirPath);
} else if (sReplaceRequest) { } else if (sReplaceRequest) {
// When processing a replace request, the lock file is: // When processing a replace request, the lock file is:
// $INSTALLDIR\..\moz_update_in_progress.lock // <install_dir>\..\moz_update_in_progress.lock
NS_tchar installDir[MAXPATHLEN]; NS_tchar installDir[MAXPATHLEN];
if (!GetInstallationDir(installDir)) { NS_tstrcpy(installDir, gInstallDirPath);
return 1;
}
NS_tchar *slash = (NS_tchar *) NS_tstrrchr(installDir, NS_SLASH); NS_tchar *slash = (NS_tchar *) NS_tstrrchr(installDir, NS_SLASH);
*slash = NS_T('\0'); *slash = NS_T('\0');
NS_tsnprintf(updateLockFilePath, NS_tsnprintf(updateLockFilePath,
@ -2561,7 +2479,7 @@ int NS_main(int argc, NS_tchar **argv)
NS_T("%s\\moz_update_in_progress.lock"), installDir); NS_T("%s\\moz_update_in_progress.lock"), installDir);
} else { } else {
// In the non-staging update case, the lock file is: // In the non-staging update case, the lock file is:
// $INSTALLDIR\$APPNAME.exe.update_in_progress.lock // <install_dir>\<app_name>.exe.update_in_progress.lock
NS_tsnprintf(updateLockFilePath, NS_tsnprintf(updateLockFilePath,
sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]), sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]),
NS_T("%s.update_in_progress.lock"), argv[callbackIndex]); NS_T("%s.update_in_progress.lock"), argv[callbackIndex]);
@ -2593,8 +2511,7 @@ int NS_main(int argc, NS_tchar **argv)
NS_tsnprintf(elevatedLockFilePath, NS_tsnprintf(elevatedLockFilePath,
sizeof(elevatedLockFilePath)/sizeof(elevatedLockFilePath[0]), sizeof(elevatedLockFilePath)/sizeof(elevatedLockFilePath[0]),
NS_T("%s/update_elevated.lock"), gSourcePath); NS_T("%s/update_elevated.lock"), gPatchDirPath);
// Even if a file has no sharing access, you can still get its attributes // Even if a file has no sharing access, you can still get its attributes
bool startedFromUnelevatedUpdater = bool startedFromUnelevatedUpdater =
@ -2640,11 +2557,6 @@ int NS_main(int argc, NS_tchar **argv)
return 1; return 1;
} }
NS_tchar installDir[MAXPATHLEN];
if (!GetInstallationDir(installDir)) {
return 1;
}
// Make sure the path to the updater to use for the update is on local. // Make sure the path to the updater to use for the update is on local.
// We do this check to make sure that file locking is available for // We do this check to make sure that file locking is available for
// race condition security checks. // race condition security checks.
@ -2670,7 +2582,7 @@ int NS_main(int argc, NS_tchar **argv)
// are available. If not don't use the service. // are available. If not don't use the service.
if (useService) { if (useService) {
WCHAR maintenanceServiceKey[MAX_PATH + 1]; WCHAR maintenanceServiceKey[MAX_PATH + 1];
if (CalculateRegistryPathFromFilePath(installDir, maintenanceServiceKey)) { if (CalculateRegistryPathFromFilePath(gInstallDirPath, maintenanceServiceKey)) {
HKEY baseKey; HKEY baseKey;
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
maintenanceServiceKey, 0, maintenanceServiceKey, 0,
@ -2744,7 +2656,7 @@ int NS_main(int argc, NS_tchar **argv)
if (updateLockFileHandle != INVALID_HANDLE_VALUE) { if (updateLockFileHandle != INVALID_HANDLE_VALUE) {
CloseHandle(updateLockFileHandle); CloseHandle(updateLockFileHandle);
} }
WriteStatusPending(gSourcePath); WriteStatusPending(gPatchDirPath);
return 0; return 0;
} }
@ -2759,7 +2671,7 @@ int NS_main(int argc, NS_tchar **argv)
bool updateStatusSucceeded = false; bool updateStatusSucceeded = false;
if (IsUpdateStatusSucceeded(updateStatusSucceeded) && if (IsUpdateStatusSucceeded(updateStatusSucceeded) &&
updateStatusSucceeded) { updateStatusSucceeded) {
if (!LaunchWinPostProcess(installDir, gSourcePath, false, nullptr)) { if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath, false, nullptr)) {
fprintf(stderr, "The post update process which runs as the user" fprintf(stderr, "The post update process which runs as the user"
" for service update could not be launched."); " for service update could not be launched.");
} }
@ -2798,7 +2710,7 @@ int NS_main(int argc, NS_tchar **argv)
} }
if (argc > callbackIndex) { if (argc > callbackIndex) {
LaunchCallbackApp(argv[4], argc - callbackIndex, LaunchCallbackApp(argv[5], argc - callbackIndex,
argv + callbackIndex, sUsingService); argv + callbackIndex, sUsingService);
} }
@ -2811,7 +2723,7 @@ int NS_main(int argc, NS_tchar **argv)
// update.status file. // update.status file.
return 0; return 0;
} else if(useService) { } else if(useService) {
// The service command was launched. The service is responsible for // The service command was launched. The service is responsible for
// writing out the update.status file. // writing out the update.status file.
if (updateLockFileHandle != INVALID_HANDLE_VALUE) { if (updateLockFileHandle != INVALID_HANDLE_VALUE) {
CloseHandle(updateLockFileHandle); CloseHandle(updateLockFileHandle);
@ -2853,16 +2765,16 @@ int NS_main(int argc, NS_tchar **argv)
if (sStagedUpdate) { if (sStagedUpdate) {
// When staging updates, blow away the old installation directory and create // When staging updates, blow away the old installation directory and create
// it from scratch. // it from scratch.
ensure_remove_recursive(gDestinationPath); ensure_remove_recursive(gWorkingDirPath);
} }
if (!sReplaceRequest) { if (!sReplaceRequest) {
// Change current directory to the directory where we need to apply the update. // Change current directory to the directory where we need to apply the update.
if (NS_tchdir(gDestinationPath) != 0) { if (NS_tchdir(gWorkingDirPath) != 0) {
// Try to create the destination directory if it doesn't exist // Try to create the destination directory if it doesn't exist
int rv = NS_tmkdir(gDestinationPath, 0755); int rv = NS_tmkdir(gWorkingDirPath, 0755);
if (rv == OK && errno != EEXIST) { if (rv == OK && errno != EEXIST) {
// Try changing the current directory again // Try changing the current directory again
if (NS_tchdir(gDestinationPath) != 0) { if (NS_tchdir(gWorkingDirPath) != 0) {
// OK, time to give up! // OK, time to give up!
return 1; return 1;
} }
@ -2873,24 +2785,21 @@ int NS_main(int argc, NS_tchar **argv)
} }
} }
LOG(("SOURCE DIRECTORY " LOG_S, gSourcePath));
LOG(("DESTINATION DIRECTORY " LOG_S, gDestinationPath));
#ifdef XP_WIN #ifdef XP_WIN
// For replace requests, we don't need to do any real updates, so this is not // For replace requests, we don't need to do any real updates, so this is not
// necessary. // necessary.
if (!sReplaceRequest) { if (!sReplaceRequest) {
// Allocate enough space for the length of the path an optional additional // Allocate enough space for the length of the path an optional additional
// trailing slash and null termination. // trailing slash and null termination.
NS_tchar *destpath = (NS_tchar *) malloc((NS_tstrlen(gDestinationPath) + 2) * sizeof(NS_tchar)); NS_tchar *destpath = (NS_tchar *) malloc((NS_tstrlen(gWorkingDirPath) + 2) * sizeof(NS_tchar));
if (!destpath) if (!destpath)
return 1; return 1;
NS_tchar *c = destpath; NS_tchar *c = destpath;
NS_tstrcpy(c, gDestinationPath); NS_tstrcpy(c, gWorkingDirPath);
c += NS_tstrlen(gDestinationPath); c += NS_tstrlen(gWorkingDirPath);
if (gDestinationPath[NS_tstrlen(gDestinationPath) - 1] != NS_T('/') && if (gWorkingDirPath[NS_tstrlen(gWorkingDirPath) - 1] != NS_T('/') &&
gDestinationPath[NS_tstrlen(gDestinationPath) - 1] != NS_T('\\')) { gWorkingDirPath[NS_tstrlen(gWorkingDirPath) - 1] != NS_T('\\')) {
NS_tstrcat(c, NS_T("/")); NS_tstrcat(c, NS_T("/"));
c += NS_tstrlen(NS_T("/")); c += NS_tstrlen(NS_T("/"));
} }
@ -2901,14 +2810,14 @@ int NS_main(int argc, NS_tchar **argv)
} }
NS_tchar applyDirLongPath[MAXPATHLEN]; NS_tchar applyDirLongPath[MAXPATHLEN];
if (!GetLongPathNameW(gDestinationPath, applyDirLongPath, if (!GetLongPathNameW(gWorkingDirPath, applyDirLongPath,
sizeof(applyDirLongPath)/sizeof(applyDirLongPath[0]))) { sizeof(applyDirLongPath)/sizeof(applyDirLongPath[0]))) {
LOG(("NS_main: unable to find apply to dir: " LOG_S, gDestinationPath)); LOG(("NS_main: unable to find apply to dir: " LOG_S, gWorkingDirPath));
LogFinish(); LogFinish();
WriteStatusFile(WRITE_ERROR); WriteStatusFile(WRITE_ERROR);
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1); EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
if (argc > callbackIndex) { if (argc > callbackIndex) {
LaunchCallbackApp(argv[4], argc - callbackIndex, LaunchCallbackApp(argv[5], argc - callbackIndex,
argv + callbackIndex, sUsingService); argv + callbackIndex, sUsingService);
} }
return 1; return 1;
@ -2930,15 +2839,15 @@ int NS_main(int argc, NS_tchar **argv)
// In case of replace requests, we should look for the callback file in // In case of replace requests, we should look for the callback file in
// the destination directory. // the destination directory.
size_t commonPrefixLength = PathCommonPrefixW(argv[callbackIndex], size_t commonPrefixLength = PathCommonPrefixW(argv[callbackIndex],
gDestinationPath, gInstallDirPath,
nullptr); nullptr);
NS_tchar *p = buffer; NS_tchar *p = buffer;
NS_tstrncpy(p, argv[callbackIndex], commonPrefixLength); NS_tstrncpy(p, argv[callbackIndex], commonPrefixLength);
p += commonPrefixLength; p += commonPrefixLength;
bufferLeft -= commonPrefixLength; bufferLeft -= commonPrefixLength;
NS_tstrncpy(p, gDestinationPath + commonPrefixLength, bufferLeft); NS_tstrncpy(p, gInstallDirPath + commonPrefixLength, bufferLeft);
size_t len = NS_tstrlen(gDestinationPath + commonPrefixLength); size_t len = NS_tstrlen(gInstallDirPath + commonPrefixLength);
p += len; p += len;
bufferLeft -= len; bufferLeft -= len;
*p = NS_T('\\'); *p = NS_T('\\');
@ -2946,8 +2855,7 @@ int NS_main(int argc, NS_tchar **argv)
bufferLeft--; bufferLeft--;
*p = NS_T('\0'); *p = NS_T('\0');
NS_tchar installDir[MAXPATHLEN]; NS_tchar installDir[MAXPATHLEN];
if (!GetInstallationDir(installDir)) NS_tstrcpy(installDir, gInstallDirPath);
return 1;
size_t callbackPrefixLength = PathCommonPrefixW(argv[callbackIndex], size_t callbackPrefixLength = PathCommonPrefixW(argv[callbackIndex],
installDir, installDir,
nullptr); nullptr);
@ -2961,7 +2869,7 @@ int NS_main(int argc, NS_tchar **argv)
WriteStatusFile(WRITE_ERROR); WriteStatusFile(WRITE_ERROR);
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1); EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
if (argc > callbackIndex) { if (argc > callbackIndex) {
LaunchCallbackApp(argv[4], LaunchCallbackApp(argv[5],
argc - callbackIndex, argc - callbackIndex,
argv + callbackIndex, argv + callbackIndex,
sUsingService); sUsingService);
@ -3042,7 +2950,7 @@ int NS_main(int argc, NS_tchar **argv)
NS_tremove(gCallbackBackupPath); NS_tremove(gCallbackBackupPath);
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1); EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
LaunchCallbackApp(argv[4], LaunchCallbackApp(argv[5],
argc - callbackIndex, argc - callbackIndex,
argv + callbackIndex, argv + callbackIndex,
sUsingService); sUsingService);
@ -3125,29 +3033,23 @@ int NS_main(int argc, NS_tchar **argv)
// the service to a newer version in that case. If we are not running // the service to a newer version in that case. If we are not running
// through the service, then MOZ_USING_SERVICE will not exist. // through the service, then MOZ_USING_SERVICE will not exist.
if (!sUsingService) { if (!sUsingService) {
NS_tchar installDir[MAXPATHLEN]; if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath, false, nullptr)) {
if (GetInstallationDir(installDir)) { LOG(("NS_main: The post update process could not be launched."));
if (!LaunchWinPostProcess(installDir, gSourcePath, false, nullptr)) {
LOG(("NS_main: The post update process could not be launched."));
}
StartServiceUpdate(installDir);
} }
StartServiceUpdate(gInstallDirPath);
} }
} }
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0); EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0);
#endif /* XP_WIN */ #endif /* XP_WIN */
#ifdef XP_MACOSX #ifdef XP_MACOSX
if (gSucceeded) { if (gSucceeded) {
char installDir[MAXPATHLEN]; LaunchMacPostProcess(gInstallDirPath);
if (GetInstallationDir(installDir)) {
LaunchMacPostProcess(installDir);
}
} }
#endif /* XP_MACOSX */ #endif /* XP_MACOSX */
if (getenv("MOZ_PROCESS_UPDATES") == nullptr) { if (getenv("MOZ_PROCESS_UPDATES") == nullptr) {
LaunchCallbackApp(argv[4], LaunchCallbackApp(argv[5],
argc - callbackIndex, argc - callbackIndex,
argv + callbackIndex, argv + callbackIndex,
sUsingService); sUsingService);
@ -3662,7 +3564,7 @@ int DoUpdate()
{ {
NS_tchar manifest[MAXPATHLEN]; NS_tchar manifest[MAXPATHLEN];
NS_tsnprintf(manifest, sizeof(manifest)/sizeof(manifest[0]), NS_tsnprintf(manifest, sizeof(manifest)/sizeof(manifest[0]),
NS_T("%s/updating/update.manifest"), gDestinationPath); NS_T("%s/updating/update.manifest"), gWorkingDirPath);
ensure_parent_dir(manifest); ensure_parent_dir(manifest);
// extract the manifest // extract the manifest

View File

@ -132,6 +132,44 @@ GetCurrentWorkingDir(char *buf, size_t size)
return NS_OK; return NS_OK;
} }
/**
* Get the path to the installation directory. For Mac OS X this will be the
* bundle directory.
*
* @param appDir the application directory file object
* @param installDirPath the path to the installation directory
*/
static nsresult
GetInstallDirPath(nsIFile *appDir, nsACString& installDirPath)
{
nsresult rv;
#ifdef XP_MACOSX
nsCOMPtr<nsIFile> parentDir1, parentDir2;
rv = appDir->GetParent(getter_AddRefs(parentDir1));
if (NS_FAILED(rv)) {
return rv;
}
rv = parentDir1->GetParent(getter_AddRefs(parentDir2));
if (NS_FAILED(rv)) {
return rv;
}
rv = parentDir2->GetNativePath(installDirPath);
#elif XP_WIN
nsAutoString installDirPathW;
rv = appDir->GetPath(installDirPathW);
if (NS_FAILED(rv)) {
return rv;
}
installDirPath = NS_ConvertUTF16toUTF8(installDirPathW);
#else
rv = appDir->GetNativePath(installDirPath);
#endif
if (NS_FAILED(rv)) {
return rv;
}
return NS_OK;
}
#if defined(XP_MACOSX) #if defined(XP_MACOSX)
// This is a copy of OS X's XRE_GetBinaryPath from nsAppRunner.cpp with the // 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 // gBinaryPath check removed so that the updater can reload the stub executable
@ -343,11 +381,12 @@ CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir,
#if defined(XP_MACOSX) #if defined(XP_MACOSX)
if (!CopyFileIntoUpdateDir(appDir, kUpdaterApp, updateDir)) if (!CopyFileIntoUpdateDir(appDir, kUpdaterApp, updateDir))
return false; return false;
CopyFileIntoUpdateDir(greDir, kUpdaterINI, updateDir);
#else #else
if (!CopyFileIntoUpdateDir(greDir, kUpdaterBin, updateDir)) if (!CopyFileIntoUpdateDir(greDir, kUpdaterBin, updateDir))
return false; return false;
#endif
CopyFileIntoUpdateDir(appDir, kUpdaterINI, updateDir); CopyFileIntoUpdateDir(appDir, kUpdaterINI, updateDir);
#endif
#if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(ANDROID) #if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(ANDROID)
nsCOMPtr<nsIFile> iconDir; nsCOMPtr<nsIFile> iconDir;
appDir->Clone(getter_AddRefs(iconDir)); appDir->Clone(getter_AddRefs(iconDir));
@ -466,40 +505,35 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
return; return;
#endif #endif
// Get the directory to which the update will be applied. On Mac OSX we need nsAutoCString installDirPath;
// to apply the update to the Updated.app directory under the Foo.app rv = GetInstallDirPath(appDir, installDirPath);
// directory which is the parent of the parent of the appDir. On other if (NS_FAILED(rv)) {
// platforms we will just apply to the appDir/updated.
nsCOMPtr<nsIFile> updatedDir;
#if defined(XP_MACOSX)
nsAutoCString 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; return;
#if defined(XP_WIN) }
// Get the directory where the update will be staged.
nsAutoCString applyToDir;
nsCOMPtr<nsIFile> updatedDir;
#ifdef XP_MACOSX
if (!GetFile(updateDir, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) {
#else
if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) {
#endif
return;
}
#ifdef XP_WIN
nsAutoString applyToDirW; nsAutoString applyToDirW;
rv = updatedDir->GetPath(applyToDirW); rv = updatedDir->GetPath(applyToDirW);
if (NS_FAILED(rv)) {
NS_ConvertUTF16toUTF8 applyToDir(applyToDirW); return;
}
applyToDir = NS_ConvertUTF16toUTF8(applyToDirW);
#else #else
nsAutoCString applyToDir;
rv = updatedDir->GetNativePath(applyToDir); rv = updatedDir->GetNativePath(applyToDir);
#endif #endif
#endif if (NS_FAILED(rv)) {
if (NS_FAILED(rv))
return; return;
}
// Make sure that the updated directory exists // Make sure that the updated directory exists
bool updatedDirExists = false; bool updatedDirExists = false;
@ -511,13 +545,11 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
#if defined(XP_WIN) #if defined(XP_WIN)
nsAutoString updateDirPathW; nsAutoString updateDirPathW;
rv = updateDir->GetPath(updateDirPathW); rv = updateDir->GetPath(updateDirPathW);
NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW); NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW);
#else #else
nsAutoCString updateDirPath; nsAutoCString updateDirPath;
rv = updateDir->GetNativePath(updateDirPath); rv = updateDir->GetNativePath(updateDirPath);
#endif #endif
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return; return;
@ -548,19 +580,20 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
immersiveArgc = 1; immersiveArgc = 1;
} }
#endif #endif
int argc = appArgc + 5 + immersiveArgc; int argc = appArgc + 6 + immersiveArgc;
char **argv = new char*[argc + 1]; char **argv = new char*[argc + 1];
if (!argv) if (!argv)
return; return;
argv[0] = (char*) updaterPath.get(); argv[0] = (char*) updaterPath.get();
argv[1] = (char*) updateDirPath.get(); argv[1] = (char*) updateDirPath.get();
argv[2] = (char*) applyToDir.get(); argv[2] = (char*) installDirPath.get();
argv[3] = (char*) pid.get(); argv[3] = (char*) applyToDir.get();
argv[4] = (char*) pid.get();
if (appArgc) { if (appArgc) {
argv[4] = workingDirPath; argv[5] = workingDirPath;
argv[5] = (char*) appFilePath.get(); argv[6] = (char*) appFilePath.get();
for (int i = 1; i < appArgc; ++i) for (int i = 1; i < appArgc; ++i)
argv[5 + i] = appArgv[i]; argv[6 + i] = appArgv[i];
#ifdef XP_WIN #ifdef XP_WIN
if (immersiveArgc) { if (immersiveArgc) {
argv[argc - 1] = "-ServerName:DefaultBrowserServer"; argv[argc - 1] = "-ServerName:DefaultBrowserServer";
@ -568,8 +601,8 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
#endif #endif
argv[argc] = nullptr; argv[argc] = nullptr;
} else { } else {
argc = 4; argc = 5;
argv[4] = nullptr; argv[5] = nullptr;
} }
if (gSafeMode) { if (gSafeMode) {
@ -726,79 +759,64 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
#endif #endif
// Get the directory to which the update will be applied. On Mac OSX we need nsAutoCString installDirPath;
// to apply the update to the Updated.app directory under the Foo.app rv = GetInstallDirPath(appDir, installDirPath);
// directory which is the parent of the parent of the appDir. On other if (NS_FAILED(rv))
// platforms we will just apply to the appDir/updated. return;
nsCOMPtr<nsIFile> updatedDir;
#if defined(XP_MACOSX) // Get the directory where the update was staged for replace and GONK OS
// Updates or where it will be applied.
#ifndef MOZ_WIDGET_GONK
// OS Updates are only supported on GONK so force it to false on everything
// but GONK to simplify the following logic.
isOSUpdate = false;
#endif
nsAutoCString applyToDir; nsAutoCString applyToDir;
{ nsCOMPtr<nsIFile> updatedDir;
nsCOMPtr<nsIFile> parentDir1, parentDir2; if (restart && !isOSUpdate) {
rv = appDir->GetParent(getter_AddRefs(parentDir1)); applyToDir.Assign(installDirPath);
if (NS_FAILED(rv)) } else {
#ifdef XP_MACOSX
if (!GetFile(updateDir, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) {
#else
if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) {
#endif
return; return;
rv = parentDir1->GetParent(getter_AddRefs(parentDir2)); }
if (NS_FAILED(rv)) #ifdef XP_WIN
nsAutoString applyToDirW;
rv = updatedDir->GetPath(applyToDirW);
if (NS_FAILED(rv)) {
return; return;
if (restart) { }
// Use the correct directory if we're not staging the update. applyToDir = NS_ConvertUTF16toUTF8(applyToDirW);
rv = parentDir2->GetNativePath(applyToDir); #elif MOZ_WIDGET_GONK
} else { if (isOSUpdate) {
if (!GetFile(parentDir2, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) if (!osApplyToDir) {
return; return;
}
rv = osApplyToDir->GetNativePath(applyToDir);
} else {
rv = updatedDir->GetNativePath(applyToDir); rv = updatedDir->GetNativePath(applyToDir);
} }
}
#else #else
if (restart) {
// Use the correct directory if we're not staging the update.
updatedDir = do_QueryInterface(appDir);
} 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
nsAutoCString applyToDir;
#if defined(MOZ_WIDGET_GONK)
if (isOSUpdate) {
if (!osApplyToDir) {
return;
}
rv = osApplyToDir->GetNativePath(applyToDir);
} else {
#endif // defined(MOZ_WIDGET_GONK)
rv = updatedDir->GetNativePath(applyToDir); rv = updatedDir->GetNativePath(applyToDir);
#if defined(MOZ_WIDGET_GONK)
}
#endif // defined(MOZ_WIDGET_GONK)
#endif // defined(XP_WIN)
#endif #endif
}
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return; return;
#if defined(XP_WIN) #if defined(XP_WIN)
nsAutoString updateDirPathW; nsAutoString updateDirPathW;
rv = updateDir->GetPath(updateDirPathW); rv = updateDir->GetPath(updateDirPathW);
NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW); NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW);
#else #else
nsAutoCString updateDirPath; nsAutoCString updateDirPath;
rv = updateDir->GetNativePath(updateDirPath); rv = updateDir->GetNativePath(updateDirPath);
#endif #endif
if (NS_FAILED(rv)) {
if (NS_FAILED(rv))
return; return;
}
// Get the current working directory. // Get the current working directory.
char workingDirPath[MAXPATHLEN]; char workingDirPath[MAXPATHLEN];
@ -834,19 +852,20 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
immersiveArgc = 1; immersiveArgc = 1;
} }
#endif #endif
int argc = appArgc + 5 + immersiveArgc; int argc = appArgc + 6 + immersiveArgc;
char **argv = new char*[argc + 1 ]; char **argv = new char*[argc + 1 ];
if (!argv) if (!argv)
return; return;
argv[0] = (char*) updaterPath.get(); argv[0] = (char*) updaterPath.get();
argv[1] = (char*) updateDirPath.get(); argv[1] = (char*) updateDirPath.get();
argv[2] = (char*) applyToDir.get(); argv[2] = (char*) installDirPath.get();
argv[3] = (char*) pid.get(); argv[3] = (char*) applyToDir.get();
argv[4] = (char*) pid.get();
if (restart && appArgc) { if (restart && appArgc) {
argv[4] = workingDirPath; argv[5] = workingDirPath;
argv[5] = (char*) appFilePath.get(); argv[6] = (char*) appFilePath.get();
for (int i = 1; i < appArgc; ++i) for (int i = 1; i < appArgc; ++i)
argv[5 + i] = appArgv[i]; argv[6 + i] = appArgv[i];
#ifdef XP_WIN #ifdef XP_WIN
if (immersiveArgc) { if (immersiveArgc) {
argv[argc - 1] = "-ServerName:DefaultBrowserServer"; argv[argc - 1] = "-ServerName:DefaultBrowserServer";
@ -854,8 +873,8 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
#endif #endif
argv[argc] = nullptr; argv[argc] = nullptr;
} else { } else {
argc = 4; argc = 5;
argv[4] = nullptr; argv[5] = nullptr;
} }
if (gSafeMode) { if (gSafeMode) {