diff --git a/.hgtags b/.hgtags
index 57895358e6..1413f35640 100755
--- a/.hgtags
+++ b/.hgtags
@@ -248,39 +248,43 @@ bb9932a7a5fd00edf52d95f354e3b37ae6a942db DRTVWR-156
6414ecdabc5d89515b08d1f872cf923ed3a5523a DRTVWR-148
2a3965b3ad202df7ea25d2be689291bb14a1280e DRTVWR-155
24a7281bef42bd4430ceb25db8b195449c2c7de3 DRTVWR-153
-a716684aa7c07c440b1de5815b8a1f3dd3fd8bfb DRTVWR-159
-9a78ac13f047056f788c4734dd91aebfe30970e3 DRTVWR-157
5910f8063a7e1ddddf504c2f35ca831cc5e8f469 DRTVWR-160
f0a174c2adb4bc39b16722a61d7eeb4f2a1d4843 3.3.3-beta1
f0a174c2adb4bc39b16722a61d7eeb4f2a1d4843 DRTVWR-144
-089e5c84b2dece68f2b016c842ef9b5de4786842 DRTVWR-161
-600f3b3920d94de805ac6dc8bb6def9c069dd360 DRTVWR-162
-c08e2ac17a99973b2a94477659220b99b8847ae2 DRTVWR-163
2d6c0634b11e6f3df11002b8510a72a0433da00a DRTVWR-164
+600f3b3920d94de805ac6dc8bb6def9c069dd360 DRTVWR-162
80b5e5e9775966d3839331ffa7a16a60f9d7c930 DRTVWR-165
fdcc08a4f20ae9bb060f4693c8980d216534efdf 3.3.3-beta2
af5f3e43e6e4424b1da19d9e16f6b853a7b822ed DRTVWR-169
4b3c68199a86cabaa5d9466d7b0f7e141e901d7a 3.3.3-beta3
6428242e124b523813bfaf4c45b3d422f0298c81 3.3.3-release
+a716684aa7c07c440b1de5815b8a1f3dd3fd8bfb DRTVWR-159
+9a78ac13f047056f788c4734dd91aebfe30970e3 DRTVWR-157
+089e5c84b2dece68f2b016c842ef9b5de4786842 DRTVWR-161
+c08e2ac17a99973b2a94477659220b99b8847ae2 DRTVWR-163
b9d0170b62eb1c7c3adaa37a0b13a833e5e659f9 DRTVWR-171
050e48759337249130f684b4a21080b683f61732 DRTVWR-168
09ef7fd1b0781f33b8a3a9af6236b7bcb4831910 DRTVWR-170
f87bfbe0b62d26f451d02a47c80ebef6b9168fc2 DRTVWR-158
f91d003091a61937a044652c4c674447f7dcbb7a 3.3.4-beta1
-005dfe5c4c377207d065fb27858d2eb0b53b143a DRTVWR-167
bce218b2b45b730b22cc51e4807aa8b571cadef3 DRTVWR-173
cbea6356ce9cb0c313b6777f10c5c14783264fcc DRTVWR-174
82b5330bc8b17d0d4b598832e9c5a92e90075682 3.3.4-beta2
57d221de3df94f90b55204313c2cef044a3c0ae2 DRTVWR-176
eb539c65e6ee26eea2bf373af2d0f4b52dc91289 DRTVWR-177
a8057e1b9a1246b434a27405be35e030f7d28b0c 3.3.4-beta3
-888768f162d2c0a8de1dcc5fb9a08bd8bd120a6b DRTVWR-175
4281aa899fb2cedb7a9ca7ce91c5c29d4aa69594 DRTVWR-180
5c08e1d8edd871807153603b690e3ee9dbb548aa DRTVWR-183
6c75f220b103db1420919c8b635fe53e2177f318 3.3.4-beta4
9cd174d3a54d93d409a7c346a15b8bfb40fc58f4 DRTVWR-184
ab2ffc547c8a8950ff187c4f6c95e5334fab597b 3.3.4-beta5
28e100d0379a2b0710c57647a28fc5239d3d7b99 3.3.4-release
+6dfb0fba782c9233dd95f24ec48146db0d3f210b DRTVWR-199
+7c9102fb998885621919f2474a002c35b583539b 3.3.4-release2
+8c9085066c78ed5f6c9379dc054c82a6fcdb1851 DRTVWR-207
+351eea5f9dc192fc5ddea3b02958de97677a0a12 3.3.4-release3
+005dfe5c4c377207d065fb27858d2eb0b53b143a DRTVWR-167
+888768f162d2c0a8de1dcc5fb9a08bd8bd120a6b DRTVWR-175
a8b3eca451a9eaab59987efb0ab1c4217e3f2dcc DRTVWR-182
1f27cdfdc54246484f8afbbe42ce48e954175cbd 3.4.0-beta1
81f6b745ef27f5915fd07f988fdec9944f2bb73e DRTVWR-186
@@ -300,8 +304,6 @@ b1dbb1a83f48f93f6f878cff9e52d2cb635e145c 3.4.0-beta2
37402e2b19af970d51b0a814d79892cc5647532b DRTVWR-200
182a9bf30e81070361bb020a78003b1cf398e79c 3.4.0-beta3
248f4acd92a706c79e842bc83d80baa7369c0c2e DRTVWR-203
-6dfb0fba782c9233dd95f24ec48146db0d3f210b DRTVWR-199
-7c9102fb998885621919f2474a002c35b583539b 3.3.4-release2
7649a3dff5ec22d3727377e5f02efd0f421e4cb5 DRTVWR-201
84fb70dfe3444e75a44fb4bee43e2fc8221cebdd 3.4.0-beta4
de3be913f68813a9bac7d1c671fef96d1159bcd6 DRTVWR-202
@@ -309,8 +311,6 @@ de3be913f68813a9bac7d1c671fef96d1159bcd6 DRTVWR-202
34dbbe2b00afe90352d3acf8290eb10ab90d1c8b oz-build-test-tag
6ee71714935ffcd159db3d4f5800c1929aac54e1 DRTVWR-205
7b22c612fc756e0ea63b10b163e81d107f85dbf8 DRTVWR-206
-8c9085066c78ed5f6c9379dc054c82a6fcdb1851 DRTVWR-207
-351eea5f9dc192fc5ddea3b02958de97677a0a12 3.3.4-release3
af7b28e75bd5a629cd9e0dc46fb3f1757626f493 DRTVWR-212
015012c2b740ccdec8a8c3d6e5f898449ecfe0b8 DRTVWR-213
62b07aa81b1957897c3846292bb9412977b0af6c 3.3.4-beta6
@@ -386,3 +386,8 @@ daca610d840625b5bebb966a57cb49581852c417 DRTVWR-265
84fbaf2d4141bd161731430e760949dc787ca206 DRTVWR-244
083d2d36b5bb1c54fc3dd7caac0e7ac381a9cef0 3.4.4-beta1
391a8c74cec7275c5d26c85ad108d4782a3e3dd9 DRTVWR-268
+b634dec987c16e8c9c938e11e52591d9ead8fa9b DRTVWR-270
+cd39255bd23330fd30c04105f2811e941d8524fe 3.4.4-beta2
+2c4011bbc2b15b82198fd8b51f3a9fe765a08c4d DRTVWR-271
+2f8a3ef687bc55828abcb17ac1ad7cde70536d7e 3.4.4-beta3
+35cfd4cf5b895fa776592f2e630e330be7f0604e DRTVWR-273
diff --git a/autobuild.xml b/autobuild.xml
index fb0de9feb2..017427278e 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -186,9 +186,9 @@
archive
name
darwin
@@ -198,9 +198,9 @@
archive
name
linux
@@ -210,9 +210,9 @@
archive
name
windows
@@ -918,9 +918,9 @@
archive
name
darwin
@@ -930,9 +930,9 @@
archive
name
linux
@@ -942,9 +942,9 @@
archive
name
windows
diff --git a/indra/mac_updater/AutoUpdater.nib b/indra/mac_updater/AutoUpdater.nib
deleted file mode 100644
index 03883e2b86..0000000000
Binary files a/indra/mac_updater/AutoUpdater.nib and /dev/null differ
diff --git a/indra/mac_updater/AutoUpdater.nib/classes.nib b/indra/mac_updater/AutoUpdater.nib/classes.nib
new file mode 100644
index 0000000000..ea58db1189
--- /dev/null
+++ b/indra/mac_updater/AutoUpdater.nib/classes.nib
@@ -0,0 +1,4 @@
+{
+IBClasses = ();
+IBVersion = 1;
+}
diff --git a/indra/mac_updater/AutoUpdater.nib/info.nib b/indra/mac_updater/AutoUpdater.nib/info.nib
new file mode 100644
index 0000000000..a49a92385b
--- /dev/null
+++ b/indra/mac_updater/AutoUpdater.nib/info.nib
@@ -0,0 +1,14 @@
+
+
+
+
+ IBDocumentLocation
+ 103 138 356 240 0 0 1280 1002
+ IBFramework Version
+ 362.0
+ IBSystem Version
+ 7D24
+ targetFramework
+ IBCarbonFramework
+
+
diff --git a/indra/mac_updater/AutoUpdater.nib/objects.xib b/indra/mac_updater/AutoUpdater.nib/objects.xib
new file mode 100644
index 0000000000..310411b711
--- /dev/null
+++ b/indra/mac_updater/AutoUpdater.nib/objects.xib
@@ -0,0 +1,56 @@
+
+
diff --git a/indra/mac_updater/AutoUpdater.xib b/indra/mac_updater/AutoUpdater.xib
deleted file mode 100644
index b29fffba3a..0000000000
--- a/indra/mac_updater/AutoUpdater.xib
+++ /dev/null
@@ -1,520 +0,0 @@
-
-
-
- 1070
- 11G63
- 2182
- 1138.51
- 569.00
-
- com.apple.InterfaceBuilder.CocoaPlugin
- 2182
-
-
- NSTextField
- NSView
- NSWindowTemplate
- NSProgressIndicator
- NSCustomObject
- IBNSLayoutConstraint
- NSButtonCell
- NSButton
- NSUserDefaultsController
- NSTextFieldCell
-
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
-
- PluginDependencyRecalculationVersion
-
-
-
-
- NSObject
-
-
- FirstResponder
-
-
- NSApplication
-
-
- 15
- 2
- {{196, 240}, {402, 120}}
- 544735232
- Window
- NSWindow
-
-
-
-
- 256
-
-
-
- 268
- {{17, 83}, {79, 17}}
-
-
-
- _NS:1505
- YES
-
- 68288064
- 272630784
- Initalizing...
-
- LucidaGrande
- 13
- 1044
-
- _NS:1505
-
-
- 6
- System
- controlColor
-
- 3
- MC42NjY2NjY2NjY3AA
-
-
-
- 6
- System
- controlTextColor
-
- 3
- MAA
-
-
-
-
-
-
- 268
- {{18, 55}, {366, 20}}
-
-
-
- _NS:9
- {250, 250}
- 16399
- 100
-
-
-
- 268
- {{308, 19}, {74, 19}}
-
-
-
- _NS:9
- YES
-
- -2080244224
- 134217728
- Cancel
-
- LucidaGrande
- 12
- 16
-
- _NS:9
-
- -2038152961
- 164
-
-
- 400
- 75
-
-
-
- {402, 120}
-
-
-
-
- {{0, 0}, {1680, 1028}}
- {10000000000000, 10000000000000}
- YES
-
-
- MacUpdaterAppDelegate
-
-
- YES
-
-
-
-
-
-
- title: values
-
-
-
-
-
- title: values
- title
- values
- 2
-
-
- 41
-
-
-
-
-
- 0
-
-
-
-
-
- -2
-
-
- File's Owner
-
-
- -1
-
-
- First Responder
-
-
- -3
-
-
- Application
-
-
- 1
-
-
-
-
-
-
-
- 2
-
-
-
-
-
-
- 5
- 0
-
- 5
- 1
-
- 20
-
- 1000
- 8
- 29
- 3
-
-
-
-
- 5
- 0
-
- 5
- 1
-
- 20
-
- 1000
- 8
- 29
- 3
-
-
-
-
- 6
- 0
-
- 6
- 1
-
- 20
-
- 1000
- 8
- 29
- 3
-
-
-
-
-
- 6
- 0
-
- 6
- 1
-
- 20
-
- 1000
- 8
- 29
- 3
-
-
-
-
- 3
- 0
-
- 3
- 1
-
- 20
-
- 1000
- 8
- 29
- 3
-
-
-
-
- 3
- 0
-
- 4
- 1
-
- 8
-
- 1000
- 6
- 24
- 3
-
-
-
-
- 4
- 0
-
- 4
- 1
-
- 20
-
- 1000
- 8
- 29
- 3
-
-
-
-
-
-
- 3
-
-
-
-
-
-
-
- 4
-
-
-
-
- 8
-
-
-
-
-
- 20
-
-
-
-
- 22
-
-
-
-
-
- 7
- 0
-
- 0
- 1
-
- 74
-
- 1000
- 3
- 9
- 1
-
-
-
-
-
-
- 23
-
-
-
-
- 31
-
-
-
-
- 32
-
-
-
-
- 35
-
-
-
-
- 36
-
-
-
-
- 37
-
-
-
-
- 38
-
-
-
-
- 39
-
-
-
-
- 40
-
-
-
-
- 42
-
-
-
-
-
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- {{357, 418}, {480, 270}}
-
-
-
-
-
-
-
-
-
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
-
-
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
- com.apple.InterfaceBuilder.CocoaPlugin
-
- com.apple.InterfaceBuilder.CocoaPlugin
-
-
-
-
-
- 42
-
-
-
-
- MacUpdaterAppDelegate
- NSObject
-
- cancel:
- id
-
-
- cancel:
-
- cancel:
- id
-
-
-
- NSProgressIndicator
- NSTextField
- NSWindow
-
-
-
- mProgressBar
- NSProgressIndicator
-
-
- mProgressText
- NSTextField
-
-
- window
- NSWindow
-
-
-
- IBProjectSource
- ./Classes/MacUpdaterAppDelegate.h
-
-
-
-
- 0
- IBCocoaFramework
- YES
- 3
- YES
-
-
diff --git a/indra/mac_updater/CMakeLists.txt b/indra/mac_updater/CMakeLists.txt
index 7382e912bf..00dcedecaa 100644
--- a/indra/mac_updater/CMakeLists.txt
+++ b/indra/mac_updater/CMakeLists.txt
@@ -18,14 +18,10 @@ include_directories(
)
set(mac_updater_SOURCE_FILES
- main.m
- MacUpdaterAppDelegate.mm
mac_updater.cpp
)
set(mac_updater_HEADER_FILES
- MacUpdaterAppDelegate.h
- mac_updater.h
CMakeLists.txt
)
@@ -36,7 +32,7 @@ list(APPEND mac_updater_SOURCE_FILES ${mac_updater_HEADER_FILES})
set(mac_updater_RESOURCE_FILES
- AutoUpdater.nib
+ AutoUpdater.nib/
)
set_source_files_properties(
${mac_updater_RESOURCE_FILES}
@@ -52,19 +48,13 @@ add_executable(mac-updater
set_target_properties(mac-updater
PROPERTIES
- MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/MacUpdater-Info.plist
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist
)
-find_library(COCOA_LIBRARY Cocoa)
-find_library(IOKIT_LIBRARY IOKit)
-
target_link_libraries(mac-updater
${LLVFS_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
- ${COCOA_LIBRARIES}
- ${BOOST_FILESYSTEM_LIBRARY}
- ${IOKIT_LIBRARY}
${CURL_LIBRARIES}
${CARES_LIBRARIES}
${LLCOMMON_LIBRARIES}
@@ -72,16 +62,10 @@ target_link_libraries(mac-updater
add_custom_command(
TARGET mac-updater POST_BUILD
-# COMMAND ${CMAKE_COMMAND}
-# ARGS
-# -E
-# copy_directory
-# ${CMAKE_CURRENT_SOURCE_DIR}/AutoUpdater.nib
-# ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mac-updater.app/Contents/Resources/AutoUpdater.nib
COMMAND ${CMAKE_COMMAND}
ARGS
-E
- copy
+ copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/AutoUpdater.nib
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mac-updater.app/Contents/Resources/AutoUpdater.nib
)
diff --git a/indra/mac_updater/MacUpdater-Info.plist b/indra/mac_updater/MacUpdater-Info.plist
deleted file mode 100644
index 92137095ff..0000000000
--- a/indra/mac_updater/MacUpdater-Info.plist
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleExecutable
- mac-updater
- CFBundleGetInfoString
-
- CFBundleIconFile
-
- CFBundleIdentifier
- com.secondlife.indra.autoupdater
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
-
- CFBundleSignature
- ????
- CFBundleVersion
- 1.0.0
- NSMainNibFile
- AutoUpdater
- NSPrincipalClass
- NSApplication
-
-
diff --git a/indra/mac_updater/MacUpdaterAppDelegate.h b/indra/mac_updater/MacUpdaterAppDelegate.h
deleted file mode 100644
index c051214bb8..0000000000
--- a/indra/mac_updater/MacUpdaterAppDelegate.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * @file MacUpdaterAppDelegate.h
- * @brief
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-
-#import
-#include
-#include "mac_updater.h"
-
-#ifndef LL_MAC_UPDATE_DELEGATE_H
-#define LL_MAC_UPDATE_DELEGATE_H
-
-@interface MacUpdaterAppDelegate : NSObject
-{
- IBOutlet NSProgressIndicator *mProgressBar;
- IBOutlet NSTextField *mProgressText;
-}
-- (void)setWindow:(NSWindow *)newWindow;
-- (NSWindow *)window;
-- (IBAction)cancel:(id)sender;
-- (void) setProgress:(int)cur max:(int) max;
-- (void) setProgressText:(const std::string&)str;
-- (int) parse_args:(NSArray *) args;
-- (void)stopAlert;
-- (void)stopAlertDidEnd:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo;
-
-
-NSWindow *_window;
-bool mAnimated;
-double mProgressPercentage;
-@property (assign) IBOutlet NSWindow *window;
-LLMacUpdater mUpdater;
-
-@end
-
-#endif //LL_MAC_UPDATE_DELEGATE_H
-
-
diff --git a/indra/mac_updater/MacUpdaterAppDelegate.mm b/indra/mac_updater/MacUpdaterAppDelegate.mm
deleted file mode 100644
index b6f95eef7e..0000000000
--- a/indra/mac_updater/MacUpdaterAppDelegate.mm
+++ /dev/null
@@ -1,265 +0,0 @@
-/**
- * @file MacUpdaterAppDelegate.mm
- * @brief
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#import "MacUpdaterAppDelegate.h"
-#include "llvfs_objc.h"
-#include
-#include
-
-@implementation MacUpdaterAppDelegate
-
-MacUpdaterAppDelegate *gWindow;
-bool gCancelled = false;
-bool gFailure =false;
-
-
-//@synthesize window = _window;
-- (void)setWindow:(NSWindow *)window
-{
- _window = window;
-}
-
-- (NSWindow *)window
-{
- return _window;
-}
-
-- (id)init
-{
- self = [super init];
- if (self) {
-
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- mAnimated = false;
- mProgressPercentage = 0.0;
- NSArray *arguments = [[NSProcessInfo processInfo] arguments];
-
- [self parse_args:arguments];
- gWindow = self;
-
- mUpdater.doUpdate();
- [pool drain];
- [pool release];
- }
- return self;
-}
-
-- (void)dealloc
-{
- [super dealloc];
-}
-
-std::string* NSToString( NSString *ns_str )
-{
- return ( new std::string([ns_str UTF8String]) );
-}
-
-
-- (void) setProgress:(int)cur max:(int) max
-{
- bool indeterminate = false;
- if (max==0)
- {
- indeterminate = true;
- }
- else
- {
- double percentage = ((double)cur / (double)max) * 100.0;
- [mProgressBar setDoubleValue:percentage];
- }
- [mProgressBar setIndeterminate:indeterminate];
-}
-
-- (void) setProgressText:(const std::string& )str
-{
- [mProgressText setStringValue:[NSString stringWithUTF8String:str.c_str()]];
-}
-
-void sendDone()
-{
- [ [ (id) gWindow window ] close];
-}
-
-void sendStopAlert()
-{
- [ gWindow stopAlert ];
-}
-
-void setProgress(int cur, int max)
-{
- [ (id) gWindow setProgress:cur max:max];
-}
-
-void setProgressText(const std::string& str)
-{
- [ (id) gWindow setProgressText:str];
-}
-
-void sendProgress(int cur, int max, const std::string str)
-{
- setProgress(cur,max);
- setProgressText(str);
-}
-
-bool copyDir(const std::string& src_dir, const std::string& dest_dir)
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- NSString* file = [NSString stringWithCString:src_dir.c_str()
- encoding:[NSString defaultCStringEncoding]];
- NSString* toParent = [NSString stringWithCString:dest_dir.c_str()
- encoding:[NSString defaultCStringEncoding]];
- NSError* error = nil;
-
- bool result = [[NSFileManager defaultManager] copyItemAtPath: file toPath: toParent error:&error];
-
- if (!result) {
- NSLog(@"Error during copy: %@", [error localizedDescription]);
- }
- [pool release];
-
- return result;
-}
-
-- (int) parse_args:(NSArray *) args
-{
- int i;
- int argc = [args count];
-
- mUpdater.mApplicationPath = NSToString( [args objectAtIndex:0] );
-
- for( i = 1; i < argc; i++ )
- {
- NSString* ns_arg = [args objectAtIndex:i];
- const char *arg = [ns_arg UTF8String];
-
- if ((!strcmp(arg, "-url")) && (i < argc))
- {
- mUpdater.mUpdateURL = NSToString( [args objectAtIndex:(++i)] );
- }
- else if ((!strcmp(arg, "-name")) && (i < argc))
- {
- mUpdater.mProductName = NSToString( [args objectAtIndex:(++i)] );
- }
- else if ((!strcmp(arg, "-bundleid")) && (i < argc))
- {
- mUpdater.mBundleID = NSToString( [args objectAtIndex:(++i)] );
- }
- else if ((!strcmp(arg, "-dmg")) && (i < argc))
- {
- mUpdater.mDmgFile = NSToString( [args objectAtIndex:(++i)] );
- }
- else if ((!strcmp(arg, "-marker")) && (i < argc))
- {
- mUpdater.mMarkerPath = NSToString( [args objectAtIndex:(++i)] );
- }
- }
- return 0;
-}
-
-bool isDirWritable(const std::string& dir_name)
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- NSString *fullPath = [NSString stringWithCString:dir_name.c_str()
- encoding:[NSString defaultCStringEncoding]];
-
- NSFileManager *fm = [NSFileManager defaultManager];
- bool result = [fm isWritableFileAtPath:fullPath];
- [pool release];
-
- return result;
-}
-
-std::string* getUserTrashFolder()
-{
- std::string *result;
-
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- NSString *trash_str=[NSHomeDirectory() stringByAppendingPathComponent:@".Trash"];
-
- result = NSToString( trash_str );
-
- [pool release];
- return result;
-
-}
-
-bool isFSRefViewerBundle(const std::string& targetURL)
-{
- bool result = false;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- NSString *fullPath = [NSString stringWithCString:targetURL.c_str()
- encoding:[NSString defaultCStringEncoding]];
- NSBundle *targetBundle = [NSBundle bundleWithPath:fullPath];
- NSString *targetBundleStr = [targetBundle bundleIdentifier];
- NSString *sourceBundleStr = [NSString stringWithCString:mUpdater.mBundleID->c_str()
- encoding:[NSString defaultCStringEncoding]];
-
- result = [targetBundleStr isEqualToString:sourceBundleStr];
-
- if(!result)
- {
- std::cout << "Target bundle ID mismatch." << std::endl;
- }
-
- [pool release];
-
- return result;
-}
-
-
-- (IBAction)cancel:(id)sender
-{
- gCancelled = true;
- sendDone();
-}
-
-- (void)stopAlert
-{
- NSAlert *alert = [[NSAlert alloc] init];
- [alert setAlertStyle:NSInformationalAlertStyle];
- [alert setMessageText:@"Error"];
- [alert setInformativeText:@"An error occurred while updating Second Life. Please download the latest version from www.secondlife.com."];
-
- [alert beginSheetModalForWindow:_window
- modalDelegate:self
-
- didEndSelector:@selector(stopAlertDidEnd:returnCode:
- contextInfo:)
- contextInfo:nil];
- }
-
- - (void)stopAlertDidEnd:(NSAlert *)alert
- returnCode:(int)returnCode contextInfo:(void *)contextInfo
-{
- [alert release];
-}
-
-
-@end
diff --git a/indra/mac_updater/mac_updater.cpp b/indra/mac_updater/mac_updater.cpp
index fc9565d63d..aa45c5d23f 100644
--- a/indra/mac_updater/mac_updater.cpp
+++ b/indra/mac_updater/mac_updater.cpp
@@ -27,8 +27,6 @@
#include "linden_common.h"
#include
-#include
-#include
#include
#include
@@ -36,6 +34,7 @@
#include
#include
+#include
#include "llerror.h"
#include "lltimer.h"
@@ -44,123 +43,267 @@
#include "llstring.h"
+#include
+
#include "llerrorcontrol.h"
-#include "mac_updater.h"
-#include
+
+enum
+{
+ kEventClassCustom = 'Cust',
+ kEventCustomProgress = 'Prog',
+ kEventParamCustomCurValue = 'Cur ',
+ kEventParamCustomMaxValue = 'Max ',
+ kEventParamCustomText = 'Text',
+ kEventCustomDone = 'Done',
+};
+
+WindowRef gWindow = NULL;
+EventHandlerRef gEventHandler = NULL;
+OSStatus gFailure = noErr;
+Boolean gCancelled = false;
+
+const char *gUpdateURL;
+const char *gProductName;
+const char *gBundleID;
+const char *gDmgFile;
+const char *gMarkerPath;
+
+void *updatethreadproc(void*);
pthread_t updatethread;
-LLMacUpdater* LLMacUpdater::sInstance = NULL;
-
-LLMacUpdater::LLMacUpdater():
- mUpdateURL (NULL),
- mProductName (NULL),
- mBundleID (NULL),
- mDmgFile (NULL),
- mMarkerPath (NULL)
+OSStatus setProgress(int cur, int max)
{
- sInstance = this;
-}
+ OSStatus err;
+ ControlRef progressBar = NULL;
+ ControlID id;
-void LLMacUpdater::doUpdate()
-{
- // We assume that all the logs we're looking for reside on the current drive
- gDirUtilp->initAppDirs("SecondLife");
-
- LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-
- // Rename current log file to ".old"
- std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log.old");
- std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log");
- LLFile::rename(log_file.c_str(), old_log_file.c_str());
-
- // Set the log file to updater.log
- LLError::logToFile(log_file);
-
- if ((mUpdateURL == NULL) && (mDmgFile == NULL))
+ id.signature = 'prog';
+ id.id = 0;
+
+ err = GetControlByID(gWindow, &id, &progressBar);
+ if(err == noErr)
{
- llinfos << "Usage: mac_updater -url | -dmg [-name ] [-program ]" << llendl;
- exit(1);
- }
- else
- {
- llinfos << "Update url is: " << mUpdateURL << llendl;
- if (mProductName)
+ Boolean indeterminate;
+
+ if(max == 0)
{
- llinfos << "Product name is: " << *mProductName << llendl;
+ indeterminate = true;
+ err = SetControlData(progressBar, kControlEntireControl, kControlProgressBarIndeterminateTag, sizeof(Boolean), (Ptr)&indeterminate);
}
else
{
- mProductName = new std::string("Second Life");
- }
- if (mBundleID)
- {
- llinfos << "Bundle ID is: " << *mBundleID << llendl;
- }
- else
- {
- mBundleID = new std::string("com.secondlife.indra.viewer");
+ double percentage = (double)cur / (double)max;
+ SetControlMinimum(progressBar, 0);
+ SetControlMaximum(progressBar, 100);
+ SetControlValue(progressBar, (SInt16)(percentage * 100));
+
+ indeterminate = false;
+ err = SetControlData(progressBar, kControlEntireControl, kControlProgressBarIndeterminateTag, sizeof(Boolean), (Ptr)&indeterminate);
+
+ Draw1Control(progressBar);
}
}
-
- llinfos << "Starting " << *mProductName << " Updater" << llendl;
-
- pthread_create(&updatethread,
- NULL,
- &sUpdatethreadproc,
- NULL);
-
-
- void *threadresult;
-
- pthread_join(updatethread, &threadresult);
-
- if(gCancelled || gFailure)
- {
- sendStopAlert();
-
- if(mMarkerPath != 0)
- {
- // Create a install fail marker that can be used by the viewer to
- // detect install problems.
- std::ofstream stream(mMarkerPath->c_str());
- if(stream) stream << -1;
- }
- exit(-1);
- } else {
- exit(0);
- }
-
- return;
+
+ return(err);
}
-//SPATTERS TODO this should be moved to lldir_mac.cpp
-const std::string LLMacUpdater::walkParents( signed int depth, const std::string& childpath )
+OSStatus setProgressText(CFStringRef text)
{
- boost::filesystem::path fullpath(childpath.c_str());
-
- while (depth > 0 && fullpath.has_parent_path())
- {
- fullpath = boost::filesystem::path(fullpath.parent_path());
- --depth;
- }
-
- return fullpath.string();
+ OSStatus err;
+ ControlRef progressText = NULL;
+ ControlID id;
+
+ id.signature = 'what';
+ id.id = 0;
+
+ err = GetControlByID(gWindow, &id, &progressText);
+ if(err == noErr)
+ {
+ err = SetControlData(progressText, kControlEntireControl, kControlStaticTextCFStringTag, sizeof(CFStringRef), (Ptr)&text);
+ Draw1Control(progressText);
+ }
+
+ return(err);
}
-//#if 0
-//size_t curl_download_callback(void *data, size_t size, size_t nmemb,
-// void *user_data)
-//{
-// S32 bytes = size * nmemb;
-// char *cdata = (char *) data;
-// for (int i =0; i < bytes; i += 1)
-// {
-// gServerResponse.append(cdata[i]);
-// }
-// return bytes;
-//}
-//#endif
+OSStatus sendProgress(long cur, long max, CFStringRef text = NULL)
+{
+ OSStatus result;
+ EventRef evt;
+
+ result = CreateEvent(
+ NULL,
+ kEventClassCustom,
+ kEventCustomProgress,
+ 0,
+ kEventAttributeNone,
+ &evt);
+
+ // This event needs to be targeted at the window so it goes to the window's handler.
+ if(result == noErr)
+ {
+ EventTargetRef target = GetWindowEventTarget(gWindow);
+ result = SetEventParameter (
+ evt,
+ kEventParamPostTarget,
+ typeEventTargetRef,
+ sizeof(target),
+ &target);
+ }
+
+ if(result == noErr)
+ {
+ result = SetEventParameter (
+ evt,
+ kEventParamCustomCurValue,
+ typeLongInteger,
+ sizeof(cur),
+ &cur);
+ }
+
+ if(result == noErr)
+ {
+ result = SetEventParameter (
+ evt,
+ kEventParamCustomMaxValue,
+ typeLongInteger,
+ sizeof(max),
+ &max);
+ }
+
+ if(result == noErr)
+ {
+ if(text != NULL)
+ {
+ result = SetEventParameter (
+ evt,
+ kEventParamCustomText,
+ typeCFStringRef,
+ sizeof(text),
+ &text);
+ }
+ }
+
+ if(result == noErr)
+ {
+ // Send the event
+ PostEventToQueue(
+ GetMainEventQueue(),
+ evt,
+ kEventPriorityStandard);
+
+ }
+
+ return(result);
+}
+
+OSStatus sendDone(void)
+{
+ OSStatus result;
+ EventRef evt;
+
+ result = CreateEvent(
+ NULL,
+ kEventClassCustom,
+ kEventCustomDone,
+ 0,
+ kEventAttributeNone,
+ &evt);
+
+ // This event needs to be targeted at the window so it goes to the window's handler.
+ if(result == noErr)
+ {
+ EventTargetRef target = GetWindowEventTarget(gWindow);
+ result = SetEventParameter (
+ evt,
+ kEventParamPostTarget,
+ typeEventTargetRef,
+ sizeof(target),
+ &target);
+ }
+
+ if(result == noErr)
+ {
+ // Send the event
+ PostEventToQueue(
+ GetMainEventQueue(),
+ evt,
+ kEventPriorityStandard);
+
+ }
+
+ return(result);
+}
+
+OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata)
+{
+ OSStatus result = eventNotHandledErr;
+ OSStatus err;
+ UInt32 evtClass = GetEventClass(event);
+ UInt32 evtKind = GetEventKind(event);
+
+ if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess))
+ {
+ HICommand cmd;
+ err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd);
+
+ if(err == noErr)
+ {
+ switch(cmd.commandID)
+ {
+ case kHICommandCancel:
+ gCancelled = true;
+// QuitAppModalLoopForWindow(gWindow);
+ result = noErr;
+ break;
+ }
+ }
+ }
+ else if((evtClass == kEventClassCustom) && (evtKind == kEventCustomProgress))
+ {
+ // Request to update the progress dialog
+ long cur = 0;
+ long max = 0;
+ CFStringRef text = NULL;
+ (void) GetEventParameter(event, kEventParamCustomCurValue, typeLongInteger, NULL, sizeof(cur), NULL, &cur);
+ (void) GetEventParameter(event, kEventParamCustomMaxValue, typeLongInteger, NULL, sizeof(max), NULL, &max);
+ (void) GetEventParameter(event, kEventParamCustomText, typeCFStringRef, NULL, sizeof(text), NULL, &text);
+
+ err = setProgress(cur, max);
+ if(err == noErr)
+ {
+ if(text != NULL)
+ {
+ setProgressText(text);
+ }
+ }
+
+ result = noErr;
+ }
+ else if((evtClass == kEventClassCustom) && (evtKind == kEventCustomDone))
+ {
+ // We're done. Exit the modal loop.
+ QuitAppModalLoopForWindow(gWindow);
+ result = noErr;
+ }
+
+ return(result);
+}
+
+#if 0
+size_t curl_download_callback(void *data, size_t size, size_t nmemb,
+ void *user_data)
+{
+ S32 bytes = size * nmemb;
+ char *cdata = (char *) data;
+ for (int i =0; i < bytes; i += 1)
+ {
+ gServerResponse.append(cdata[i]);
+ }
+ return bytes;
+}
+#endif
int curl_progress_callback_func(void *clientp,
double dltotal,
@@ -170,7 +313,7 @@ int curl_progress_callback_func(void *clientp,
{
int max = (int)(dltotal / 1024.0);
int cur = (int)(dlnow / 1024.0);
- setProgress(cur, max);
+ sendProgress(cur, max);
if(gCancelled)
return(1);
@@ -178,432 +321,899 @@ int curl_progress_callback_func(void *clientp,
return(0);
}
-bool LLMacUpdater::isApplication(const std::string& app_str)
+int parse_args(int argc, char **argv)
{
- return !(bool) app_str.compare( app_str.length()-4, 4, ".app");
-}
-
-// Search through the directory specified by 'parent' for an item that appears to be a Second Life viewer.
-bool LLMacUpdater::findAppBundleOnDiskImage(const boost::filesystem::path& dir_path,
- boost::filesystem::path& path_found)
-{
- if ( !boost::filesystem::exists( dir_path ) ) return false;
+ int j;
- boost::filesystem::directory_iterator end_itr;
-
- for ( boost::filesystem::directory_iterator itr( dir_path );
- itr != end_itr;
- ++itr )
- {
- if ( boost::filesystem::is_directory(itr->status()) )
- {
- std::string dir_name = itr->path().string();
- if ( isApplication(dir_name) )
- {
- if(isFSRefViewerBundle(dir_name))
- {
- llinfos << dir_name << " is the one" << llendl;
-
- path_found = itr->path();
- return true;
- }
- }
- }
- }
- return false;
-}
-
-bool LLMacUpdater::verifyDirectory(const boost::filesystem::path* directory, bool isParent)
-{
- bool replacingTarget;
- std::string app_str = directory->string();
-
- if (boost::filesystem::is_directory(*directory))
- {
- // This is fine, just means we're not replacing anything.
- replacingTarget = true;
- }
- else
- {
- replacingTarget = isParent;
- }
-
- //Check that the directory is writeable.
- if(!isDirWritable(app_str))
- {
- // Parent directory isn't writable.
- llinfos << "Target directory not writable." << llendl;
- replacingTarget = false;
- }
- return replacingTarget;
-}
-
-bool LLMacUpdater::getViewerDir(boost::filesystem::path &app_dir)
-{
- std::string app_dir_str;
-
- //Walk up 6 levels from the App Updater's installation point.
- app_dir_str = walkParents( 6, *mApplicationPath );
-
- app_dir = boost::filesystem::path(app_dir_str);
-
- //Check to see that the directory's name ends in .app Lame but it's the best thing we have to go on.
- //If it's not there, we're going to default to /Applications/VIEWERNAME
- if (!isApplication(app_dir_str))
- {
- llinfos << "Target search failed, defaulting to /Applications/" << *mProductName << ".app." << llendl;
- std::string newpath = std::string("/Applications/") + mProductName->c_str();
- app_dir = boost::filesystem::path(newpath);
- }
- return verifyDirectory(&app_dir);
-}
-
-bool LLMacUpdater::downloadDMG(const std::string& dmgName, boost::filesystem::path* temp_dir)
-{
- LLFILE *downloadFile = NULL;
- char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
-
- chdir(temp_dir->string().c_str());
-
- snprintf(temp, sizeof(temp), "SecondLife.dmg");
-
- downloadFile = LLFile::fopen(temp, "wb"); /* Flawfinder: ignore */
- if(downloadFile == NULL)
- {
- return false;
- }
-
- bool success = false;
-
- CURL *curl = curl_easy_init();
-
- curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
- // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback);
- curl_easy_setopt(curl, CURLOPT_FILE, downloadFile);
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
- curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, &curl_progress_callback_func);
- curl_easy_setopt(curl, CURLOPT_URL, mUpdateURL);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
-
- sendProgress(0, 1, std::string("Downloading..."));
-
- CURLcode result = curl_easy_perform(curl);
-
- curl_easy_cleanup(curl);
-
- if(gCancelled)
- {
- llinfos << "User cancel, bailing out."<< llendl;
- goto close_file;
- }
-
- if(result != CURLE_OK)
- {
- llinfos << "Error " << result << " while downloading disk image."<< llendl;
- goto close_file;
- }
-
- fclose(downloadFile);
- downloadFile = NULL;
-
- success = true;
-
-close_file:
- // Close disk image file if necessary
- if(downloadFile != NULL)
+ for (j = 1; j < argc; j++)
{
- llinfos << "Closing download file." << llendl;
-
- fclose(downloadFile);
- downloadFile = NULL;
+ if ((!strcmp(argv[j], "-url")) && (++j < argc))
+ {
+ gUpdateURL = argv[j];
+ }
+ else if ((!strcmp(argv[j], "-name")) && (++j < argc))
+ {
+ gProductName = argv[j];
+ }
+ else if ((!strcmp(argv[j], "-bundleid")) && (++j < argc))
+ {
+ gBundleID = argv[j];
+ }
+ else if ((!strcmp(argv[j], "-dmg")) && (++j < argc))
+ {
+ gDmgFile = argv[j];
+ }
+ else if ((!strcmp(argv[j], "-marker")) && (++j < argc))
+ {
+ gMarkerPath = argv[j];;
+ }
}
- return success;
+ return 0;
}
-
-bool LLMacUpdater::doMount(const std::string& dmgName, char* deviceNode, const boost::filesystem::path& temp_dir)
+
+int main(int argc, char **argv)
{
- char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
-
- sendProgress(0, 0, std::string("Mounting image..."));
- chdir(temp_dir.string().c_str());
- std::string mnt_dir = temp_dir.string() + std::string("/mnt");
- LLFile::mkdir(mnt_dir.c_str(), 0700);
-
- // NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder,
- // but if our cleanup fails, this makes it much harder for the user to unmount the image.
- std::string mountOutput;
- boost::format cmdFormat("hdiutil attach %s -mountpoint mnt");
- cmdFormat % dmgName;
- FILE* mounter = popen(cmdFormat.str().c_str(), "r"); /* Flawfinder: ignore */
-
- if(mounter == NULL)
- {
- llinfos << "Failed to mount disk image, exiting."<< llendl;
- return false;
- }
-
- // We need to scan the output from hdiutil to find the device node it uses to attach the disk image.
- // If we don't have this information, we can't detach it later.
- while(mounter != NULL)
- {
- size_t len = fread(temp, 1, sizeof(temp)-1, mounter);
- temp[len] = 0;
- mountOutput.append(temp);
- if(len < sizeof(temp)-1)
- {
- // End of file or error.
- int result = pclose(mounter);
- if(result != 0)
- {
- // NOTE: We used to abort here, but pclose() started returning
- // -1, possibly when the size of the DMG passed a certain point
- llinfos << "Unexpected result closing pipe: " << result << llendl;
- }
- mounter = NULL;
- }
- }
-
- if(!mountOutput.empty())
- {
- const char *s = mountOutput.c_str();
- const char *prefix = "/dev/";
- char *sub = strstr(s, prefix);
-
- if(sub != NULL)
- {
- sub += strlen(prefix); /* Flawfinder: ignore */
- sscanf(sub, "%1023s", deviceNode); /* Flawfinder: ignore */
- }
- }
-
- if(deviceNode[0] != 0)
- {
- llinfos << "Disk image attached on /dev/" << deviceNode << llendl;
- }
- else
- {
- llinfos << "Disk image device node not found!" << llendl;
- return false;
- }
-
- return true;
+ // We assume that all the logs we're looking for reside on the current drive
+ gDirUtilp->initAppDirs("SecondLife");
+
+ LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+
+ // Rename current log file to ".old"
+ std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log.old");
+ std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log");
+ LLFile::rename(log_file.c_str(), old_log_file.c_str());
+
+ // Set the log file to updater.log
+ LLError::logToFile(log_file);
+
+ /////////////////////////////////////////
+ //
+ // Process command line arguments
+ //
+ gUpdateURL = NULL;
+ gProductName = NULL;
+ gBundleID = NULL;
+ gDmgFile = NULL;
+ gMarkerPath = NULL;
+ parse_args(argc, argv);
+ if ((gUpdateURL == NULL) && (gDmgFile == NULL))
+ {
+ llinfos << "Usage: mac_updater -url | -dmg [-name ] [-program ]" << llendl;
+ exit(1);
+ }
+ else
+ {
+ llinfos << "Update url is: " << gUpdateURL << llendl;
+ if (gProductName)
+ {
+ llinfos << "Product name is: " << gProductName << llendl;
+ }
+ else
+ {
+ gProductName = "Second Life";
+ }
+ if (gBundleID)
+ {
+ llinfos << "Bundle ID is: " << gBundleID << llendl;
+ }
+ else
+ {
+ gBundleID = "com.secondlife.indra.viewer";
+ }
+ }
+
+ llinfos << "Starting " << gProductName << " Updater" << llendl;
+
+ // Real UI...
+ OSStatus err;
+ IBNibRef nib = NULL;
+
+ err = CreateNibReference(CFSTR("AutoUpdater"), &nib);
+
+ char windowTitle[MAX_PATH]; /* Flawfinder: ignore */
+ snprintf(windowTitle, sizeof(windowTitle), "%s Updater", gProductName);
+ CFStringRef windowTitleRef = NULL;
+ windowTitleRef = CFStringCreateWithCString(NULL, windowTitle, kCFStringEncodingUTF8);
+
+ if(err == noErr)
+ {
+ err = CreateWindowFromNib(nib, CFSTR("Updater"), &gWindow);
+ }
+
+ if (err == noErr)
+ {
+ err = SetWindowTitleWithCFString(gWindow, windowTitleRef);
+ }
+ CFRelease(windowTitleRef);
+
+ if(err == noErr)
+ {
+ // Set up an event handler for the window.
+ EventTypeSpec handlerEvents[] =
+ {
+ { kEventClassCommand, kEventCommandProcess },
+ { kEventClassCustom, kEventCustomProgress },
+ { kEventClassCustom, kEventCustomDone }
+ };
+ InstallStandardEventHandler(GetWindowEventTarget(gWindow));
+ InstallWindowEventHandler(
+ gWindow,
+ NewEventHandlerUPP(dialogHandler),
+ GetEventTypeCount (handlerEvents),
+ handlerEvents,
+ 0,
+ &gEventHandler);
+ }
+
+ if(err == noErr)
+ {
+ ShowWindow(gWindow);
+ SelectWindow(gWindow);
+ }
+
+ if(err == noErr)
+ {
+ pthread_create(&updatethread,
+ NULL,
+ &updatethreadproc,
+ NULL);
+
+ }
+
+ if(err == noErr)
+ {
+ RunAppModalLoopForWindow(gWindow);
+ }
+
+ void *threadresult;
+
+ pthread_join(updatethread, &threadresult);
+
+ if(!gCancelled && (gFailure != noErr))
+ {
+ // Something went wrong. Since we always just tell the user to download a new version, we don't really care what.
+ AlertStdCFStringAlertParamRec params;
+ SInt16 retval_mac = 1;
+ DialogRef alert = NULL;
+ OSStatus err;
+
+ params.version = kStdCFStringAlertVersionOne;
+ params.movable = false;
+ params.helpButton = false;
+ params.defaultText = (CFStringRef)kAlertDefaultOKText;
+ params.cancelText = 0;
+ params.otherText = 0;
+ params.defaultButton = 1;
+ params.cancelButton = 0;
+ params.position = kWindowDefaultPosition;
+ params.flags = 0;
+
+ err = CreateStandardAlert(
+ kAlertStopAlert,
+ CFSTR("Error"),
+ CFSTR("An error occurred while updating Second Life. Please download the latest version from www.secondlife.com."),
+ ¶ms,
+ &alert);
+
+ if(err == noErr)
+ {
+ err = RunStandardAlert(
+ alert,
+ NULL,
+ &retval_mac);
+ }
+
+ if(gMarkerPath != 0)
+ {
+ // Create a install fail marker that can be used by the viewer to
+ // detect install problems.
+ std::ofstream stream(gMarkerPath);
+ if(stream) stream << -1;
+ }
+ exit(-1);
+ } else {
+ exit(0);
+ }
+
+ if(gWindow != NULL)
+ {
+ DisposeWindow(gWindow);
+ }
+
+ if(nib != NULL)
+ {
+ DisposeNibReference(nib);
+ }
+
+ return 0;
}
-bool LLMacUpdater::moveApplication (const boost::filesystem::path& app_dir,
- const boost::filesystem::path& temp_dir,
- boost::filesystem::path& aside_dir)
+bool isDirWritable(FSRef &dir)
{
- try
- {
- //Grab filename from installdir append to tempdir move set aside_dir to moved path.
- std::string install_str = app_dir.parent_path().string();
- std::string temp_str = temp_dir.string();
- std::string app_str = app_dir.filename().string();
- aside_dir = boost::filesystem::path( boost::filesystem::operator/(temp_dir,app_str) );
- std::cout << "Attempting to move " << app_dir.string() << " to " << aside_dir.string() << std::endl;
-
- boost::filesystem::rename(app_dir, aside_dir);
- }
- catch(boost::filesystem::filesystem_error e)
- {
- llinfos << "Application move failed." << llendl;
- return false;
- }
- return true;
+ bool result = false;
+
+ // Test for a writable directory by creating a directory, then deleting it again.
+ // This is kinda lame, but will pretty much always give the right answer.
+
+ OSStatus err = noErr;
+ char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
+
+ err = FSRefMakePath(&dir, (UInt8*)temp, sizeof(temp));
+
+ if(err == noErr)
+ {
+ strncat(temp, "/.test_XXXXXX", (sizeof(temp) - strlen(temp)) - 1);
+
+ if(mkdtemp(temp) != NULL)
+ {
+ // We were able to make the directory. This means the directory is writable.
+ result = true;
+
+ // Clean up.
+ rmdir(temp);
+ }
+ }
+
+#if 0
+ // This seemed like a good idea, but won't tell us if we're on a volume mounted read-only.
+ UInt8 perm;
+ err = FSGetUserPrivilegesPermissions(&targetParentRef, &perm, NULL);
+ if(err == noErr)
+ {
+ if(perm & kioACUserNoMakeChangesMask)
+ {
+ // Parent directory isn't writable.
+ llinfos << "Target parent directory not writable." << llendl;
+ err = -1;
+ replacingTarget = false;
+ }
+ }
+#endif
+
+ return result;
}
-bool LLMacUpdater::doInstall(const boost::filesystem::path& app_dir,
- const boost::filesystem::path& temp_dir,
- boost::filesystem::path& mount_dir,
- bool replacingTarget)
-{
- std::string temp_name = temp_dir.string() + std::string("/mnt");
-
- llinfos << "Disk image mount point is: " << temp_name << llendl;
-
- mount_dir = boost::filesystem::path(temp_name.c_str());
-
- if (! boost::filesystem::exists ( mount_dir ) )
- {
- llinfos << "Couldn't make FSRef to disk image mount point." << llendl;
- return false;
- }
-
- sendProgress(0, 0, std::string("Searching for the app bundle..."));
-
- boost::filesystem::path source_dir;
-
- if ( !findAppBundleOnDiskImage(mount_dir, source_dir) )
- {
- llinfos << "Couldn't find application bundle on mounted disk image." << llendl;
- return false;
- }
- else
- {
- llinfos << "found the bundle." << llendl;
- }
-
- sendProgress(0, 0, std::string("Preparing to copy files..."));
-
- // this will hold the name of the destination target
- boost::filesystem::path aside_dir;
-
- if(replacingTarget)
- {
-
- if (! moveApplication (app_dir, temp_dir, aside_dir) )
- {
- llwarns << "failed to move aside old version." << llendl;
- return false;
- }
- }
-
- sendProgress(0, 0, std::string("Copying files..."));
-
- llinfos << "Starting copy..." << llendl;
- // If we were replacingTarget, we've moved the app to a temp directory.
- // Otherwise the destination should be empty.
- // We have mounted the DMG as a volume so we should be able to just
- // move the app from the volume to the destination and everything will just work.
-
-
- // Copy the new version from the disk image to the target location.
-
- //The installer volume is mounted read-only so we can't move. Instead copy and then unmount.
- if (! copyDir(source_dir.string(), app_dir.string()) )
- {
- llwarns << "Failed to copy " << source_dir.string() << " to " << app_dir.string() << llendl;
-
- // Something went wrong during the copy. Attempt to put the old version back and bail.
- boost::filesystem::rename(app_dir, aside_dir);
- return false;
-
- }
-
- // The update has succeeded. Clear the cache directory.
-
- sendProgress(0, 0, std::string("Clearing cache..."));
-
- llinfos << "Clearing cache..." << llendl;
-
- gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*");
-
- llinfos << "Clear complete." << llendl;
-
- return true;
+static std::string HFSUniStr255_to_utf8str(const HFSUniStr255* src)
+{
+ llutf16string string16((U16*)&(src->unicode), src->length);
+ std::string result = utf16str_to_utf8str(string16);
+ return result;
}
-bool mkTempDir(boost::filesystem::path& temp_dir)
-{
- char temp_str[PATH_MAX] = "/tmp/SecondLifeUpdate_XXXXXX";
-
- if(mkdtemp(temp_str) == NULL)
- {
- return false;
- }
-
- temp_dir = boost::filesystem::path(temp_str);
-
- return true;
+int restoreObject(const char* aside, const char* target, const char* path, const char* object)
+{
+ char source[PATH_MAX] = ""; /* Flawfinder: ignore */
+ char dest[PATH_MAX] = ""; /* Flawfinder: ignore */
+ snprintf(source, sizeof(source), "%s/%s/%s", aside, path, object);
+ snprintf(dest, sizeof(dest), "%s/%s", target, path);
+ FSRef sourceRef;
+ FSRef destRef;
+ OSStatus err;
+ err = FSPathMakeRef((UInt8 *)source, &sourceRef, NULL);
+ if(err != noErr) return false;
+ err = FSPathMakeRef((UInt8 *)dest, &destRef, NULL);
+ if(err != noErr) return false;
+
+ llinfos << "Copying " << source << " to " << dest << llendl;
+
+ err = FSCopyObjectSync(
+ &sourceRef,
+ &destRef,
+ NULL,
+ NULL,
+ kFSFileOperationOverwrite);
+
+ if(err != noErr) return false;
+ return true;
}
-void* LLMacUpdater::updatethreadproc(void*)
+// Replace any mention of "Second Life" with the product name.
+void filterFile(const char* filename)
+{
+ char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
+ // First copy the target's version, so we can run it through sed.
+ snprintf(temp, sizeof(temp), "cp '%s' '%s.tmp'", filename, filename);
+ system(temp); /* Flawfinder: ignore */
+
+ // Now run it through sed.
+ snprintf(temp, sizeof(temp),
+ "sed 's/Second Life/%s/g' '%s.tmp' > '%s'", gProductName, filename, filename);
+ system(temp); /* Flawfinder: ignore */
+}
+
+static bool isFSRefViewerBundle(FSRef *targetRef)
+{
+ bool result = false;
+ CFURLRef targetURL = NULL;
+ CFBundleRef targetBundle = NULL;
+ CFStringRef targetBundleID = NULL;
+ CFStringRef sourceBundleID = NULL;
+
+ targetURL = CFURLCreateFromFSRef(NULL, targetRef);
+
+ if(targetURL == NULL)
+ {
+ llinfos << "Error creating target URL." << llendl;
+ }
+ else
+ {
+ targetBundle = CFBundleCreate(NULL, targetURL);
+ }
+
+ if(targetBundle == NULL)
+ {
+ llinfos << "Failed to create target bundle." << llendl;
+ }
+ else
+ {
+ targetBundleID = CFBundleGetIdentifier(targetBundle);
+ }
+
+ if(targetBundleID == NULL)
+ {
+ llinfos << "Couldn't retrieve target bundle ID." << llendl;
+ }
+ else
+ {
+ sourceBundleID = CFStringCreateWithCString(NULL, gBundleID, kCFStringEncodingUTF8);
+ if(CFStringCompare(sourceBundleID, targetBundleID, 0) == kCFCompareEqualTo)
+ {
+ // This is the bundle we're looking for.
+ result = true;
+ }
+ else
+ {
+ llinfos << "Target bundle ID mismatch." << llendl;
+ }
+ }
+
+ // Don't release targetBundleID -- since we don't retain it, it's released when targetBundle is released.
+ if(targetURL != NULL)
+ CFRelease(targetURL);
+ if(targetBundle != NULL)
+ CFRelease(targetBundle);
+
+ return result;
+}
+
+// Search through the directory specified by 'parent' for an item that appears to be a Second Life viewer.
+static OSErr findAppBundleOnDiskImage(FSRef *parent, FSRef *app)
+{
+ FSIterator iterator;
+ bool found = false;
+
+ OSErr err = FSOpenIterator( parent, kFSIterateFlat, &iterator );
+ if(!err)
+ {
+ do
+ {
+ ItemCount actualObjects = 0;
+ Boolean containerChanged = false;
+ FSCatalogInfo info;
+ FSRef ref;
+ HFSUniStr255 unicodeName;
+ err = FSGetCatalogInfoBulk(
+ iterator,
+ 1,
+ &actualObjects,
+ &containerChanged,
+ kFSCatInfoNodeFlags,
+ &info,
+ &ref,
+ NULL,
+ &unicodeName );
+
+ if(actualObjects == 0)
+ break;
+
+ if(!err)
+ {
+ // Call succeeded and not done with the iteration.
+ std::string name = HFSUniStr255_to_utf8str(&unicodeName);
+
+ llinfos << "Considering \"" << name << "\"" << llendl;
+
+ if(info.nodeFlags & kFSNodeIsDirectoryMask)
+ {
+ // This is a directory. See if it's a .app
+ if(name.find(".app") != std::string::npos)
+ {
+ // Looks promising. Check to see if it has the right bundle identifier.
+ if(isFSRefViewerBundle(&ref))
+ {
+ llinfos << name << " is the one" << llendl;
+ // This is the one. Return it.
+ *app = ref;
+ found = true;
+ break;
+ } else {
+ llinfos << name << " is not the bundle we are looking for; move along" << llendl;
+ }
+
+ }
+ }
+ }
+ }
+ while(!err);
+
+ llinfos << "closing the iterator" << llendl;
+
+ FSCloseIterator(iterator);
+
+ llinfos << "closed" << llendl;
+ }
+
+ if(!err && !found)
+ err = fnfErr;
+
+ return err;
+}
+
+void *updatethreadproc(void*)
{
char tempDir[PATH_MAX] = ""; /* Flawfinder: ignore */
+ FSRef tempDirRef;
char temp[PATH_MAX] = ""; /* Flawfinder: ignore */
// *NOTE: This buffer length is used in a scanf() below.
char deviceNode[1024] = ""; /* Flawfinder: ignore */
-
- bool replacingTarget = false;
-
- boost::filesystem::path app_dir;
- boost::filesystem::path temp_dir;
- boost::filesystem::path mount_dir;
-
- // Attempt to get a reference to the Second Life application bundle containing this updater.
- // Any failures during this process will cause us to default to updating /Applications/Second Life.app
+ LLFILE *downloadFile = NULL;
+ OSStatus err;
+ ProcessSerialNumber psn;
+ char target[PATH_MAX] = ""; /* Flawfinder: ignore */
+ FSRef targetRef;
+ FSRef targetParentRef;
+ FSVolumeRefNum targetVol;
+ FSRef trashFolderRef;
+ Boolean replacingTarget = false;
+ memset(&tempDirRef, 0, sizeof(tempDirRef));
+ memset(&targetRef, 0, sizeof(targetRef));
+ memset(&targetParentRef, 0, sizeof(targetParentRef));
+
try
- {
- replacingTarget = getViewerDir( app_dir );
-
- if (!mkTempDir(temp_dir))
- {
- throw 0;
- }
-
- //In case the dir doesn't exist, try to create it. If create fails, verify it exists.
- if (! boost::filesystem::create_directory(app_dir))
- {
+ {
+ // Attempt to get a reference to the Second Life application bundle containing this updater.
+ // Any failures during this process will cause us to default to updating /Applications/Second Life.app
+ {
+ FSRef myBundle;
+ err = GetCurrentProcess(&psn);
+ if(err == noErr)
+ {
+ err = GetProcessBundleLocation(&psn, &myBundle);
+ }
- if(isFSRefViewerBundle(app_dir.string()))
- {
- // This is the bundle we're looking for.
- replacingTarget = true;
- }
- else
- {
- throw 0;
- }
- }
-
- if ( !verifyDirectory(&app_dir, true) )
- {
- // We're so hosed.
- llinfos << "Applications directory not found, giving up." << llendl;
- throw 0;
- }
+ if(err == noErr)
+ {
+ // Sanity check: Make sure the name of the item referenced by targetRef is "Second Life.app".
+ FSRefMakePath(&myBundle, (UInt8*)target, sizeof(target));
+
+ llinfos << "Updater bundle location: " << target << llendl;
+ }
+
+ // Our bundle should be in Second Life.app/Contents/Resources/AutoUpdater.app
+ // so we need to go up 3 levels to get the path to the main application bundle.
+ if(err == noErr)
+ {
+ err = FSGetCatalogInfo(&myBundle, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
+ }
+ if(err == noErr)
+ {
+ err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
+ }
+ if(err == noErr)
+ {
+ err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
+ }
+
+ // And once more to get the parent of the target
+ if(err == noErr)
+ {
+ err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetParentRef);
+ }
+
+ if(err == noErr)
+ {
+ FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target));
+ llinfos << "Path to target: " << target << llendl;
+ }
+
+ // Sanity check: make sure the target is a bundle with the right identifier
+ if(err == noErr)
+ {
+ // Assume the worst...
+ err = -1;
+
+ if(isFSRefViewerBundle(&targetRef))
+ {
+ // This is the bundle we're looking for.
+ err = noErr;
+ replacingTarget = true;
+ }
+ }
+
+ // Make sure the target's parent directory is writable.
+ if(err == noErr)
+ {
+ if(!isDirWritable(targetParentRef))
+ {
+ // Parent directory isn't writable.
+ llinfos << "Target parent directory not writable." << llendl;
+ err = -1;
+ replacingTarget = false;
+ }
+ }
+
+ if(err != noErr)
+ {
+ Boolean isDirectory;
+ llinfos << "Target search failed, defaulting to /Applications/" << gProductName << ".app." << llendl;
+
+ // Set up the parent directory
+ err = FSPathMakeRef((UInt8*)"/Applications", &targetParentRef, &isDirectory);
+ if((err != noErr) || (!isDirectory))
+ {
+ // We're so hosed.
+ llinfos << "Applications directory not found, giving up." << llendl;
+ throw 0;
+ }
+
+ snprintf(target, sizeof(target), "/Applications/%s.app", gProductName);
+
+ memset(&targetRef, 0, sizeof(targetRef));
+ err = FSPathMakeRef((UInt8*)target, &targetRef, NULL);
+ if(err == fnfErr)
+ {
+ // This is fine, just means we're not replacing anything.
+ err = noErr;
+ replacingTarget = false;
+ }
+ else
+ {
+ replacingTarget = true;
+ }
+
+ // Make sure the target's parent directory is writable.
+ if(err == noErr)
+ {
+ if(!isDirWritable(targetParentRef))
+ {
+ // Parent directory isn't writable.
+ llinfos << "Target parent directory not writable." << llendl;
+ err = -1;
+ replacingTarget = false;
+ }
+ }
+
+ }
+
+ // If we haven't fixed all problems by this point, just bail.
+ if(err != noErr)
+ {
+ llinfos << "Unable to pick a target, giving up." << llendl;
+ throw 0;
+ }
+ }
+
+ // Find the volID of the volume the target resides on
+ {
+ FSCatalogInfo info;
+ err = FSGetCatalogInfo(
+ &targetParentRef,
+ kFSCatInfoVolume,
+ &info,
+ NULL,
+ NULL,
+ NULL);
+
+ if(err != noErr)
+ throw 0;
+
+ targetVol = info.volume;
+ }
+
+ // Find the temporary items and trash folders on that volume.
+ err = FSFindFolder(
+ targetVol,
+ kTrashFolderType,
+ true,
+ &trashFolderRef);
+
+ if(err != noErr)
+ throw 0;
+
+#if 0 // *HACK for DEV-11935 see below for details.
+
+ FSRef tempFolderRef;
+
+ err = FSFindFolder(
+ targetVol,
+ kTemporaryFolderType,
+ true,
+ &tempFolderRef);
+
+ if(err != noErr)
+ throw 0;
+
+ err = FSRefMakePath(&tempFolderRef, (UInt8*)temp, sizeof(temp));
+
+ if(err != noErr)
+ throw 0;
+
+#else
+
+ // *HACK for DEV-11935 the above kTemporaryFolderType query was giving
+ // back results with path names that seem to be too long to be used as
+ // mount points. I suspect this incompatibility was introduced in the
+ // Leopard 10.5.2 update, but I have not verified this.
+ char const HARDCODED_TMP[] = "/tmp";
+ strncpy(temp, HARDCODED_TMP, sizeof(HARDCODED_TMP));
+
+#endif // 0 *HACK for DEV-11935
// Skip downloading the file if the dmg was passed on the command line.
std::string dmgName;
- if(mDmgFile != NULL) {
- //Create a string from the mDmgFile then a dir reference to that.
- //change to that directory and begin install.
-
- boost::filesystem::path dmg_path(*mDmgFile);
-
- dmgName = dmg_path.string();
- std::string* dmgPath = new std::string(dmg_path.parent_path().string());
- if ( !boost::filesystem::exists( dmg_path.parent_path() ) ) {
- llinfos << "Path " << *dmgPath << " is not writeable. Aborting." << llendl;
- throw 0;
- }
-
- chdir(dmgPath->c_str());
+ if(gDmgFile != NULL) {
+ dmgName = basename((char *)gDmgFile);
+ char * dmgDir = dirname((char *)gDmgFile);
+ strncpy(tempDir, dmgDir, sizeof(tempDir));
+ err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL);
+ if(err != noErr) throw 0;
+ chdir(tempDir);
+ goto begin_install;
} else {
// Continue on to download file.
dmgName = "SecondLife.dmg";
-
+ }
- if (!downloadDMG(dmgName, &temp_dir))
- {
- throw 0;
- }
- }
-
- if (!doMount(dmgName, deviceNode, temp_dir))
- {
- throw 0;
- }
-
- if (!doInstall( app_dir, temp_dir, mount_dir, replacingTarget ))
- {
- throw 0;
- }
+
+ strncat(temp, "/SecondLifeUpdate_XXXXXX", (sizeof(temp) - strlen(temp)) - 1);
+ if(mkdtemp(temp) == NULL)
+ {
+ throw 0;
+ }
+
+ strncpy(tempDir, temp, sizeof(tempDir));
+ temp[sizeof(tempDir) - 1] = '\0';
+
+ llinfos << "tempDir is " << tempDir << llendl;
+ err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL);
+
+ if(err != noErr)
+ throw 0;
+
+ chdir(tempDir);
+
+ snprintf(temp, sizeof(temp), "SecondLife.dmg");
+
+ downloadFile = LLFile::fopen(temp, "wb"); /* Flawfinder: ignore */
+ if(downloadFile == NULL)
+ {
+ throw 0;
+ }
+
+ {
+ CURL *curl = curl_easy_init();
+
+ curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
+ // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback);
+ curl_easy_setopt(curl, CURLOPT_FILE, downloadFile);
+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
+ curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, &curl_progress_callback_func);
+ curl_easy_setopt(curl, CURLOPT_URL, gUpdateURL);
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
+
+ sendProgress(0, 1, CFSTR("Downloading..."));
+
+ CURLcode result = curl_easy_perform(curl);
+
+ curl_easy_cleanup(curl);
+
+ if(gCancelled)
+ {
+ llinfos << "User cancel, bailing out."<< llendl;
+ throw 0;
+ }
+
+ if(result != CURLE_OK)
+ {
+ llinfos << "Error " << result << " while downloading disk image."<< llendl;
+ throw 0;
+ }
+
+ fclose(downloadFile);
+ downloadFile = NULL;
+ }
+
+ begin_install:
+ sendProgress(0, 0, CFSTR("Mounting image..."));
+ LLFile::mkdir("mnt", 0700);
+
+ // NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder,
+ // but if our cleanup fails, this makes it much harder for the user to unmount the image.
+ std::string mountOutput;
+ boost::format cmdFormat("hdiutil attach %s -mountpoint mnt");
+ cmdFormat % dmgName;
+ FILE* mounter = popen(cmdFormat.str().c_str(), "r"); /* Flawfinder: ignore */
+
+ if(mounter == NULL)
+ {
+ llinfos << "Failed to mount disk image, exiting."<< llendl;
+ throw 0;
+ }
+
+ // We need to scan the output from hdiutil to find the device node it uses to attach the disk image.
+ // If we don't have this information, we can't detach it later.
+ while(mounter != NULL)
+ {
+ size_t len = fread(temp, 1, sizeof(temp)-1, mounter);
+ temp[len] = 0;
+ mountOutput.append(temp);
+ if(len < sizeof(temp)-1)
+ {
+ // End of file or error.
+ int result = pclose(mounter);
+ if(result != 0)
+ {
+ // NOTE: We used to abort here, but pclose() started returning
+ // -1, possibly when the size of the DMG passed a certain point
+ llinfos << "Unexpected result closing pipe: " << result << llendl;
+ }
+ mounter = NULL;
+ }
+ }
+
+ if(!mountOutput.empty())
+ {
+ const char *s = mountOutput.c_str();
+ const char *prefix = "/dev/";
+ char *sub = strstr(s, prefix);
+
+ if(sub != NULL)
+ {
+ sub += strlen(prefix); /* Flawfinder: ignore */
+ sscanf(sub, "%1023s", deviceNode); /* Flawfinder: ignore */
+ }
+ }
+
+ if(deviceNode[0] != 0)
+ {
+ llinfos << "Disk image attached on /dev/" << deviceNode << llendl;
+ }
+ else
+ {
+ llinfos << "Disk image device node not found!" << llendl;
+ throw 0;
+ }
+
+ // Get an FSRef to the new application on the disk image
+ FSRef sourceRef;
+ FSRef mountRef;
+ snprintf(temp, sizeof(temp), "%s/mnt", tempDir);
+
+ llinfos << "Disk image mount point is: " << temp << llendl;
+
+ err = FSPathMakeRef((UInt8 *)temp, &mountRef, NULL);
+ if(err != noErr)
+ {
+ llinfos << "Couldn't make FSRef to disk image mount point." << llendl;
+ throw 0;
+ }
+
+ sendProgress(0, 0, CFSTR("Searching for the app bundle..."));
+ err = findAppBundleOnDiskImage(&mountRef, &sourceRef);
+ if(err != noErr)
+ {
+ llinfos << "Couldn't find application bundle on mounted disk image." << llendl;
+ throw 0;
+ }
+ else
+ {
+ llinfos << "found the bundle." << llendl;
+ }
+
+ sendProgress(0, 0, CFSTR("Preparing to copy files..."));
+
+ FSRef asideRef;
+ char aside[MAX_PATH]; /* Flawfinder: ignore */
+
+ // this will hold the name of the destination target
+ CFStringRef appNameRef;
+
+ if(replacingTarget)
+ {
+ // Get the name of the target we're replacing
+ HFSUniStr255 appNameUniStr;
+ err = FSGetCatalogInfo(&targetRef, 0, NULL, &appNameUniStr, NULL, NULL);
+ if(err != noErr)
+ throw 0;
+ appNameRef = FSCreateStringFromHFSUniStr(NULL, &appNameUniStr);
+
+ // Move aside old version (into work directory)
+ err = FSMoveObject(&targetRef, &tempDirRef, &asideRef);
+ if(err != noErr)
+ {
+ llwarns << "failed to move aside old version (error code " <<
+ err << ")" << llendl;
+ throw 0;
+ }
+
+ // Grab the path for later use.
+ err = FSRefMakePath(&asideRef, (UInt8*)aside, sizeof(aside));
+ }
+ else
+ {
+ // Construct the name of the target based on the product name
+ char appName[MAX_PATH]; /* Flawfinder: ignore */
+ snprintf(appName, sizeof(appName), "%s.app", gProductName);
+ appNameRef = CFStringCreateWithCString(NULL, appName, kCFStringEncodingUTF8);
+ }
+
+ sendProgress(0, 0, CFSTR("Copying files..."));
+
+ llinfos << "Starting copy..." << llendl;
+
+ // Copy the new version from the disk image to the target location.
+ err = FSCopyObjectSync(
+ &sourceRef,
+ &targetParentRef,
+ appNameRef,
+ &targetRef,
+ kFSFileOperationDefaultOptions);
+
+ // Grab the path for later use.
+ err = FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target));
+ if(err != noErr)
+ throw 0;
+
+ llinfos << "Copy complete. Target = " << target << llendl;
+
+ if(err != noErr)
+ {
+ // Something went wrong during the copy. Attempt to put the old version back and bail.
+ (void)FSDeleteObject(&targetRef);
+ if(replacingTarget)
+ {
+ (void)FSMoveObject(&asideRef, &targetParentRef, NULL);
+ }
+ throw 0;
+ }
+ else
+ {
+ // The update has succeeded. Clear the cache directory.
+
+ sendProgress(0, 0, CFSTR("Clearing cache..."));
+
+ llinfos << "Clearing cache..." << llendl;
+
+ gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), "*.*");
+
+ llinfos << "Clear complete." << llendl;
+
+ }
}
catch(...)
{
if(!gCancelled)
- gFailure = true;
+ if(gFailure == noErr)
+ gFailure = -1;
}
// Failures from here on out are all non-fatal and not reported.
- sendProgress(0, 3, std::string("Cleaning up..."));
+ sendProgress(0, 3, CFSTR("Cleaning up..."));
- setProgress(1, 3);
+ // Close disk image file if necessary
+ if(downloadFile != NULL)
+ {
+ llinfos << "Closing download file." << llendl;
+
+ fclose(downloadFile);
+ downloadFile = NULL;
+ }
+
+ sendProgress(1, 3);
// Unmount image
if(deviceNode[0] != 0)
{
@@ -613,61 +1223,35 @@ void* LLMacUpdater::updatethreadproc(void*)
system(temp); /* Flawfinder: ignore */
}
- setProgress(2, 3);
- std::string *trash_str=getUserTrashFolder();
+ sendProgress(2, 3);
// Move work directory to the trash
if(tempDir[0] != 0)
{
llinfos << "Moving work directory to the trash." << llendl;
-
- try
- {
- boost::filesystem::path trash_dir(*trash_str);
- boost::filesystem::rename(mount_dir, trash_dir);
- }
- catch(boost::filesystem::filesystem_error e)
- {
- llwarns << "Failed to move " << mount_dir.string() << " to " << *trash_str << llendl;
- return (NULL);
- }
+
+ FSRef trashRef;
+ OSStatus err = FSMoveObjectToTrashSync(&tempDirRef, &trashRef, 0);
+ if(err != noErr) {
+ llwarns << "failed to move files to trash, (error code " <<
+ err << ")" << llendl;
+ }
}
- std::string app_name_str = app_dir.string();
-
- if(!gCancelled && !gFailure && !app_name_str.empty())
+ if(!gCancelled && !gFailure && (target[0] != 0))
{
- //SPATTERS todo is there no better way to do this than system calls?
llinfos << "Touching application bundle." << llendl;
-
- std::stringstream touch_str;
- touch_str << "touch '" << app_name_str << "'";
-
- system(touch_str.str().c_str()); /* Flawfinder: ignore */
+ snprintf(temp, sizeof(temp), "touch '%s'", target);
+ system(temp); /* Flawfinder: ignore */
llinfos << "Launching updated application." << llendl;
-
- std::stringstream open_str;
-
- open_str << "open '" << app_name_str << "'";
- system(open_str.str().c_str()); /* Flawfinder: ignore */
+ snprintf(temp, sizeof(temp), "open '%s'", target);
+ system(temp); /* Flawfinder: ignore */
}
sendDone();
- return (NULL);
+ return(NULL);
}
-
-//static
-void* LLMacUpdater::sUpdatethreadproc(void* vptr)
-{
- if (!sInstance)
- {
- llerrs << "LLMacUpdater not instantiated before use. Aborting." << llendl;
- return (NULL);
- }
- return sInstance->updatethreadproc(vptr);
-}
-
diff --git a/indra/mac_updater/main.m b/indra/mac_updater/main.m
deleted file mode 100644
index aa3776a87d..0000000000
--- a/indra/mac_updater/main.m
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * @file main.m
- * @brief
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#import
-
-int main(int argc, char *argv[])
-{
- int retVal = NSApplicationMain(argc, (const char **)argv);
-
- return retVal;
-}