зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset b55cdb5c3841 (bug 1728167) for causing xpcshell failures in bootstrapSvc.js
CLOSED TREE
This commit is contained in:
Родитель
5b0ce631d6
Коммит
0ffe70c46e
|
@ -450,59 +450,3 @@ void SetGroupOwnershipAndPermissions(const char* aAppBundle) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_13) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
|
||||
@interface NSTask (NSTask10_13)
|
||||
@property(copy) NSURL* executableURL NS_AVAILABLE_MAC(10_13);
|
||||
@property(copy) NSArray<NSString*>* arguments;
|
||||
- (BOOL)launchAndReturnError:(NSError**)error NS_AVAILABLE_MAC(10_13);
|
||||
@end
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Helper to launch macOS tasks via NSTask.
|
||||
*/
|
||||
static void LaunchTask(NSString* aPath, NSArray* aArguments) {
|
||||
if (@available(macOS 10.13, *)) {
|
||||
NSTask* task = [[NSTask alloc] init];
|
||||
[task setExecutableURL:[NSURL fileURLWithPath:aPath]];
|
||||
if (aArguments) {
|
||||
[task setArguments:aArguments];
|
||||
}
|
||||
[task launchAndReturnError:nil];
|
||||
[task release];
|
||||
} else {
|
||||
NSArray* arguments = aArguments;
|
||||
if (!arguments) {
|
||||
arguments = @[];
|
||||
}
|
||||
[NSTask launchedTaskWithLaunchPath:aPath arguments:arguments];
|
||||
}
|
||||
}
|
||||
|
||||
static void RegisterAppWithLaunchServices(NSString* aBundlePath) {
|
||||
NSArray* arguments = @[ @"-f", aBundlePath ];
|
||||
LaunchTask(@"/System/Library/Frameworks/CoreServices.framework/Frameworks/"
|
||||
@"LaunchServices.framework/Support/lsregister",
|
||||
arguments);
|
||||
}
|
||||
|
||||
static void StripQuarantineBit(NSString* aBundlePath) {
|
||||
NSArray* arguments = @[ @"-d", @"com.apple.quarantine", aBundlePath ];
|
||||
LaunchTask(@"/usr/bin/xattr", arguments);
|
||||
}
|
||||
|
||||
bool PerformInstallationFromDMG(int argc, char** argv) {
|
||||
MacAutoreleasePool pool;
|
||||
if (argc < 4) {
|
||||
return false;
|
||||
}
|
||||
NSString* bundlePath = [NSString stringWithUTF8String:argv[2]];
|
||||
NSString* destPath = [NSString stringWithUTF8String:argv[3]];
|
||||
if ([[NSFileManager defaultManager] copyItemAtPath:bundlePath toPath:destPath error:nil]) {
|
||||
RegisterAppWithLaunchServices(destPath);
|
||||
StripQuarantineBit(destPath);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,6 @@ void LaunchMacPostProcess(const char* aAppBundle);
|
|||
bool ObtainUpdaterArguments(int* argc, char*** argv);
|
||||
bool ServeElevatedUpdate(int argc, const char** argv);
|
||||
void SetGroupOwnershipAndPermissions(const char* aAppBundle);
|
||||
bool PerformInstallationFromDMG(int argc, char** argv);
|
||||
struct UpdateServerThreadArgs {
|
||||
int argc;
|
||||
const NS_tchar** argv;
|
||||
|
@ -2728,10 +2727,6 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
// argument prior to callbackIndex is the working directory.
|
||||
const int callbackIndex = 6;
|
||||
|
||||
// `isDMGInstall` is only ever true for macOS, but we are declaring it here
|
||||
// to avoid a ton of extra #ifdef's.
|
||||
bool isDMGInstall = false;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// We want to control file permissions explicitly, or else we could end up
|
||||
// corrupting installs for other users on the system. Accordingly, set the
|
||||
|
@ -2749,39 +2744,17 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == 4 && (strstr(argv[1], "-dmgInstall") != 0)) {
|
||||
isDMGInstall = true;
|
||||
if (isElevated) {
|
||||
PerformInstallationFromDMG(argc, argv);
|
||||
freeArguments(argc, argv);
|
||||
CleanupElevatedMacUpdate(true);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
NS_tchar elevatedLockFilePath[MAXPATHLEN] = {NS_T('\0')};
|
||||
NS_tsnprintf(elevatedLockFilePath,
|
||||
sizeof(elevatedLockFilePath) / sizeof(elevatedLockFilePath[0]),
|
||||
NS_T("%s\\update_elevated.lock"), gPatchDirPath);
|
||||
gUseSecureOutputPath =
|
||||
sUsingService || (NS_tremove(elevatedLockFilePath) && errno != ENOENT);
|
||||
#endif
|
||||
|
||||
if (!isDMGInstall) {
|
||||
// Skip update-related code path for DMG installs.
|
||||
|
||||
#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && !defined(XP_MACOSX)
|
||||
// On Windows and Mac we rely on native APIs to do verifications so we don't
|
||||
// need to initialize NSS at all there.
|
||||
// Otherwise, minimize the amount of NSS we depend on by avoiding all the
|
||||
// NSS databases.
|
||||
// Otherwise, minimize the amount of NSS we depend on by avoiding all the NSS
|
||||
// databases.
|
||||
if (NSS_NoDB_Init(nullptr) != SECSuccess) {
|
||||
PRErrorCode error = PR_GetError();
|
||||
fprintf(stderr, "Could not initialize NSS: %s (%d)",
|
||||
PR_ErrorToName(error), (int)error);
|
||||
fprintf(stderr, "Could not initialize NSS: %s (%d)", PR_ErrorToName(error),
|
||||
(int)error);
|
||||
_exit(1);
|
||||
}
|
||||
#endif
|
||||
|
@ -2797,17 +2770,17 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
// To process an update the updater command line must at a minimum have the
|
||||
// directory path containing the updater.mar file to process as the first
|
||||
// argument, the install directory as the second argument, and the directory
|
||||
// to apply the update to as the third argument. When the updater is
|
||||
// launched by another process the PID of the parent process should be
|
||||
// provided in the optional fourth argument and the updater will wait on the
|
||||
// parent process to exit if the value is non-zero and the process is
|
||||
// present. This is necessary due to not being able to update files that are
|
||||
// in use on Windows. The optional fifth argument is the callback's working
|
||||
// directory and the optional sixth argument is the callback path. The
|
||||
// callback is the application to launch after updating and it will be
|
||||
// launched when these arguments are provided whether the update was
|
||||
// successful or not. All remaining arguments are optional and are passed to
|
||||
// the callback when it is launched.
|
||||
// to apply the update to as the third argument. When the updater is launched
|
||||
// by another process the PID of the parent process should be provided in the
|
||||
// optional fourth argument and the updater will wait on the parent process to
|
||||
// exit if the value is non-zero and the process is present. This is necessary
|
||||
// due to not being able to update files that are in use on Windows. The
|
||||
// optional fifth argument is the callback's working directory and the
|
||||
// optional sixth argument is the callback path. The callback is the
|
||||
// application to launch after updating and it will be launched when these
|
||||
// arguments are provided whether the update was successful or not. All
|
||||
// remaining arguments are optional and are passed to the callback when it is
|
||||
// launched.
|
||||
if (argc < 4) {
|
||||
fprintf(stderr,
|
||||
"Usage: updater patch-dir install-dir apply-to-dir [wait-pid "
|
||||
|
@ -2853,6 +2826,15 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
NS_tstrncpy(gPatchDirPath, argv[1], MAXPATHLEN);
|
||||
gPatchDirPath[MAXPATHLEN - 1] = NS_T('\0');
|
||||
|
||||
#ifdef XP_WIN
|
||||
NS_tchar elevatedLockFilePath[MAXPATHLEN] = {NS_T('\0')};
|
||||
NS_tsnprintf(elevatedLockFilePath,
|
||||
sizeof(elevatedLockFilePath) / sizeof(elevatedLockFilePath[0]),
|
||||
NS_T("%s\\update_elevated.lock"), gPatchDirPath);
|
||||
gUseSecureOutputPath =
|
||||
sUsingService || (NS_tremove(elevatedLockFilePath) && errno != ENOENT);
|
||||
#endif
|
||||
|
||||
// This check is also performed in workmonitor.cpp since the maintenance
|
||||
// service can be called directly.
|
||||
if (!IsValidFullPath(argv[2])) {
|
||||
|
@ -2869,9 +2851,6 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // if (!isDMGInstall)
|
||||
|
||||
// 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
|
||||
|
@ -2887,10 +2866,7 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
bool useService = false;
|
||||
bool testOnlyFallbackKeyExists = false;
|
||||
bool noServiceFallback = false;
|
||||
#endif
|
||||
|
||||
if (!isDMGInstall) {
|
||||
#ifdef XP_WIN
|
||||
// We never want the service to be used unless we build with
|
||||
// the maintenance service.
|
||||
# ifdef MOZ_MAINTENANCE_SERVICE
|
||||
|
@ -2924,8 +2900,6 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
}
|
||||
#endif
|
||||
|
||||
} // if (!isDMGInstall)
|
||||
|
||||
// If there is a PID specified and it is not '0' then wait for the process to
|
||||
// exit.
|
||||
NS_tpid pid = 0;
|
||||
|
@ -2942,7 +2916,6 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!isDMGInstall) {
|
||||
// This check is also performed in workmonitor.cpp since the maintenance
|
||||
// service can be called directly.
|
||||
if (!IsValidFullPath(argv[3])) {
|
||||
|
@ -2961,8 +2934,8 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
}
|
||||
// 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.
|
||||
// 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);
|
||||
|
@ -3008,12 +2981,10 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
ShouldRunSilently(argc - callbackIndex, argv + callbackIndex);
|
||||
}
|
||||
|
||||
} // if (!isDMGInstall)
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (!isElevated && (!IsRecursivelyWritable(argv[2]) || isDMGInstall)) {
|
||||
// If the app directory isn't recursively writeable or if this is a DMG
|
||||
// install, an elevated helper process is required.
|
||||
if (!isElevated && !IsRecursivelyWritable(argv[2])) {
|
||||
// If the app directory isn't recursively writeable, an elevated update is
|
||||
// required.
|
||||
if (sUpdateSilently) {
|
||||
// An elevated update always requires an elevation dialog, so if we are
|
||||
// updating silently, don't do an elevated update.
|
||||
|
@ -3037,10 +3008,8 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
if (t1.Run(ServeElevatedUpdateThreadFunc, &threadArgs) == 0) {
|
||||
// Show an indeterminate progress bar while an elevated update is in
|
||||
// progress.
|
||||
if (!isDMGInstall) {
|
||||
ShowProgressUI(true);
|
||||
}
|
||||
}
|
||||
t1.Join();
|
||||
}
|
||||
|
||||
|
@ -3049,11 +3018,6 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
HANDLE updateLockFileHandle = INVALID_HANDLE_VALUE;
|
||||
#endif
|
||||
|
||||
if (!isDMGInstall) {
|
||||
NS_tchar logFilePath[MAXPATHLEN + 1] = {L'\0'};
|
||||
#ifdef XP_WIN
|
||||
if (gUseSecureOutputPath) {
|
||||
|
@ -3169,13 +3133,13 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
// used, in case of an error when fallback is not enabled we write the
|
||||
// error to the update.status file.
|
||||
// When fallback is disabled (MOZ_NO_SERVICE_FALLBACK does not exist) then
|
||||
// we will instead fallback to not using the service and display a UAC
|
||||
// prompt.
|
||||
// we will instead fallback to not using the service and display a UAC prompt.
|
||||
int lastFallbackError = FALLBACKKEY_UNKNOWN_ERROR;
|
||||
|
||||
// Check whether a second instance of the updater should be launched by the
|
||||
// maintenance service or with the 'runas' verb when write access is denied
|
||||
// to the installation directory.
|
||||
// maintenance service or with the 'runas' verb when write access is denied to
|
||||
// the installation directory.
|
||||
HANDLE updateLockFileHandle = INVALID_HANDLE_VALUE;
|
||||
if (!sUsingService &&
|
||||
(argc > callbackIndex || sStagedUpdate || sReplaceRequest)) {
|
||||
NS_tchar updateLockFilePath[MAXPATHLEN];
|
||||
|
@ -3184,8 +3148,7 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
// <install_dir>\updated.update_in_progress.lock
|
||||
NS_tsnprintf(updateLockFilePath,
|
||||
sizeof(updateLockFilePath) / sizeof(updateLockFilePath[0]),
|
||||
NS_T("%s/updated.update_in_progress.lock"),
|
||||
gInstallDirPath);
|
||||
NS_T("%s/updated.update_in_progress.lock"), gInstallDirPath);
|
||||
} else if (sReplaceRequest) {
|
||||
// When processing a replace request, the lock file is:
|
||||
// <install_dir>\..\moz_update_in_progress.lock
|
||||
|
@ -3251,9 +3214,9 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
elevatedFileHandle = CreateFileW(
|
||||
elevatedLockFilePath, GENERIC_READ | GENERIC_WRITE, 0, nullptr,
|
||||
OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
elevatedFileHandle =
|
||||
CreateFileW(elevatedLockFilePath, GENERIC_READ | GENERIC_WRITE, 0,
|
||||
nullptr, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, nullptr);
|
||||
if (elevatedFileHandle == INVALID_HANDLE_VALUE) {
|
||||
LOG(("Unable to create elevated lock file! Exiting"));
|
||||
output_finish();
|
||||
|
@ -3348,12 +3311,12 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
// If the command was launched then wait for the service to be done.
|
||||
if (useService) {
|
||||
bool showProgressUI = false;
|
||||
// Never show the progress UI when staging updates or in a
|
||||
// background task.
|
||||
// Never show the progress UI when staging updates or in a background
|
||||
// task.
|
||||
if (!sStagedUpdate && !sUpdateSilently) {
|
||||
// We need to call this separately instead of allowing
|
||||
// ShowProgressUI to initialize the strings because the service
|
||||
// will move the ini file out of the way when running updater.
|
||||
// ShowProgressUI to initialize the strings because the service will
|
||||
// move the ini file out of the way when running updater.
|
||||
showProgressUI = !InitProgressUIStrings();
|
||||
}
|
||||
|
||||
|
@ -3442,8 +3405,8 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
// determine if the updater has created a new one.
|
||||
char uuidStringBefore[UUID_LEN] = {'\0'};
|
||||
bool checkID = GetSecureID(uuidStringBefore);
|
||||
// Write a catchall failure status in case it fails without changing
|
||||
// the status.
|
||||
// Write a catchall failure status in case it fails without changing the
|
||||
// status.
|
||||
WriteStatusFile(UPDATE_STATUS_UNCHANGED);
|
||||
|
||||
SHELLEXECUTEINFO sinfo;
|
||||
|
@ -3477,9 +3440,9 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
} else {
|
||||
// Don't copy the secure output files if the elevation request was
|
||||
// canceled since the status file written below is in the patch
|
||||
// directory. At this point it should already be set to false and
|
||||
// this is set here to make it clear that it should be false at this
|
||||
// point and to prevent future changes from regressing this code.
|
||||
// directory. At this point it should already be set to false and this
|
||||
// is set here to make it clear that it should be false at this point
|
||||
// and to prevent future changes from regressing this code.
|
||||
gCopyOutputFiles = false;
|
||||
WriteStatusFile(ELEVATION_CANCELED);
|
||||
}
|
||||
|
@ -3488,9 +3451,9 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
// If we started the elevated updater, and it finished, check the secure
|
||||
// update status file to make sure that it succeeded, and if it did we
|
||||
// need to launch the PostUpdate process in the unelevated updater which
|
||||
// is running in the current user's session. Note that we don't need to
|
||||
// do this when staging an update since the PostUpdate step runs during
|
||||
// the replace request.
|
||||
// is running in the current user's session. Note that we don't need to do
|
||||
// this when staging an update since the PostUpdate step runs during the
|
||||
// replace request.
|
||||
if (!sStagedUpdate) {
|
||||
bool updateStatusSucceeded = false;
|
||||
if (IsSecureUpdateStatusSucceeded(updateStatusSucceeded) &&
|
||||
|
@ -3530,9 +3493,9 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
}
|
||||
return 0;
|
||||
|
||||
// This is the end of the code block for launching another instance of
|
||||
// the updater using either the maintenance service or with the 'runas'
|
||||
// verb when the updater doesn't have write access to the installation
|
||||
// This is the end of the code block for launching another instance of the
|
||||
// updater using either the maintenance service or with the 'runas' verb
|
||||
// when the updater doesn't have write access to the installation
|
||||
// directory.
|
||||
}
|
||||
// This is the end of the code block when the updater was not launched by
|
||||
|
@ -3540,8 +3503,7 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
// installation directory.
|
||||
}
|
||||
// If we made it this far this is the updater instance that will perform the
|
||||
// actual update and gCopyOutputFiles will be false (e.g. the default
|
||||
// value).
|
||||
// actual update and gCopyOutputFiles will be false (e.g. the default value).
|
||||
#endif
|
||||
|
||||
if (sStagedUpdate) {
|
||||
|
@ -3556,15 +3518,15 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
CloseHandle(updateLockFileHandle);
|
||||
}
|
||||
# endif
|
||||
// WRITE_ERROR is one of the cases where the staging failure falls back
|
||||
// to applying the update on startup.
|
||||
// WRITE_ERROR is one of the cases where the staging failure falls back to
|
||||
// applying the update on startup.
|
||||
WriteStatusFile(WRITE_ERROR);
|
||||
output_finish();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
// When staging updates, blow away the old installation directory and
|
||||
// create it from scratch.
|
||||
// When staging updates, blow away the old installation directory and create
|
||||
// it from scratch.
|
||||
ensure_remove_recursive(gWorkingDirPath);
|
||||
}
|
||||
if (!sReplaceRequest) {
|
||||
|
@ -3601,10 +3563,10 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
HANDLE callbackFile = INVALID_HANDLE_VALUE;
|
||||
if (argc > callbackIndex) {
|
||||
// If the callback executable is specified it must exist for a successful
|
||||
// update. It is important we null out the whole buffer here because
|
||||
// later we make the assumption that the callback application is inside
|
||||
// the apply-to dir. If we don't have a fully null'ed out buffer it can
|
||||
// lead to stack corruption which causes crashes and other problems.
|
||||
// update. It is important we null out the whole buffer here because later
|
||||
// we make the assumption that the callback application is inside the
|
||||
// apply-to dir. If we don't have a fully null'ed out buffer it can lead
|
||||
// to stack corruption which causes crashes and other problems.
|
||||
NS_tchar callbackLongPath[MAXPATHLEN];
|
||||
ZeroMemory(callbackLongPath, sizeof(callbackLongPath));
|
||||
NS_tchar* targetPath = argv[callbackIndex];
|
||||
|
@ -3664,8 +3626,8 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
++s;
|
||||
}
|
||||
|
||||
// Copy the string and replace backslashes with forward slashes along
|
||||
// the way.
|
||||
// Copy the string and replace backslashes with forward slashes along the
|
||||
// way.
|
||||
do {
|
||||
if (*s == NS_T('\\')) {
|
||||
*d = NS_T('/');
|
||||
|
@ -3697,8 +3659,7 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Make a copy of the callback executable so it can be read when
|
||||
// patching.
|
||||
// Make a copy of the callback executable so it can be read when patching.
|
||||
if (!CopyFileW(argv[callbackIndex], gCallbackBackupPath, false)) {
|
||||
DWORD copyFileError = GetLastError();
|
||||
if (copyFileError == ERROR_ACCESS_DENIED) {
|
||||
|
@ -3750,8 +3711,8 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
|
||||
// Fail the update if the last error was not a sharing violation.
|
||||
if (lastWriteError != ERROR_SHARING_VIOLATION) {
|
||||
LOG((
|
||||
"NS_main: callback app file in use, failed to exclusively open "
|
||||
LOG(
|
||||
("NS_main: callback app file in use, failed to exclusively open "
|
||||
"executable file: " LOG_S,
|
||||
argv[callbackIndex]));
|
||||
if (lastWriteError == ERROR_ACCESS_DENIED) {
|
||||
|
@ -3764,12 +3725,12 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
}
|
||||
|
||||
// Fail even on sharing violation from a background task, since a
|
||||
// background task has a higher risk of interfering with a running
|
||||
// app. Note that this does not apply when staging (when an exclusive
|
||||
// lock isn't necessary), as there is no callback.
|
||||
// background task has a higher risk of interfering with a running app.
|
||||
// Note that this does not apply when staging (when an exclusive lock
|
||||
// isn't necessary), as there is no callback.
|
||||
if (lastWriteError == ERROR_SHARING_VIOLATION && sUpdateSilently) {
|
||||
LOG((
|
||||
"NS_main: callback app file in use, failed to exclusively open "
|
||||
LOG(
|
||||
("NS_main: callback app file in use, failed to exclusively open "
|
||||
"executable file from background task: " LOG_S,
|
||||
argv[callbackIndex]));
|
||||
WriteStatusFile(WRITE_ERROR_BACKGROUND_TASK_SHARING_VIOLATION);
|
||||
|
@ -3786,8 +3747,8 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
}
|
||||
output_finish();
|
||||
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
|
||||
LaunchCallbackApp(argv[5], argc - callbackIndex,
|
||||
argv + callbackIndex, sUsingService);
|
||||
LaunchCallbackApp(argv[5], argc - callbackIndex, argv + callbackIndex,
|
||||
sUsingService);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -3803,12 +3764,12 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
// request; it can be used during a replace request but then it doesn't
|
||||
// use gDeleteDirPath.
|
||||
if (!sStagedUpdate && !sReplaceRequest) {
|
||||
// The directory to move files that are in use to on Windows. This
|
||||
// directory will be deleted after the update is finished, on OS reboot
|
||||
// using MoveFileEx if it contains files that are in use, or by the post
|
||||
// update process after the update finishes. On Windows when performing a
|
||||
// normal update (e.g. the update is not a staged update and is not a
|
||||
// replace request) gWorkingDirPath is the same as gInstallDirPath and
|
||||
// The directory to move files that are in use to on Windows. This directory
|
||||
// will be deleted after the update is finished, on OS reboot using
|
||||
// MoveFileEx if it contains files that are in use, or by the post update
|
||||
// process after the update finishes. On Windows when performing a normal
|
||||
// update (e.g. the update is not a staged update and is not a replace
|
||||
// request) gWorkingDirPath is the same as gInstallDirPath and
|
||||
// gWorkingDirPath is used because it is the destination directory.
|
||||
NS_tsnprintf(gDeleteDirPath,
|
||||
sizeof(gDeleteDirPath) / sizeof(gDeleteDirPath[0]),
|
||||
|
@ -3822,8 +3783,8 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
|
||||
// Run update process on a background thread. ShowProgressUI may return
|
||||
// before QuitProgressUI has been called, so wait for UpdateThreadFunc to
|
||||
// terminate. Avoid showing the progress UI when staging an update, or if
|
||||
// this is an elevated process on OSX.
|
||||
// terminate. Avoid showing the progress UI when staging an update, or if this
|
||||
// is an elevated process on OSX.
|
||||
Thread t;
|
||||
if (t.Run(UpdateThreadFunc, nullptr) == 0) {
|
||||
if (!sStagedUpdate && !sReplaceRequest && !sUpdateSilently
|
||||
|
@ -3851,18 +3812,17 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
}
|
||||
|
||||
if (!sStagedUpdate && !sReplaceRequest && _wrmdir(gDeleteDirPath)) {
|
||||
LOG(("NS_main: unable to remove directory: " LOG_S ", err: %d",
|
||||
DELETE_DIR, errno));
|
||||
LOG(("NS_main: unable to remove directory: " LOG_S ", err: %d", DELETE_DIR,
|
||||
errno));
|
||||
// The directory probably couldn't be removed due to it containing files
|
||||
// that are in use and will be removed on OS reboot. The call to remove
|
||||
// the directory on OS reboot is done after the calls to remove the files
|
||||
// so the files are removed first on OS reboot since the directory must be
|
||||
// empty for the directory removal to be successful. The MoveFileEx call
|
||||
// to remove the directory on OS reboot will fail if the process doesn't
|
||||
// have write access to the HKEY_LOCAL_MACHINE registry key but this is ok
|
||||
// since the installer / uninstaller will delete the directory along with
|
||||
// its contents after an update is applied, on reinstall, and on
|
||||
// uninstall.
|
||||
// that are in use and will be removed on OS reboot. The call to remove the
|
||||
// directory on OS reboot is done after the calls to remove the files so the
|
||||
// files are removed first on OS reboot since the directory must be empty
|
||||
// for the directory removal to be successful. The MoveFileEx call to remove
|
||||
// the directory on OS reboot will fail if the process doesn't have write
|
||||
// access to the HKEY_LOCAL_MACHINE registry key but this is ok since the
|
||||
// installer / uninstaller will delete the directory along with its contents
|
||||
// after an update is applied, on reinstall, and on uninstall.
|
||||
if (MoveFileEx(gDeleteDirPath, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) {
|
||||
LOG(("NS_main: directory will be removed on OS reboot: " LOG_S,
|
||||
DELETE_DIR));
|
||||
|
@ -3875,8 +3835,6 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
}
|
||||
#endif /* XP_WIN */
|
||||
|
||||
} // if (!isDMGInstall)
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (isElevated) {
|
||||
SetGroupOwnershipAndPermissions(gInstallDirPath);
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <sys/param.h>
|
||||
|
||||
#include "MacRunFromDmgUtils.h"
|
||||
#include "MacLaunchHelper.h"
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/intl/Localization.h"
|
||||
|
@ -26,13 +25,19 @@
|
|||
#include "nsIMacDockSupport.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsString.h"
|
||||
#include "nsUpdateDriver.h"
|
||||
#include "SDKDeclarations.h"
|
||||
|
||||
// For IOKit docs, see:
|
||||
// https://developer.apple.com/documentation/iokit
|
||||
// https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_13) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
|
||||
@interface NSTask (NSTask10_13)
|
||||
@property(copy) NSURL* executableURL NS_AVAILABLE_MAC(10_13);
|
||||
@property(copy) NSArray<NSString*>* arguments;
|
||||
- (BOOL)launchAndReturnError:(NSError**)error NS_AVAILABLE_MAC(10_13);
|
||||
@end
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace MacRunFromDmgUtils {
|
||||
|
||||
|
@ -173,41 +178,11 @@ static void StripQuarantineBit(NSString* aBundlePath) {
|
|||
LaunchTask(@"/usr/bin/xattr", arguments);
|
||||
}
|
||||
|
||||
bool LaunchElevatedDmgInstall(NSString* aBundlePath, NSArray* aArguments) {
|
||||
NSTask* task;
|
||||
if (@available(macOS 10.13, *)) {
|
||||
task = [[NSTask alloc] init];
|
||||
[task setExecutableURL:[NSURL fileURLWithPath:aBundlePath]];
|
||||
if (aArguments) {
|
||||
[task setArguments:aArguments];
|
||||
}
|
||||
[task launchAndReturnError:nil];
|
||||
} else {
|
||||
NSArray* arguments = aArguments;
|
||||
if (!arguments) {
|
||||
arguments = @[];
|
||||
}
|
||||
task = [NSTask launchedTaskWithLaunchPath:aBundlePath arguments:arguments];
|
||||
}
|
||||
|
||||
bool didSucceed = InstallPrivilegedHelper();
|
||||
[task waitUntilExit];
|
||||
if (@available(macOS 10.13, *)) {
|
||||
[task release];
|
||||
}
|
||||
if (!didSucceed) {
|
||||
AbortElevatedUpdate();
|
||||
}
|
||||
|
||||
return didSucceed;
|
||||
}
|
||||
|
||||
// Note: both arguments are expected to contain the app name (to end with
|
||||
// '.app').
|
||||
static bool InstallFromDmg(NSString* aBundlePath, NSString* aDestPath) {
|
||||
bool installSuccessful = false;
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
if ([fileManager copyItemAtPath:aBundlePath toPath:aDestPath error:nil]) {
|
||||
if ([[NSFileManager defaultManager] copyItemAtPath:aBundlePath toPath:aDestPath error:nil]) {
|
||||
RegisterAppWithLaunchServices(aDestPath);
|
||||
StripQuarantineBit(aDestPath);
|
||||
installSuccessful = true;
|
||||
|
@ -215,22 +190,10 @@ static bool InstallFromDmg(NSString* aBundlePath, NSString* aDestPath) {
|
|||
|
||||
// The installation may have been unsuccessful if the user did not have the
|
||||
// rights to write to the Applications directory. Check for this situation and
|
||||
// launch an elevated installation if necessary. Rather than creating a new,
|
||||
// dedicated executable for this installation and incurring the
|
||||
// added maintenance burden of yet another executable, we are using the
|
||||
// updater binary. Since bug 394984 landed, the updater has the ability to
|
||||
// install and launch itself as a Privileged Helper tool, which is what is
|
||||
// necessary here.
|
||||
// launch an elevated installation if necessary.
|
||||
NSString* destDir = [aDestPath stringByDeletingLastPathComponent];
|
||||
if (!installSuccessful && ![fileManager isWritableFileAtPath:destDir]) {
|
||||
NSString* updaterBinPath = [NSString pathWithComponents:@[
|
||||
aBundlePath, @"Contents", @"MacOS", [NSString stringWithUTF8String:UPDATER_APP], @"Contents",
|
||||
@"MacOS", [NSString stringWithUTF8String:UPDATER_BIN]
|
||||
]];
|
||||
|
||||
NSArray* arguments = @[ @"-dmgInstall", aBundlePath, aDestPath ];
|
||||
LaunchElevatedDmgInstall(updaterBinPath, arguments);
|
||||
installSuccessful = [fileManager fileExistsAtPath:aDestPath];
|
||||
if (!installSuccessful && ![[NSFileManager defaultManager] isWritableFileAtPath:destDir]) {
|
||||
// TODO: launch elevated installation.
|
||||
}
|
||||
|
||||
if (!installSuccessful) {
|
||||
|
|
|
@ -64,6 +64,16 @@ static LazyLogModule sUpdateLog("updatedriver");
|
|||
#endif
|
||||
#define LOG(args) MOZ_LOG(sUpdateLog, mozilla::LogLevel::Debug, args)
|
||||
|
||||
#ifdef XP_WIN
|
||||
# define UPDATER_BIN "updater.exe"
|
||||
# define MAINTENANCE_SVC_NAME L"MozillaMaintenance"
|
||||
#elif XP_MACOSX
|
||||
# define UPDATER_APP "updater.app"
|
||||
# define UPDATER_BIN "org.mozilla.updater"
|
||||
#else
|
||||
# define UPDATER_BIN "updater"
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
static void UpdateDriverSetupMacCommandLine(int& argc, char**& argv,
|
||||
bool restart) {
|
||||
|
|
|
@ -26,16 +26,6 @@ typedef pid_t ProcessType;
|
|||
typedef PRProcess* ProcessType;
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
# define UPDATER_BIN "updater.exe"
|
||||
# define MAINTENANCE_SVC_NAME L"MozillaMaintenance"
|
||||
#elif XP_MACOSX
|
||||
# define UPDATER_APP "updater.app"
|
||||
# define UPDATER_BIN "org.mozilla.updater"
|
||||
#else
|
||||
# define UPDATER_BIN "updater"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function processes any available updates. As part of that process, it
|
||||
* may exit the current process and relaunch it at a later time.
|
||||
|
|
|
@ -30,12 +30,6 @@ using NSAppearanceName = NSString*;
|
|||
@property(class, strong, readonly) NSColor* systemPurpleColor NS_AVAILABLE_MAC(10_10);
|
||||
@end
|
||||
|
||||
@interface NSTask (NSTask10_13)
|
||||
@property(copy) NSURL* executableURL NS_AVAILABLE_MAC(10_13);
|
||||
@property(copy) NSArray<NSString*>* arguments;
|
||||
- (BOOL)launchAndReturnError:(NSError**)error NS_AVAILABLE_MAC(10_13);
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_14) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_14
|
||||
|
|
Загрузка…
Ссылка в новой задаче