mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-24 09:27:31 +09:00
parent
470a6e4401
commit
13fcc4a046
949 changed files with 95662 additions and 444 deletions
|
|
@ -14,3 +14,16 @@ endif
|
|||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
||||
export::
|
||||
sed -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' $(srcdir)/macbuild/Contents/Info.plist.in > $(DIST)/bin/Info.plist
|
||||
libs::
|
||||
$(NSINSTALL) -D $(DIST)/bin/updater.app
|
||||
rsync -a -C --exclude '*.in' $(srcdir)/macbuild/Contents $(DIST)/bin/updater.app
|
||||
rsync -a -C $(DIST)/bin/Info.plist $(DIST)/bin/updater.app/Contents
|
||||
sed -e 's/%APP_NAME%/$(MOZ_APP_DISPLAYNAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \
|
||||
iconv -f UTF-8 -t UTF-16 > $(DIST)/bin/updater.app/Contents/Resources/English.lproj/InfoPlist.strings
|
||||
$(NSINSTALL) -D $(DIST)/bin/updater.app/Contents/MacOS
|
||||
$(NSINSTALL) $(DIST)/bin/org.mozilla.updater $(DIST)/bin/updater.app/Contents/MacOS
|
||||
endif
|
||||
|
|
|
|||
384
toolkit/mozapps/update/updater/launchchild_osx.mm
Normal file
384
toolkit/mozapps/update/updater/launchchild_osx.mm
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <crt_externs.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <spawn.h>
|
||||
#include <SystemConfiguration/SystemConfiguration.h>
|
||||
#include "readstrings.h"
|
||||
|
||||
class MacAutoreleasePool {
|
||||
public:
|
||||
MacAutoreleasePool()
|
||||
{
|
||||
mPool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
~MacAutoreleasePool()
|
||||
{
|
||||
[mPool release];
|
||||
}
|
||||
|
||||
private:
|
||||
NSAutoreleasePool* mPool;
|
||||
};
|
||||
|
||||
void LaunchChild(int argc, const char** argv)
|
||||
{
|
||||
MacAutoreleasePool pool;
|
||||
|
||||
@try {
|
||||
NSString* launchPath = [NSString stringWithUTF8String:argv[0]];
|
||||
NSMutableArray* arguments = [NSMutableArray arrayWithCapacity:argc - 1];
|
||||
for (int i = 1; i < argc; i++) {
|
||||
[arguments addObject:[NSString stringWithUTF8String:argv[i]]];
|
||||
}
|
||||
[NSTask launchedTaskWithLaunchPath:launchPath
|
||||
arguments:arguments];
|
||||
} @catch (NSException* e) {
|
||||
NSLog(@"%@: %@", e.name, e.reason);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LaunchMacPostProcess(const char* aAppBundle)
|
||||
{
|
||||
MacAutoreleasePool pool;
|
||||
|
||||
// Launch helper to perform post processing for the update; this is the Mac
|
||||
// analogue of LaunchWinPostProcess (PostUpdateWin).
|
||||
NSString* iniPath = [NSString stringWithUTF8String:aAppBundle];
|
||||
iniPath =
|
||||
[iniPath stringByAppendingPathComponent:@"Contents/Resources/updater.ini"];
|
||||
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
if (![fileManager fileExistsAtPath:iniPath]) {
|
||||
// the file does not exist; there is nothing to run
|
||||
return;
|
||||
}
|
||||
|
||||
int readResult;
|
||||
char values[2][MAX_TEXT_LEN];
|
||||
readResult = ReadStrings([iniPath UTF8String],
|
||||
"ExeRelPath\0ExeArg\0",
|
||||
2,
|
||||
values,
|
||||
"PostUpdateMac");
|
||||
if (readResult) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *exeRelPath = [NSString stringWithUTF8String:values[0]];
|
||||
NSString *exeArg = [NSString stringWithUTF8String:values[1]];
|
||||
if (!exeArg || !exeRelPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The path must not traverse directories and it must be a relative path.
|
||||
if ([exeRelPath rangeOfString:@".."].location != NSNotFound ||
|
||||
[exeRelPath rangeOfString:@"./"].location != NSNotFound ||
|
||||
[exeRelPath rangeOfString:@"/"].location == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSString* exeFullPath = [NSString stringWithUTF8String:aAppBundle];
|
||||
exeFullPath = [exeFullPath stringByAppendingPathComponent:exeRelPath];
|
||||
|
||||
char optVals[1][MAX_TEXT_LEN];
|
||||
readResult = ReadStrings([iniPath UTF8String],
|
||||
"ExeAsync\0",
|
||||
1,
|
||||
optVals,
|
||||
"PostUpdateMac");
|
||||
|
||||
NSTask *task = [[NSTask alloc] init];
|
||||
[task setLaunchPath:exeFullPath];
|
||||
[task setArguments:[NSArray arrayWithObject:exeArg]];
|
||||
[task launch];
|
||||
if (!readResult) {
|
||||
NSString *exeAsync = [NSString stringWithUTF8String:optVals[0]];
|
||||
if ([exeAsync isEqualToString:@"false"]) {
|
||||
[task waitUntilExit];
|
||||
}
|
||||
}
|
||||
// ignore the return value of the task, there's nothing we can do with it
|
||||
[task release];
|
||||
}
|
||||
|
||||
id ConnectToUpdateServer()
|
||||
{
|
||||
MacAutoreleasePool pool;
|
||||
|
||||
id updateServer = nil;
|
||||
BOOL isConnected = NO;
|
||||
int currTry = 0;
|
||||
const int numRetries = 10; // Number of IPC connection retries before
|
||||
// giving up.
|
||||
while (!isConnected && currTry < numRetries) {
|
||||
@try {
|
||||
updateServer = (id)[NSConnection
|
||||
rootProxyForConnectionWithRegisteredName:
|
||||
@"org.mozilla.updater.server"
|
||||
host:nil
|
||||
usingNameServer:[NSSocketPortNameServer sharedInstance]];
|
||||
if (!updateServer ||
|
||||
![updateServer respondsToSelector:@selector(abort)] ||
|
||||
![updateServer respondsToSelector:@selector(getArguments)] ||
|
||||
![updateServer respondsToSelector:@selector(shutdown)]) {
|
||||
NSLog(@"Server doesn't exist or doesn't provide correct selectors.");
|
||||
sleep(1); // Wait 1 second.
|
||||
currTry++;
|
||||
} else {
|
||||
isConnected = YES;
|
||||
}
|
||||
} @catch (NSException* e) {
|
||||
NSLog(@"Encountered exception, retrying: %@: %@", e.name, e.reason);
|
||||
sleep(1); // Wait 1 second.
|
||||
currTry++;
|
||||
}
|
||||
}
|
||||
if (!isConnected) {
|
||||
NSLog(@"Failed to connect to update server after several retries.");
|
||||
return nil;
|
||||
}
|
||||
return updateServer;
|
||||
}
|
||||
|
||||
void CleanupElevatedMacUpdate(bool aFailureOccurred)
|
||||
{
|
||||
MacAutoreleasePool pool;
|
||||
|
||||
id updateServer = ConnectToUpdateServer();
|
||||
if (updateServer) {
|
||||
@try {
|
||||
if (aFailureOccurred) {
|
||||
[updateServer performSelector:@selector(abort)];
|
||||
} else {
|
||||
[updateServer performSelector:@selector(shutdown)];
|
||||
}
|
||||
} @catch (NSException* e) { }
|
||||
}
|
||||
|
||||
NSFileManager* manager = [NSFileManager defaultManager];
|
||||
[manager removeItemAtPath:@"/Library/PrivilegedHelperTools/org.mozilla.updater"
|
||||
error:nil];
|
||||
[manager removeItemAtPath:@"/Library/LaunchDaemons/org.mozilla.updater.plist"
|
||||
error:nil];
|
||||
const char* launchctlArgs[] = {"/bin/launchctl",
|
||||
"remove",
|
||||
"org.mozilla.updater"};
|
||||
// The following call will terminate the current process due to the "remove"
|
||||
// argument in launchctlArgs.
|
||||
LaunchChild(3, launchctlArgs);
|
||||
}
|
||||
|
||||
// Note: Caller is responsible for freeing argv.
|
||||
bool ObtainUpdaterArguments(int* argc, char*** argv)
|
||||
{
|
||||
MacAutoreleasePool pool;
|
||||
|
||||
id updateServer = ConnectToUpdateServer();
|
||||
if (!updateServer) {
|
||||
// Let's try our best and clean up.
|
||||
CleanupElevatedMacUpdate(true);
|
||||
return false; // Won't actually get here due to CleanupElevatedMacUpdate.
|
||||
}
|
||||
|
||||
@try {
|
||||
NSArray* updaterArguments =
|
||||
[updateServer performSelector:@selector(getArguments)];
|
||||
*argc = [updaterArguments count];
|
||||
char** tempArgv = (char**)malloc(sizeof(char*) * (*argc));
|
||||
for (int i = 0; i < *argc; i++) {
|
||||
int argLen = [[updaterArguments objectAtIndex:i] length] + 1;
|
||||
tempArgv[i] = (char*)malloc(argLen);
|
||||
strncpy(tempArgv[i], [[updaterArguments objectAtIndex:i] UTF8String],
|
||||
argLen);
|
||||
}
|
||||
*argv = tempArgv;
|
||||
} @catch (NSException* e) {
|
||||
// Let's try our best and clean up.
|
||||
CleanupElevatedMacUpdate(true);
|
||||
return false; // Won't actually get here due to CleanupElevatedMacUpdate.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ElevatedUpdateServer is launched from a non-elevated updater process.
|
||||
* It allows an elevated updater process (usually a privileged helper tool) to
|
||||
* connect to it and receive all the necessary arguments to complete a
|
||||
* successful update.
|
||||
*/
|
||||
@interface ElevatedUpdateServer : NSObject
|
||||
{
|
||||
NSArray* mUpdaterArguments;
|
||||
BOOL mShouldKeepRunning;
|
||||
BOOL mAborted;
|
||||
}
|
||||
- (id)initWithArgs:(NSArray*)args;
|
||||
- (BOOL)runServer;
|
||||
- (NSArray*)getArguments;
|
||||
- (void)abort;
|
||||
- (BOOL)wasAborted;
|
||||
- (void)shutdown;
|
||||
- (BOOL)shouldKeepRunning;
|
||||
@end
|
||||
|
||||
@implementation ElevatedUpdateServer
|
||||
|
||||
- (id)initWithArgs:(NSArray*)args
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
mUpdaterArguments = args;
|
||||
mShouldKeepRunning = YES;
|
||||
mAborted = NO;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)runServer
|
||||
{
|
||||
NSPort* serverPort = [NSSocketPort port];
|
||||
NSConnection* server = [NSConnection connectionWithReceivePort:serverPort
|
||||
sendPort:serverPort];
|
||||
[server setRootObject:self];
|
||||
if ([server registerName:@"org.mozilla.updater.server"
|
||||
withNameServer:[NSSocketPortNameServer sharedInstance]] == NO) {
|
||||
NSLog(@"Unable to register as DirectoryServer.");
|
||||
NSLog(@"Is another copy running?");
|
||||
return NO;
|
||||
}
|
||||
|
||||
while ([self shouldKeepRunning] &&
|
||||
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
|
||||
beforeDate:[NSDate distantFuture]]);
|
||||
return ![self wasAborted];
|
||||
}
|
||||
|
||||
- (NSArray*)getArguments
|
||||
{
|
||||
return mUpdaterArguments;
|
||||
}
|
||||
|
||||
- (void)abort
|
||||
{
|
||||
mAborted = YES;
|
||||
[self shutdown];
|
||||
}
|
||||
|
||||
- (BOOL)wasAborted
|
||||
{
|
||||
return mAborted;
|
||||
}
|
||||
|
||||
- (void)shutdown
|
||||
{
|
||||
mShouldKeepRunning = NO;
|
||||
}
|
||||
|
||||
- (BOOL)shouldKeepRunning
|
||||
{
|
||||
return mShouldKeepRunning;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
bool ServeElevatedUpdate(int argc, const char** argv)
|
||||
{
|
||||
MacAutoreleasePool pool;
|
||||
|
||||
NSMutableArray* updaterArguments = [NSMutableArray arrayWithCapacity:argc];
|
||||
for (int i = 0; i < argc; i++) {
|
||||
[updaterArguments addObject:[NSString stringWithUTF8String:argv[i]]];
|
||||
}
|
||||
|
||||
ElevatedUpdateServer* updater =
|
||||
[[ElevatedUpdateServer alloc] initWithArgs:[updaterArguments copy]];
|
||||
bool didSucceed = [updater runServer];
|
||||
|
||||
[updater release];
|
||||
return didSucceed;
|
||||
}
|
||||
|
||||
bool IsOwnedByGroupAdmin(const char* aAppBundle)
|
||||
{
|
||||
MacAutoreleasePool pool;
|
||||
|
||||
NSString* appDir = [NSString stringWithUTF8String:aAppBundle];
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
|
||||
NSDictionary* attributes = [fileManager attributesOfItemAtPath:appDir
|
||||
error:nil];
|
||||
bool isOwnedByAdmin = false;
|
||||
if (attributes &&
|
||||
[[attributes valueForKey:NSFileGroupOwnerAccountID] intValue] == 80) {
|
||||
isOwnedByAdmin = true;
|
||||
}
|
||||
return isOwnedByAdmin;
|
||||
}
|
||||
|
||||
void SetGroupOwnershipAndPermissions(const char* aAppBundle)
|
||||
{
|
||||
MacAutoreleasePool pool;
|
||||
|
||||
NSString* appDir = [NSString stringWithUTF8String:aAppBundle];
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
NSError* error = nil;
|
||||
NSArray* paths =
|
||||
[fileManager subpathsOfDirectoryAtPath:appDir
|
||||
error:&error];
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set group ownership of Firefox.app to 80 ("admin") and permissions to
|
||||
// 0775.
|
||||
if (![fileManager setAttributes:@{ NSFileGroupOwnerAccountID: @(80),
|
||||
NSFilePosixPermissions: @(0775) }
|
||||
ofItemAtPath:appDir
|
||||
error:&error] || error) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray* permKeys = [NSArray arrayWithObjects:NSFileGroupOwnerAccountID,
|
||||
NSFilePosixPermissions,
|
||||
nil];
|
||||
// For all descendants of Firefox.app, set group ownership to 80 ("admin") and
|
||||
// ensure write permission for the group.
|
||||
for (NSString* currPath in paths) {
|
||||
NSString* child = [appDir stringByAppendingPathComponent:currPath];
|
||||
NSDictionary* oldAttributes =
|
||||
[fileManager attributesOfItemAtPath:child
|
||||
error:&error];
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
// Skip symlinks, since they could be pointing to files outside of the .app
|
||||
// bundle.
|
||||
if ([oldAttributes fileType] == NSFileTypeSymbolicLink) {
|
||||
continue;
|
||||
}
|
||||
NSNumber* oldPerms =
|
||||
(NSNumber*)[oldAttributes valueForKey:NSFilePosixPermissions];
|
||||
NSArray* permObjects =
|
||||
[NSArray arrayWithObjects:
|
||||
[NSNumber numberWithUnsignedLong:80],
|
||||
[NSNumber numberWithUnsignedLong:[oldPerms shortValue] | 020],
|
||||
nil];
|
||||
NSDictionary* attributes = [NSDictionary dictionaryWithObjects:permObjects
|
||||
forKeys:permKeys];
|
||||
if (![fileManager setAttributes:attributes
|
||||
ofItemAtPath:child
|
||||
error:&error] || error) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>org.mozilla.updater</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>updater.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.mozilla.updater</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.5</string>
|
||||
<key>LSMinimumSystemVersionByArchitecture</key>
|
||||
<dict>
|
||||
<key>i386</key>
|
||||
<string>10.5.0</string>
|
||||
<key>x86_64</key>
|
||||
<string>10.6.0</string>
|
||||
</dict>
|
||||
<key>SMAuthorizedClients</key>
|
||||
<array>
|
||||
<string>identifier "%MOZ_MACBUNDLE_ID%" and ((anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9]) or (anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] and certificate leaf[field.1.2.840.113635.100.6.1.13] and certificate leaf[subject.OU] = "43AQ936H96"))</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
1
toolkit/mozapps/update/updater/macbuild/Contents/PkgInfo
Normal file
1
toolkit/mozapps/update/updater/macbuild/Contents/PkgInfo
Normal file
|
|
@ -0,0 +1 @@
|
|||
APPL????
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
/* 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/. */
|
||||
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
CFBundleName = "%APP_NAME% Software Update";
|
||||
19
toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib
generated
Normal file
19
toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib
generated
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
IBClasses = (
|
||||
{
|
||||
CLASS = FirstResponder;
|
||||
LANGUAGE = ObjC;
|
||||
SUPERCLASS = NSObject;
|
||||
},
|
||||
{
|
||||
CLASS = UpdaterUI;
|
||||
LANGUAGE = ObjC;
|
||||
OUTLETS = {
|
||||
progressBar = NSProgressIndicator;
|
||||
progressTextField = NSTextField;
|
||||
};
|
||||
SUPERCLASS = NSObject;
|
||||
}
|
||||
);
|
||||
IBVersion = 1;
|
||||
}
|
||||
22
toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib
generated
Normal file
22
toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib
generated
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBDocumentLocation</key>
|
||||
<string>111 162 356 240 0 0 1440 878 </string>
|
||||
<key>IBEditorPositions</key>
|
||||
<dict>
|
||||
<key>29</key>
|
||||
<string>106 299 84 44 0 0 1440 878 </string>
|
||||
</dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>489.0</string>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>21</integer>
|
||||
<integer>29</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>10J567</string>
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
generated
Normal file
BIN
toolkit/mozapps/update/updater/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
generated
Normal file
Binary file not shown.
Binary file not shown.
|
|
@ -3,13 +3,26 @@
|
|||
# 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/.
|
||||
|
||||
Program('updater')
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
Program('org.mozilla.updater')
|
||||
else:
|
||||
Program('updater')
|
||||
|
||||
updater_rel_path = ''
|
||||
include('updater-common.build')
|
||||
|
||||
CXXFLAGS += CONFIG['MOZ_BZ2_CFLAGS']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
LDFLAGS += ['-sectcreate',
|
||||
'__TEXT',
|
||||
'__info_plist',
|
||||
TOPOBJDIR + '/dist/bin/Info.plist',
|
||||
'-sectcreate',
|
||||
'__TEXT',
|
||||
'__launchd_plist',
|
||||
SRCDIR + '/Launchd.plist']
|
||||
|
||||
GENERATED_FILES = [
|
||||
'primaryCert.h',
|
||||
'secondaryCert.h',
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ int InitProgressUI(int *argc, NS_tchar ***argv);
|
|||
// Called on the main thread at startup
|
||||
int ShowProgressUI(bool indeterminate = false, bool initUIStrings = true);
|
||||
int InitProgressUIStrings();
|
||||
#elif defined(XP_MACOSX)
|
||||
// Called on the main thread at startup
|
||||
int ShowProgressUI(bool indeterminate = false);
|
||||
#else
|
||||
// Called on the main thread at startup
|
||||
int ShowProgressUI();
|
||||
|
|
|
|||
144
toolkit/mozapps/update/updater/progressui_osx.mm
Normal file
144
toolkit/mozapps/update/updater/progressui_osx.mm
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/. */
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "progressui.h"
|
||||
#include "readstrings.h"
|
||||
#include "errors.h"
|
||||
|
||||
#define TIMER_INTERVAL 0.2
|
||||
|
||||
static float sProgressVal; // between 0 and 100
|
||||
static BOOL sQuit = NO;
|
||||
static BOOL sIndeterminate = NO;
|
||||
static StringTable sLabels;
|
||||
static const char *sUpdatePath;
|
||||
|
||||
@interface UpdaterUI : NSObject
|
||||
{
|
||||
IBOutlet NSProgressIndicator *progressBar;
|
||||
IBOutlet NSTextField *progressTextField;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation UpdaterUI
|
||||
|
||||
-(void)awakeFromNib
|
||||
{
|
||||
NSWindow *w = [progressBar window];
|
||||
|
||||
[w setTitle:[NSString stringWithUTF8String:sLabels.title]];
|
||||
[progressTextField setStringValue:[NSString stringWithUTF8String:sLabels.info]];
|
||||
|
||||
NSRect origTextFrame = [progressTextField frame];
|
||||
[progressTextField sizeToFit];
|
||||
|
||||
int widthAdjust = progressTextField.frame.size.width - origTextFrame.size.width;
|
||||
|
||||
if (widthAdjust > 0) {
|
||||
NSRect f;
|
||||
f.size.width = w.frame.size.width + widthAdjust;
|
||||
f.size.height = w.frame.size.height;
|
||||
[w setFrame:f display:YES];
|
||||
}
|
||||
|
||||
[w center];
|
||||
|
||||
[progressBar setIndeterminate:sIndeterminate];
|
||||
[progressBar setDoubleValue:0.0];
|
||||
|
||||
[[NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self
|
||||
selector:@selector(updateProgressUI:)
|
||||
userInfo:nil repeats:YES] retain];
|
||||
|
||||
// Make sure we are on top initially
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
// called when the timer goes off
|
||||
-(void)updateProgressUI:(NSTimer *)aTimer
|
||||
{
|
||||
if (sQuit) {
|
||||
[aTimer invalidate];
|
||||
[aTimer release];
|
||||
|
||||
// It seems to be necessary to activate and hide ourselves before we stop,
|
||||
// otherwise the "run" method will not return until the user focuses some
|
||||
// other app. The activate step is necessary if we are not the active app.
|
||||
// This is a big hack, but it seems to do the trick.
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
[NSApp hide:self];
|
||||
[NSApp stop:self];
|
||||
}
|
||||
|
||||
float progress = sProgressVal;
|
||||
|
||||
[progressBar setDoubleValue:(double)progress];
|
||||
}
|
||||
|
||||
// leave this as returning a BOOL instead of NSApplicationTerminateReply
|
||||
// for backward compatibility
|
||||
- (BOOL)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
return sQuit;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
int
|
||||
InitProgressUI(int *pargc, char ***pargv)
|
||||
{
|
||||
sUpdatePath = (*pargv)[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ShowProgressUI(bool indeterminate)
|
||||
{
|
||||
// Only show the Progress UI if the process is taking a significant amount of
|
||||
// time where a significant amount of time is defined as .5 seconds after
|
||||
// ShowProgressUI is called sProgress is less than 70.
|
||||
usleep(500000);
|
||||
|
||||
if (sQuit || sProgressVal > 70.0f)
|
||||
return 0;
|
||||
|
||||
char path[PATH_MAX];
|
||||
SprintfLiteral(path, "%s/updater.ini", sUpdatePath);
|
||||
if (ReadStrings(path, &sLabels) != OK)
|
||||
return -1;
|
||||
|
||||
// Continue the update without showing the Progress UI if any of the supplied
|
||||
// strings are larger than MAX_TEXT_LEN (Bug 628829).
|
||||
if (!(strlen(sLabels.title) < MAX_TEXT_LEN - 1 &&
|
||||
strlen(sLabels.info) < MAX_TEXT_LEN - 1))
|
||||
return -1;
|
||||
|
||||
sIndeterminate = indeterminate;
|
||||
[NSApplication sharedApplication];
|
||||
[NSBundle loadNibNamed:@"MainMenu" owner:NSApp];
|
||||
[NSApp run];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Called on a background thread
|
||||
void
|
||||
QuitProgressUI()
|
||||
{
|
||||
sQuit = YES;
|
||||
}
|
||||
|
||||
// Called on a background thread
|
||||
void
|
||||
UpdateProgressUI(float progress)
|
||||
{
|
||||
sProgressVal = progress; // 32-bit writes are atomic
|
||||
}
|
||||
|
|
@ -73,6 +73,24 @@ if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
|||
'progressui_gtk.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
have_progressui = 1
|
||||
srcs += [
|
||||
'launchchild_osx.mm',
|
||||
'progressui_osx.mm',
|
||||
]
|
||||
OS_LIBS += [
|
||||
'-framework Cocoa',
|
||||
'-framework Security',
|
||||
'-framework SystemConfiguration',
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
'/toolkit/xre/updaterfileutils_osx.mm',
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
'/toolkit/xre',
|
||||
]
|
||||
|
||||
if have_progressui == 0:
|
||||
srcs += [
|
||||
'progressui_null.cpp',
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "updatecommon.h"
|
||||
#ifdef XP_MACOSX
|
||||
#include "updaterfileutils_osx.h"
|
||||
#endif // XP_MACOSX
|
||||
|
||||
#include "mozilla/Compiler.h"
|
||||
#include "mozilla/Types.h"
|
||||
|
|
@ -72,6 +75,23 @@
|
|||
#define PARENT_WAIT 10000
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
// These functions are defined in launchchild_osx.mm
|
||||
void CleanupElevatedMacUpdate(bool aFailureOccurred);
|
||||
bool IsOwnedByGroupAdmin(const char* aAppBundle);
|
||||
bool IsRecursivelyWritable(const char* aPath);
|
||||
void LaunchChild(int argc, const char** argv);
|
||||
void LaunchMacPostProcess(const char* aAppBundle);
|
||||
bool ObtainUpdaterArguments(int* argc, char*** argv);
|
||||
bool ServeElevatedUpdate(int argc, const char** argv);
|
||||
void SetGroupOwnershipAndPermissions(const char* aAppBundle);
|
||||
struct UpdateServerThreadArgs
|
||||
{
|
||||
int argc;
|
||||
const NS_tchar** argv;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef _O_BINARY
|
||||
# define _O_BINARY 0
|
||||
#endif
|
||||
|
|
@ -86,13 +106,14 @@
|
|||
|
||||
// We want to use execv to invoke the callback executable on platforms where
|
||||
// we were launched using execv. See nsUpdateDriver.cpp.
|
||||
#if defined(XP_UNIX)
|
||||
#if defined(XP_UNIX) && !defined(XP_MACOSX)
|
||||
#define USE_EXECV
|
||||
#endif
|
||||
|
||||
# define MAYBE_USE_HARD_LINKS 0
|
||||
|
||||
#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN)
|
||||
#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \
|
||||
!defined(XP_MACOSX)
|
||||
#include "nss.h"
|
||||
#include "prerror.h"
|
||||
#endif
|
||||
|
|
@ -1675,6 +1696,21 @@ PatchFile::Execute()
|
|||
|
||||
AutoFile ofile(ensure_open(mFile.get(), shouldTruncate ? NS_T("wb+") : NS_T("rb+"),
|
||||
ss.st_mode));
|
||||
#elif defined(XP_MACOSX)
|
||||
AutoFile ofile(ensure_open(mFile.get(), NS_T("wb+"), ss.st_mode));
|
||||
// Modified code from FileUtils.cpp
|
||||
fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, header.dlen};
|
||||
// Try to get a continous chunk of disk space
|
||||
rv = fcntl(fileno((FILE *)ofile), F_PREALLOCATE, &store);
|
||||
if (rv == -1) {
|
||||
// OK, perhaps we are too fragmented, allocate non-continuous
|
||||
store.fst_flags = F_ALLOCATEALL;
|
||||
rv = fcntl(fileno((FILE *)ofile), F_PREALLOCATE, &store);
|
||||
}
|
||||
|
||||
if (rv != -1) {
|
||||
ftruncate(fileno((FILE *)ofile), header.dlen);
|
||||
}
|
||||
#else
|
||||
AutoFile ofile(ensure_open(mFile.get(), NS_T("wb+"), ss.st_mode));
|
||||
#endif
|
||||
|
|
@ -2055,6 +2091,8 @@ LaunchCallbackApp(const NS_tchar *workingDir,
|
|||
|
||||
#if defined(USE_EXECV)
|
||||
execv(argv[0], argv);
|
||||
#elif defined(XP_MACOSX)
|
||||
LaunchChild(argc, (const char**)argv);
|
||||
#elif defined(XP_WIN)
|
||||
WinLaunchChild(argv[0], argc, argv, nullptr);
|
||||
#else
|
||||
|
|
@ -2170,14 +2208,18 @@ CopyInstallDirToDestDir()
|
|||
// These files should not be copied over to the updated app
|
||||
#ifdef XP_WIN
|
||||
#define SKIPLIST_COUNT 3
|
||||
#elif XP_MACOSX
|
||||
#define SKIPLIST_COUNT 0
|
||||
#else
|
||||
#define SKIPLIST_COUNT 2
|
||||
#endif
|
||||
copy_recursive_skiplist<SKIPLIST_COUNT> skiplist;
|
||||
#ifndef XP_MACOSX
|
||||
skiplist.append(0, gInstallDirPath, NS_T("updated"));
|
||||
skiplist.append(1, gInstallDirPath, NS_T("updates/0"));
|
||||
#ifdef XP_WIN
|
||||
skiplist.append(2, gInstallDirPath, NS_T("updated.update_in_progress.lock"));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return ensure_copy_recursive(gInstallDirPath, gWorkingDirPath, skiplist);
|
||||
|
|
@ -2197,7 +2239,11 @@ ProcessReplaceRequest()
|
|||
// 2. Move newDir to destDir. In case of failure, revert step 1 and abort.
|
||||
// 3. Delete tmpDir (or defer it to the next reboot).
|
||||
|
||||
#ifdef XP_WIN
|
||||
#ifdef XP_MACOSX
|
||||
NS_tchar destDir[MAXPATHLEN];
|
||||
NS_tsnprintf(destDir, sizeof(destDir)/sizeof(destDir[0]),
|
||||
NS_T("%s/Contents"), gInstallDirPath);
|
||||
#elif XP_WIN
|
||||
// Windows preserves the case of the file/directory names. We use the
|
||||
// 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
|
||||
|
|
@ -2217,8 +2263,13 @@ ProcessReplaceRequest()
|
|||
|
||||
NS_tchar newDir[MAXPATHLEN];
|
||||
NS_tsnprintf(newDir, sizeof(newDir)/sizeof(newDir[0]),
|
||||
#ifdef XP_MACOSX
|
||||
NS_T("%s/Contents"),
|
||||
gWorkingDirPath);
|
||||
#else
|
||||
NS_T("%s.bak/updated"),
|
||||
gInstallDirPath);
|
||||
#endif
|
||||
|
||||
// First try to remove the possibly existing temp directory, because if this
|
||||
// directory exists, we will fail to rename destDir.
|
||||
|
|
@ -2256,6 +2307,14 @@ ProcessReplaceRequest()
|
|||
LOG(("Begin moving newDir (" LOG_S ") to destDir (" LOG_S ")",
|
||||
newDir, destDir));
|
||||
rv = rename_file(newDir, destDir, true);
|
||||
#ifdef XP_MACOSX
|
||||
if (rv) {
|
||||
LOG(("Moving failed. Begin copying newDir (" LOG_S ") to destDir (" LOG_S ")",
|
||||
newDir, destDir));
|
||||
copy_recursive_skiplist<0> skiplist;
|
||||
rv = ensure_copy_recursive(newDir, destDir, skiplist);
|
||||
}
|
||||
#endif
|
||||
if (rv) {
|
||||
LOG(("Moving newDir to destDir failed, err: %d", rv));
|
||||
LOG(("Now, try to move tmpDir back to destDir"));
|
||||
|
|
@ -2269,7 +2328,7 @@ ProcessReplaceRequest()
|
|||
return rv;
|
||||
}
|
||||
|
||||
#if !defined(XP_WIN)
|
||||
#if !defined(XP_WIN) && !defined(XP_MACOSX)
|
||||
// Platforms that have their updates directory in the installation directory
|
||||
// need to have the last-update.log and backup-update.log files moved from the
|
||||
// old installation directory to the new installation directory.
|
||||
|
|
@ -2303,6 +2362,15 @@ ProcessReplaceRequest()
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// On OS X, we we need to remove the staging directory after its Contents
|
||||
// directory has been moved.
|
||||
NS_tchar updatedAppDir[MAXPATHLEN];
|
||||
NS_tsnprintf(updatedAppDir, sizeof(updatedAppDir)/sizeof(updatedAppDir[0]),
|
||||
NS_T("%s/Updated.app"), gPatchDirPath);
|
||||
ensure_remove_recursive(updatedAppDir);
|
||||
#endif
|
||||
|
||||
gSucceeded = true;
|
||||
|
||||
return 0;
|
||||
|
|
@ -2412,7 +2480,11 @@ UpdateThreadFunc(void *param)
|
|||
NS_tchar updateSettingsPath[MAX_TEXT_LEN];
|
||||
NS_tsnprintf(updateSettingsPath,
|
||||
sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]),
|
||||
#ifdef XP_MACOSX
|
||||
NS_T("%s/Contents/Resources/update-settings.ini"),
|
||||
#else
|
||||
NS_T("%s/update-settings.ini"),
|
||||
#endif
|
||||
gWorkingDirPath);
|
||||
MARChannelStringTable MARStrings;
|
||||
if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) {
|
||||
|
|
@ -2484,6 +2556,15 @@ UpdateThreadFunc(void *param)
|
|||
if (rv) {
|
||||
LOG(("failed: %d", rv));
|
||||
} else {
|
||||
#ifdef XP_MACOSX
|
||||
// If the update was successful we need to update the timestamp on the
|
||||
// top-level Mac OS X bundle directory so that Mac OS X's Launch Services
|
||||
// picks up any major changes when the bundle is updated.
|
||||
if (!sStagedUpdate && utimes(gInstallDirPath, nullptr) != 0) {
|
||||
LOG(("Couldn't set access/modification time on application bundle."));
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG(("succeeded"));
|
||||
}
|
||||
WriteStatusFile(rv);
|
||||
|
|
@ -2493,11 +2574,34 @@ UpdateThreadFunc(void *param)
|
|||
QuitProgressUI();
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
static void
|
||||
ServeElevatedUpdateThreadFunc(void* param)
|
||||
{
|
||||
UpdateServerThreadArgs* threadArgs = (UpdateServerThreadArgs*)param;
|
||||
gSucceeded = ServeElevatedUpdate(threadArgs->argc, threadArgs->argv);
|
||||
if (!gSucceeded) {
|
||||
WriteStatusFile(ELEVATION_CANCELED);
|
||||
}
|
||||
QuitProgressUI();
|
||||
}
|
||||
|
||||
void freeArguments(int argc, char** argv)
|
||||
{
|
||||
for (int i = 0; i < argc; i++) {
|
||||
free(argv[i]);
|
||||
}
|
||||
free(argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
int LaunchCallbackAndPostProcessApps(int argc, NS_tchar** argv,
|
||||
int callbackIndex
|
||||
#ifdef XP_WIN
|
||||
, const WCHAR* elevatedLockFilePath
|
||||
, HANDLE updateLockFileHandle
|
||||
#elif XP_MACOSX
|
||||
, bool isElevated
|
||||
#endif
|
||||
)
|
||||
{
|
||||
|
|
@ -2509,11 +2613,19 @@ int LaunchCallbackAndPostProcessApps(int argc, NS_tchar** argv,
|
|||
}
|
||||
}
|
||||
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0);
|
||||
#elif XP_MACOSX
|
||||
if (!isElevated) {
|
||||
if (gSucceeded) {
|
||||
LaunchMacPostProcess(gInstallDirPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
LaunchCallbackApp(argv[5],
|
||||
argc - callbackIndex,
|
||||
argv + callbackIndex);
|
||||
#ifdef XP_MACOSX
|
||||
} // if (!isElevated)
|
||||
#endif /* XP_MACOSX */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2525,7 +2637,20 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
// argument prior to callbackIndex is the working directory.
|
||||
const int callbackIndex = 6;
|
||||
|
||||
#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN)
|
||||
#ifdef XP_MACOSX
|
||||
bool isElevated =
|
||||
strstr(argv[0], "/Library/PrivilegedHelperTools/org.mozilla.updater") != 0;
|
||||
if (isElevated) {
|
||||
if (!ObtainUpdaterArguments(&argc, &argv)) {
|
||||
// Won't actually get here because ObtainUpdaterArguments will terminate
|
||||
// the current process on failure.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
|
@ -2538,7 +2663,13 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
}
|
||||
#endif
|
||||
|
||||
InitProgressUI(&argc, &argv);
|
||||
#ifdef XP_MACOSX
|
||||
if (!isElevated) {
|
||||
#endif
|
||||
InitProgressUI(&argc, &argv);
|
||||
#ifdef XP_MACOSX
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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
|
||||
|
|
@ -2556,6 +2687,12 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
// launched.
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "Usage: updater patch-dir install-dir apply-to-dir [wait-pid [callback-working-dir callback-path args...]]\n");
|
||||
#ifdef XP_MACOSX
|
||||
if (isElevated) {
|
||||
freeArguments(argc, argv);
|
||||
CleanupElevatedMacUpdate(true);
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2564,6 +2701,12 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
// directory is invalid don't write the status file.
|
||||
fprintf(stderr, "The patch directory path is not valid for this " \
|
||||
"application (" LOG_S ")\n", argv[1]);
|
||||
#ifdef XP_MACOSX
|
||||
if (isElevated) {
|
||||
freeArguments(argc, argv);
|
||||
CleanupElevatedMacUpdate(true);
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
// The directory containing the update information.
|
||||
|
|
@ -2573,6 +2716,12 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
WriteStatusFile(INVALID_INSTALL_DIR_PATH_ERROR);
|
||||
fprintf(stderr, "The install directory path is not valid for this " \
|
||||
"application (" LOG_S ")\n", argv[2]);
|
||||
#ifdef XP_MACOSX
|
||||
if (isElevated) {
|
||||
freeArguments(argc, argv);
|
||||
CleanupElevatedMacUpdate(true);
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
// The directory we're going to update to.
|
||||
|
|
@ -2635,6 +2784,12 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
WriteStatusFile(INVALID_WORKING_DIR_PATH_ERROR);
|
||||
fprintf(stderr, "The working directory path is not valid for this " \
|
||||
"application (" LOG_S ")\n", argv[3]);
|
||||
#ifdef XP_MACOSX
|
||||
if (isElevated) {
|
||||
freeArguments(argc, argv);
|
||||
CleanupElevatedMacUpdate(true);
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
// The directory we're going to update to.
|
||||
|
|
@ -2653,6 +2808,12 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
WriteStatusFile(INVALID_CALLBACK_PATH_ERROR);
|
||||
fprintf(stderr, "The callback file path is not valid for this " \
|
||||
"application (" LOG_S ")\n", argv[callbackIndex]);
|
||||
#ifdef XP_MACOSX
|
||||
if (isElevated) {
|
||||
freeArguments(argc, argv);
|
||||
CleanupElevatedMacUpdate(true);
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2663,10 +2824,37 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
WriteStatusFile(INVALID_CALLBACK_DIR_ERROR);
|
||||
fprintf(stderr, "The callback file must be located in the " \
|
||||
"installation directory (" LOG_S ")\n", argv[callbackIndex]);
|
||||
#ifdef XP_MACOSX
|
||||
if (isElevated) {
|
||||
freeArguments(argc, argv);
|
||||
CleanupElevatedMacUpdate(true);
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (!isElevated && !IsRecursivelyWritable(argv[2])) {
|
||||
// If the app directory isn't recursively writeable, an elevated update is
|
||||
// required.
|
||||
UpdateServerThreadArgs threadArgs;
|
||||
threadArgs.argc = argc;
|
||||
threadArgs.argv = const_cast<const NS_tchar**>(argv);
|
||||
|
||||
Thread t1;
|
||||
if (t1.Run(ServeElevatedUpdateThreadFunc, &threadArgs) == 0) {
|
||||
// Show an indeterminate progress bar while an elevated update is in
|
||||
// progress.
|
||||
ShowProgressUI(true);
|
||||
}
|
||||
t1.Join();
|
||||
|
||||
LaunchCallbackAndPostProcessApps(argc, argv, callbackIndex, false);
|
||||
return gSucceeded ? 0 : 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (EnvHasValue("MOZ_OS_UPDATE")) {
|
||||
sIsOSUpdate = true;
|
||||
putenv(const_cast<char*>("MOZ_OS_UPDATE="));
|
||||
|
|
@ -2676,6 +2864,12 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
|
||||
if (!WriteStatusFile("applying")) {
|
||||
LOG(("failed setting status to 'applying'"));
|
||||
#ifdef XP_MACOSX
|
||||
if (isElevated) {
|
||||
freeArguments(argc, argv);
|
||||
CleanupElevatedMacUpdate(true);
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2912,6 +3106,12 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
// Try to create the destination directory if it doesn't exist
|
||||
int rv = NS_tmkdir(gWorkingDirPath, 0755);
|
||||
if (rv != OK && errno != EEXIST) {
|
||||
#ifdef XP_MACOSX
|
||||
if (isElevated) {
|
||||
freeArguments(argc, argv);
|
||||
CleanupElevatedMacUpdate(true);
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -3152,7 +3352,11 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
// is an elevated process on OSX.
|
||||
Thread t;
|
||||
if (t.Run(UpdateThreadFunc, nullptr) == 0) {
|
||||
if (!sStagedUpdate && !sReplaceRequest) {
|
||||
if (!sStagedUpdate && !sReplaceRequest
|
||||
#ifdef XP_MACOSX
|
||||
&& !isElevated
|
||||
#endif
|
||||
) {
|
||||
ShowProgressUI();
|
||||
}
|
||||
}
|
||||
|
|
@ -3189,12 +3393,66 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
}
|
||||
#endif /* XP_WIN */
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// When the update is successful remove the precomplete file in the root of
|
||||
// the application bundle and move the distribution directory from
|
||||
// Contents/MacOS to Contents/Resources and if both exist delete the
|
||||
// directory under Contents/MacOS (see Bug 1068439).
|
||||
if (gSucceeded && !sStagedUpdate) {
|
||||
NS_tchar oldPrecomplete[MAXPATHLEN];
|
||||
NS_tsnprintf(oldPrecomplete, sizeof(oldPrecomplete)/sizeof(oldPrecomplete[0]),
|
||||
NS_T("%s/precomplete"), gInstallDirPath);
|
||||
NS_tremove(oldPrecomplete);
|
||||
|
||||
NS_tchar oldDistDir[MAXPATHLEN];
|
||||
NS_tsnprintf(oldDistDir, sizeof(oldDistDir)/sizeof(oldDistDir[0]),
|
||||
NS_T("%s/Contents/MacOS/distribution"), gInstallDirPath);
|
||||
int rv = NS_taccess(oldDistDir, F_OK);
|
||||
if (!rv) {
|
||||
NS_tchar newDistDir[MAXPATHLEN];
|
||||
NS_tsnprintf(newDistDir, sizeof(newDistDir)/sizeof(newDistDir[0]),
|
||||
NS_T("%s/Contents/Resources/distribution"), gInstallDirPath);
|
||||
rv = NS_taccess(newDistDir, F_OK);
|
||||
if (!rv) {
|
||||
LOG(("New distribution directory already exists... removing old " \
|
||||
"distribution directory: " LOG_S, oldDistDir));
|
||||
rv = ensure_remove_recursive(oldDistDir);
|
||||
if (rv) {
|
||||
LOG(("Removing old distribution directory failed - err: %d", rv));
|
||||
}
|
||||
} else {
|
||||
LOG(("Moving old distribution directory to new location. src: " LOG_S \
|
||||
", dst:" LOG_S, oldDistDir, newDistDir));
|
||||
rv = rename_file(oldDistDir, newDistDir, true);
|
||||
if (rv) {
|
||||
LOG(("Moving old distribution directory to new location failed - " \
|
||||
"err: %d", rv));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isElevated) {
|
||||
SetGroupOwnershipAndPermissions(gInstallDirPath);
|
||||
freeArguments(argc, argv);
|
||||
CleanupElevatedMacUpdate(false);
|
||||
} else if (IsOwnedByGroupAdmin(gInstallDirPath)) {
|
||||
// If the group ownership of the Firefox .app bundle was set to the "admin"
|
||||
// group during a previous elevated update, we need to ensure that all files
|
||||
// in the bundle have group ownership of "admin" as well as write permission
|
||||
// for the group to not break updates in the future.
|
||||
SetGroupOwnershipAndPermissions(gInstallDirPath);
|
||||
}
|
||||
#endif /* XP_MACOSX */
|
||||
|
||||
LogFinish();
|
||||
|
||||
int retVal = LaunchCallbackAndPostProcessApps(argc, argv, callbackIndex
|
||||
#ifdef XP_WIN
|
||||
, elevatedLockFilePath
|
||||
, updateLockFileHandle
|
||||
#elif XP_MACOSX
|
||||
, isElevated
|
||||
#endif
|
||||
);
|
||||
|
||||
|
|
@ -3650,8 +3908,13 @@ int AddPreCompleteActions(ActionList *list)
|
|||
return OK;
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
mozilla::UniquePtr<NS_tchar[]> manifestPath(get_full_path(
|
||||
NS_T("Contents/Resources/precomplete")));
|
||||
#else
|
||||
mozilla::UniquePtr<NS_tchar[]> manifestPath(get_full_path(
|
||||
NS_T("precomplete")));
|
||||
#endif
|
||||
|
||||
NS_tchar *rb = GetManifestContents(manifestPath.get());
|
||||
if (rb == nullptr) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue