Ticket #4234: 4234-work-in-progress-patch.txt

File 4234-work-in-progress-patch.txt, 52.3 KB (added by mcs, 6 years ago)

Firefox 17.x patch (work in progress)

Line 
1diff --git a/.mozconfig-mac b/.mozconfig-mac
2index c04c4e0..d14269e 100644
3--- a/.mozconfig-mac
4+++ b/.mozconfig-mac
5@@ -25,18 +25,22 @@ mk_add_options BUILD_OFFICIAL=1
6 
7 ac_add_options --disable-optimize
8 ac_add_options --enable-debug
9 #ac_add_options --disable-debug
10 #ac_add_options --enable-optimize
11 #ac_add_options --enable-strip
12 
13 ac_add_options --enable-official-branding
14+ac_add_options --enable-tor-bundle-update
15+
16+#ac_add_options --disable-updater
17+ac_add_options --enable-update-packaging
18+# --enable-signmar and --enable-verify-mar
19 
20-ac_add_options --disable-updater
21 ac_add_options --disable-crashreporter
22 ac_add_options --disable-maintenance-service
23 ac_add_options --disable-webrtc
24 ac_add_options --disable-tests
25 ac_add_options --disable-ctypes
26 
27 export CFLAGS="-Wno-return-type"
28 export CXXFLAGS="-Wno-return-type"
29--- a/browser/base/content/aboutDialog.js
30+++ b/browser/base/content/aboutDialog.js
31@@ -37,16 +37,23 @@ function init(aEvent)
32   if (/a\d+$/.test(version)) {
33     let buildID = Services.appinfo.appBuildID;
34     let buildDate = buildID.slice(0,4) + "-" + buildID.slice(4,6) + "-" + buildID.slice(6,8);
35     document.getElementById("version").textContent += " (" + buildDate + ")";
36     document.getElementById("experimental").hidden = false;
37     document.getElementById("communityDesc").hidden = true;
38   }
39 
40+#ifdef TOR_BUNDLE_UPDATE
41+  let tbbVersion = Services.prefs.getCharPref("torbrowser.version", null);
42+  let versionElem = document.getElementById("version");
43+  if (tbbVersion && versionElem)
44+    versionElem.textContent += " (TBB " + tbbVersion + ")";
45+#endif
46+
47 #ifdef MOZ_UPDATER
48   gAppUpdater = new appUpdater();
49 
50   let defaults = Services.prefs.getDefaultBranch("");
51   let channelLabel = document.getElementById("currentChannel");
52   channelLabel.value = defaults.getCharPref("app.update.channel");
53 #endif
54 
55@@ -315,19 +322,27 @@ appUpdater.prototype =
56       if (gAppUpdater.update.billboardURL || gAppUpdater.update.licenseURL) {
57         gAppUpdater.selectPanel("updateButtonBox");
58         gAppUpdater.setupUpdateButton("update.openUpdateUI." +
59                                       (this.isMajor ? "upgradeButton"
60                                                     : "applyButton"));
61         return;
62       }
63 
64+     // If the update has the same version as the current application,
65+     // skip add-on compatibility check and start downloading now.
66+#ifdef TOR_BUNDLE_UPDATE
67+      var pkgVersion = Services.prefs.getCharPref("torbrowser.version", "0");
68+dump("update appVersion: " + gAppUpdater.update.appVersion + "\n");
69+dump("appinfo version:   " + pkgVersion + "\n");
70+#else
71+      var pkgVersion = Services.appinfo.version;
72+#endif
73       if (!gAppUpdater.update.appVersion ||
74-          Services.vc.compare(gAppUpdater.update.appVersion,
75-                              Services.appinfo.version) == 0) {
76+          Services.vc.compare(gAppUpdater.update.appVersion, pkgVersion) == 0) {
77         gAppUpdater.startDownload();
78         return;
79       }
80 
81       gAppUpdater.checkAddonCompatibility();
82     },
83 
84     /**
85@@ -383,21 +398,26 @@ appUpdater.prototype =
86         // application and is not compatible with the new application version
87         // then the user should be warned that the add-on will become
88         // incompatible. If an addon's type equals plugin it is skipped since
89         // checking plugins compatibility information isn't supported and
90         // getting the scope property of a plugin breaks in some environments
91         // (see bug 566787). The hotfix add-on is also ignored as it shouldn't
92         // block the user from upgrading.
93         try {
94+#ifdef TOR_BUNDLE_UPDATE
95+          let compatVersion = self.update.platformVersion;
96+#else
97+          let compatVersion = self.update.appVersion;
98+#endif
99           if (aAddon.type != "plugin" && aAddon.id != hotfixID &&
100               !aAddon.appDisabled && !aAddon.userDisabled &&
101               aAddon.scope != AddonManager.SCOPE_APPLICATION &&
102               aAddon.isCompatible &&
103-              !aAddon.isCompatibleWith(self.update.appVersion,
104+              !aAddon.isCompatibleWith(compatVersion,
105                                        self.update.platformVersion))
106             self.addons.push(aAddon);
107         }
108         catch (e) {
109           Components.utils.reportError(e);
110         }
111       });
112       self.addonsTotalCount = self.addons.length;
113@@ -411,18 +431,23 @@ appUpdater.prototype =
114   },
115 
116   /**
117    * Checks if there are updates for add-ons that are incompatible with the
118    * application update.
119    */
120   checkAddonsForUpdates: function() {
121     this.addons.forEach(function(aAddon) {
122+#ifdef TOR_BUNDLE_UPDATE
123+      let compatVersion = self.update.platformVersion;
124+#else
125+      let compatVersion = self.update.appVersion;
126+#endif
127       aAddon.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_DETECTED,
128-                         this.update.appVersion,
129+                         compatVersion,
130                          this.update.platformVersion);
131     }, this);
132   },
133 
134   /**
135    * See XPIProvider.jsm
136    */
137   onCompatibilityUpdateAvailable: function(aAddon) {
138@@ -433,18 +458,23 @@ appUpdater.prototype =
139       }
140     }
141   },
142 
143   /**
144    * See XPIProvider.jsm
145    */
146   onUpdateAvailable: function(aAddon, aInstall) {
147+#ifdef TOR_BUNDLE_UPDATE
148+    let compatVersion = self.update.platformVersion;
149+#else
150+    let compatVersion = self.update.appVersion;
151+#endif
152     if (!this.bs.isAddonBlocklisted(aAddon.id, aInstall.version,
153-                                    this.update.appVersion,
154+                                    compatVersion,
155                                     this.update.platformVersion)) {
156       // Compatibility or new version updates mean the same thing here.
157       this.onCompatibilityUpdateAvailable(aAddon);
158     }
159   },
160 
161   /**
162    * See XPIProvider.jsm
163diff --git a/configure.in b/configure.in
164index 988741e..04ce24e 100644
165--- a/configure.in
166+++ b/configure.in
167@@ -6192,16 +6192,30 @@ AC_SUBST(MOZ_UPDATE_CHANNEL)
168 MOZ_ARG_ENABLE_BOOL(update-packaging,
169 [  --enable-update-packaging
170                           Enable tools/update-packaging],
171     MOZ_UPDATE_PACKAGING=1,
172     MOZ_UPDATE_PACKAGING= )
173 AC_SUBST(MOZ_UPDATE_PACKAGING)
174 
175 dnl ========================================================
176+dnl Tor Additions
177+dnl ========================================================
178+MOZ_ARG_ENABLE_BOOL(tor-bundle-update,
179+[  --enable-tor-bundle-update
180+                          Enable Tor Browser Bundle update],
181+    TOR_BUNDLE_UPDATE=1,
182+    TOR_BUNDLE_UPDATE= )
183+if test -n "$TOR_BUNDLE_UPDATE"; then
184+    AC_DEFINE(TOR_BUNDLE_UPDATE)
185+fi
186+
187+AC_SUBST(TOR_BUNDLE_UPDATE)
188+
189+dnl ========================================================
190 dnl build the tests by default
191 dnl ========================================================
192 MOZ_ARG_DISABLE_BOOL(tests,
193 [  --disable-tests         Do not build test libraries & programs],
194     ENABLE_TESTS=,
195     ENABLE_TESTS=1 )
196 
197 dnl ========================================================
198@@ -8411,16 +8425,18 @@ if test -n "$LIBXUL_SDK"; then
199     MOZ_APP_STATIC_INI=
200 fi
201 AC_SUBST(MOZ_APP_STATIC_INI)
202 
203 AC_SUBST(MOZ_PKG_SPECIAL)
204 
205 AC_SUBST(MOZILLA_OFFICIAL)
206 
207+AC_SUBST(TOR_BUNDLE_UPDATE)
208+
209 if test "$MOZ_TELEMETRY_REPORTING"; then
210     AC_DEFINE(MOZ_TELEMETRY_REPORTING)
211 fi
212 
213 dnl win32 options
214 AC_SUBST(MOZ_MAPINFO)
215 AC_SUBST(MOZ_BROWSE_INFO)
216 AC_SUBST(MOZ_TOOLS_DIR)
217diff --git a/js/xpconnect/shell/xpcshell.cpp b/js/xpconnect/shell/xpcshell.cpp
218index b536238..c35e229 100644
219--- a/js/xpconnect/shell/xpcshell.cpp
220+++ b/js/xpconnect/shell/xpcshell.cpp
221@@ -2028,16 +2028,18 @@ XPCShellDirProvider::GetFile(const char *prop, bool *persistent,
222             NS_FAILED(file->AppendNative(NS_LITERAL_CSTRING("pref"))))
223             return NS_ERROR_FAILURE;
224         NS_ADDREF(*result = file);
225         return NS_OK;
226     } else if (mAppFile && !strcmp(prop, XRE_UPDATE_ROOT_DIR)) {
227         // For xpcshell, we pretend that the update root directory is always
228         // the same as the GRE directory, except for Windows, where we immitate
229         // the algorithm defined in nsXREDirProvider::GetUpdateRootDir.
230+        // To support Tor Browser Bundle updates from xpcshell, modify this
231+        // code to match changes in nsXREDirProvider::GetUpdateRootDir.
232         *persistent = true;
233 #ifdef XP_WIN
234         char appData[MAX_PATH] = {'\0'};
235         char path[MAX_PATH] = {'\0'};
236         LPITEMIDLIST pItemIDList;
237         if (FAILED(SHGetSpecialFolderLocation(NULL, CSIDL_LOCAL_APPDATA, &pItemIDList)) ||
238             FAILED(SHGetPathFromIDListA(pItemIDList, appData))) {
239             return NS_ERROR_FAILURE;
240diff --git a/toolkit/mozapps/update/nsUpdateService.js b/toolkit/mozapps/update/nsUpdateService.js
241index b9531fe..f2f370f 100644
242--- a/toolkit/mozapps/update/nsUpdateService.js
243+++ b/toolkit/mozapps/update/nsUpdateService.js
244@@ -6,17 +6,21 @@
245 # License, v. 2.0. If a copy of the MPL was not distributed with this
246 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
247 */
248 
249 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
250 Components.utils.import("resource://gre/modules/FileUtils.jsm");
251 Components.utils.import("resource://gre/modules/AddonManager.jsm");
252 Components.utils.import("resource://gre/modules/Services.jsm");
253+#ifdef BUILD_CTYPES
254+#ifdef XP_WIN
255 Components.utils.import("resource://gre/modules/ctypes.jsm");
256+#endif
257+#endif
258 
259 const Cc = Components.classes;
260 const Ci = Components.interfaces;
261 const Cr = Components.results;
262 
263 const UPDATESERVICE_CID = Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}");
264 const UPDATESERVICE_CONTRACTID = "@mozilla.org/updates/update-service;1";
265 
266@@ -62,20 +66,39 @@ const URI_BRAND_PROPERTIES      = "chrome://branding/locale/brand.properties";
267 const URI_UPDATES_PROPERTIES    = "chrome://mozapps/locale/update/updates.properties";
268 const URI_UPDATE_NS             = "http://www.mozilla.org/2005/app-update";
269 
270 const CATEGORY_UPDATE_TIMER               = "update-timer";
271 
272 const KEY_APPDIR          = "XCurProcD";
273 const KEY_GRED            = "GreD";
274 
275+#ifdef TOR_BUNDLE_UPDATE
276+#define NEED_ACCESS_TO_INST_ROOT_DIR
277+#ifdef XP_MACOSX
278+const APP_DIR_TO_INST_ROOT = 5; // number of directories to climb up
279+#define INST_ROOT_IS_ABOVE_APP_DIR
280+#else
281+const APP_DIR_TO_INST_ROOT = 1;
282+#define INST_ROOT_IS_ABOVE_APP_DIR
283+#endif
284+#elifdef XP_MACOSX
285+// On Mac, we store the Updated.app directory inside the bundle directory.
286+const APP_DIR_TO_INST_ROOT = 2;
287+#define INST_ROOT_IS_ABOVE_APP_DIR
288+#else
289+#define NEED_ACCESS_TO_INST_ROOT_DIR   // Windows and all others.
290+#endif
291+
292 #ifdef XP_WIN
293 #define USE_UPDROOT
294 #elifdef ANDROID
295 #define USE_UPDROOT
296+#elifdef TOR_BUNDLE_UPDATE
297+#define USE_UPDROOT
298 #endif
299 
300 #ifdef USE_UPDROOT
301 const KEY_UPDROOT         = "UpdRootD";
302 #endif
303 
304 const DIR_UPDATES         = "updates";
305 #ifdef XP_MACOSX
306@@ -197,16 +220,17 @@ XPCOMUtils.defineLazyGetter(this, "gOSVersion", function aus_gOSVersion() {
307   try {
308     osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version");
309   }
310   catch (e) {
311     LOG("gOSVersion - OS Version unknown: updates are not possible.");
312   }
313 
314   if (osVersion) {
315+#ifdef BUILD_CTYPES
316 #ifdef XP_WIN
317     const BYTE = ctypes.uint8_t;
318     const WORD = ctypes.uint16_t;
319     const DWORD = ctypes.uint32_t;
320     const WCHAR = ctypes.jschar;
321     const BOOL = ctypes.int;
322 
323     // This structure is described at:
324@@ -303,16 +327,17 @@ XPCOMUtils.defineLazyGetter(this, "gOSVersion", function aus_gOSVersion() {
325         } finally {
326           osVersion += " (" + arch + ")";
327         }
328       } finally {
329         kernel32.close();
330       }
331     }
332 #endif
333+#endif
334 
335     try {
336       osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")";
337     }
338     catch (e) {
339       // Not all platforms have a secondary widget library, so an error is nothing to worry about.
340     }
341     osVersion = encodeURIComponent(osVersion);
342@@ -375,16 +400,17 @@ XPCOMUtils.defineLazyGetter(this, "gCanApplyUpdates", function aus_gCanApplyUpda
343 
344     if (parseFloat(windowsVersion) >= 6) {
345       try {
346         var fileLocator = Cc["@mozilla.org/file/directory_service;1"].
347                           getService(Ci.nsIProperties);
348         // KEY_UPDROOT will fail and throw an exception if
349         // appDir is not under the Program Files, so we rely on that
350         var dir = fileLocator.get(KEY_UPDROOT, Ci.nsIFile);
351+LOG("TODO: For TBB, the above call will not throw. Need to test that updates work ok on Vista or later");
352         // appDir is under Program Files, so check if the user can elevate
353         userCanElevate = Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).
354                          userCanElevate;
355         LOG("gCanApplyUpdates - on Vista, userCanElevate: " + userCanElevate);
356       }
357       catch (ex) {
358         // When the installation directory is not under Program Files,
359         // fall through to checking if write access to the
360@@ -452,17 +478,17 @@ XPCOMUtils.defineLazyGetter(this, "gCanStageUpdates", function aus_gCanStageUpda
361   }
362 #endif
363 
364   try {
365     var updateTestFile = getInstallDirRoot();
366     updateTestFile.append(FILE_PERMS_TEST);
367     LOG("gCanStageUpdates - testing write access " + updateTestFile.path);
368     testWriteAccess(updateTestFile, true);
369-#ifndef XP_MACOSX
370+#ifdef NEED_ACCESS_TO_INST_ROOT_DIR
371     // On all platforms except Mac, we need to test the parent directory as well,
372     // as we need to be able to move files in that directory during the replacing
373     // step.
374     updateTestFile = getInstallDirRoot().parent;
375     updateTestFile.append(FILE_PERMS_TEST);
376     LOG("gCanStageUpdates - testing write access " + updateTestFile.path);
377     updateTestFile.createUnique(Ci.nsILocalFile.DIRECTORY_TYPE,
378                                 FileUtils.PERMS_DIRECTORY);
379@@ -535,16 +561,23 @@ function getPref(func, preference, defaultValue) {
380   try {
381     return Services.prefs[func](preference);
382   }
383   catch (e) {
384   }
385   return defaultValue;
386 }
387 
388+
389+// getTBBVersion() returns the Tor Browser Bundle version.
390+function getTBBVersion() {
391+  return getPref("getCharPref", "torbrowser.version", "0");
392+}
393+
394+
395 /**
396  * Convert a string containing binary values to hex.
397  */
398 function binaryToHex(input) {
399   var result = "";
400   for (var i = 0; i < input.length; ++i) {
401     var hex = input.charCodeAt(i).toString(16);
402     if (hex.length == 1)
403@@ -572,24 +605,29 @@ function getUpdateDirCreate(pathArray) {
404 #endif
405   return FileUtils.getDir(KEY_APPDIR, pathArray, true);
406 }
407 
408 /**
409  * Gets the root of the installation directory which is the application
410  * bundle directory on Mac OS X and the location of the application binary
411  * on all other platforms.
412+ * Returns the same directory as GetApplyToPathFromAppDir() within
413+ * toolkit/xre/nsUpdateDriver.cpp.
414  *
415  * @return nsIFile object for the directory
416  */
417 function getInstallDirRoot() {
418   var dir = FileUtils.getDir(KEY_APPDIR, [], false);
419-#ifdef XP_MACOSX
420-  // On Mac, we store the Updated.app directory inside the bundle directory.
421-  dir = dir.parent.parent;
422+#ifdef INST_ROOT_IS_ABOVE_APP_DIR
423+  var levelsToRemove = APP_DIR_TO_INST_ROOT;
424+  while (dir && dir.parent && (levelsToRemove > 0)) {
425+    dir = dir.parent;
426+    --levelsToRemove;
427+  }
428 #endif
429   return dir;
430 }
431 
432 /**
433  * Gets the file at the specified hierarchy under the update root directory.
434  * @param   pathArray
435  *          An array of path components to locate beneath the directory
436@@ -636,17 +674,27 @@ function getStatusTextFromCode(code, defaultCode) {
437  * @return The active updates directory, as a nsIFile object
438  */
439 function getUpdatesDir() {
440   // Right now, we only support downloading one patch at a time, so we always
441   // use the same target directory.
442   return getUpdateDirCreate([DIR_UPDATES, "0"]);
443 }
444 
445-#ifndef USE_UPDROOT
446+#ifdef TOR_BUNDLE_UPDATE
447+function getUpdatesDirInApplyToDir() {
448+  var dir = getInstallDirRoot();
449+  dir.append(UPDATED_DIR);
450+  dir.append(DIR_UPDATES);
451+  if (!dir.exists()) {
452+    dir.create(Ci.nsILocalFile.DIRECTORY_TYPE, 0755);
453+  }
454+  return dir;
455+}
456+#elifndef USE_UPDROOT
457 /**
458  * Get the Active Updates directory inside the directory where we apply the
459  * background updates.
460  * @return The active updates directory inside the updated directory, as a
461  *         nsIFile object.
462  */
463 function getUpdatesDirInApplyToDir() {
464   var dir = FileUtils.getDir(KEY_APPDIR, []);
465@@ -754,23 +802,31 @@ function cleanUpUpdatesDir(aBackgroundUpdate) {
466   var e = updateDir.directoryEntries;
467   while (e.hasMoreElements()) {
468     var f = e.getNext().QueryInterface(Ci.nsIFile);
469     // Preserve the last update log file for debugging purposes
470     if (f.leafName == FILE_UPDATE_LOG) {
471       var dir;
472       try {
473 #ifdef USE_UPDROOT
474+#ifdef TOR_BUNDLE_UPDATE
475+        if (aBackgroundUpdate) {
476+          dir = getUpdatesDirInApplyToDir();
477+        } else {
478+          dir = f.parent.parent;
479+        }
480+#else
481         // If we're on a platform which uses the update root directory, the log
482         // files are written outside of the application directory, so they will
483         // not get overwritten when we replace the directories after a
484         // background update.  Therefore, we don't need any special logic for
485         // that case here.
486         // Note that this currently only applies to Windows.
487         dir = f.parent.parent;
488+#endif
489 #else
490         // If we don't use the update root directory, the log files are written
491         // inside the application directory.  In that case, we want to write
492         // the log files to the updated directory in the case of background
493         // updates, so that they would be available when we replace that
494         // directory with the application directory later on.
495         if (aBackgroundUpdate) {
496           dir = getUpdatesDirInApplyToDir();
497@@ -839,17 +895,17 @@ function cleanupActiveUpdate() {
498  * update url. The update.locale file can be located in the application
499  * directory or the GRE directory with preference given to it being located in
500  * the application directory.
501  */
502 function getLocale() {
503   if (gLocale)
504     return gLocale;
505 
506-  for each (res in ['app', 'gre']) {
507+  for each (var res in ['app', 'gre']) {
508     var channel = Services.io.newChannel("resource://" + res + "/" + FILE_UPDATE_LOCALE, null, null);
509     try {
510       var inputStream = channel.open();
511       gLocale = readStringFromInputStream(inputStream);
512     } catch(e) {}
513     if (gLocale)
514       break;
515   }
516@@ -1862,19 +1918,20 @@ UpdateService.prototype = {
517     // Choose the newest of the available minor and major updates.
518     var majorUpdate = null;
519     var minorUpdate = null;
520     var vc = Services.vc;
521 
522     updates.forEach(function(aUpdate) {
523       // Ignore updates for older versions of the application and updates for
524       // the same version of the application with the same build ID.
525-      if (vc.compare(aUpdate.appVersion, Services.appinfo.version) < 0 ||
526-          vc.compare(aUpdate.appVersion, Services.appinfo.version) == 0 &&
527-          aUpdate.buildID == Services.appinfo.appBuildID) {
528+      var tbbVersion = getTBBVersion();
529+      var rc = vc.compare(aUpdate.appVersion, tbbVersion);
530+      if (rc < 0 || ((rc == 0) &&
531+                     (aUpdate.buildID == Services.appinfo.appBuildID))) {
532         LOG("UpdateService:selectUpdate - skipping update because the " +
533             "update's application version is less than the current " +
534             "application version");
535         return;
536       }
537 
538       // Skip the update if the user responded with "never" to this update's
539       // application version and the update specifies showNeverForVersion
540@@ -1995,17 +2052,17 @@ UpdateService.prototype = {
541       var status = this.downloadUpdate(update, true);
542       if (status == STATE_NONE)
543         cleanupActiveUpdate();
544       return;
545     }
546 
547     // Only check add-on compatibility when the version changes.
548     if (update.appVersion &&
549-        Services.vc.compare(update.appVersion, Services.appinfo.version) != 0) {
550+        Services.vc.compare(update.appVersion, getTBBVersion()) != 0) {
551       this._update = update;
552       this._checkAddonCompatibility();
553     }
554     else {
555       LOG("UpdateService:_selectAndInstallUpdate - no need to show prompt, " +
556           "just download the update");
557       var status = this.downloadUpdate(update, true);
558       if (status == STATE_NONE)
559@@ -2023,16 +2080,21 @@ UpdateService.prototype = {
560     try {
561       var hotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID);
562     }
563     catch (e) { }
564 
565     // Get all the installed add-ons
566     var self = this;
567     AddonManager.getAllAddons(function(addons) {
568+#ifdef TOR_BUNDLE_UPDATE
569+      let compatVersion = self._update.platformVersion;
570+#else
571+      let compatVersion = self._update.appVersion;
572+#endif
573       self._incompatibleAddons = [];
574       addons.forEach(function(addon) {
575         // Protect against code that overrides the add-ons manager and doesn't
576         // implement the isCompatibleWith or the findUpdates method.
577         if (!("isCompatibleWith" in addon) || !("findUpdates" in addon)) {
578           let errMsg = "Add-on doesn't implement either the isCompatibleWith " +
579                        "or the findUpdates method!";
580           if (addon.id)
581@@ -2051,17 +2113,17 @@ UpdateService.prototype = {
582         // getting the scope property of a plugin breaks in some environments
583         // (see bug 566787). The hotfix add-on is also ignored as it shouldn't
584         // block the user from upgrading.
585         try {
586           if (addon.type != "plugin" && addon.id != hotfixID &&
587               !addon.appDisabled && !addon.userDisabled &&
588               addon.scope != AddonManager.SCOPE_APPLICATION &&
589               addon.isCompatible &&
590-              !addon.isCompatibleWith(self._update.appVersion,
591+              !addon.isCompatibleWith(compatVersion,
592                                       self._update.platformVersion))
593             self._incompatibleAddons.push(addon);
594         }
595         catch (e) {
596           Components.utils.reportError(e);
597         }
598       });
599 
600@@ -2087,17 +2149,17 @@ UpdateService.prototype = {
601 #          only as a hidden option for those that want it.
602        */
603         self._updateCheckCount = self._incompatibleAddons.length;
604         LOG("UpdateService:_checkAddonCompatibility - checking for " +
605             "incompatible add-ons");
606 
607         self._incompatibleAddons.forEach(function(addon) {
608           addon.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_DETECTED,
609-                            this._update.appVersion, this._update.platformVersion);
610+                            compatVersion, this._update.platformVersion);
611         }, self);
612       }
613       else {
614         LOG("UpdateService:_checkAddonCompatibility - no need to show prompt, " +
615             "just download the update");
616         var status = self.downloadUpdate(self._update, true);
617         if (status == STATE_NONE)
618           cleanupActiveUpdate();
619@@ -2123,18 +2185,23 @@ UpdateService.prototype = {
620     if (getPref("getIntPref", PREF_APP_UPDATE_INCOMPATIBLE_MODE, 0) == 1)
621       return;
622 
623     // If the new version of this add-on is blocklisted for the new application
624     // then it isn't a valid update and the user should still be warned that
625     // the add-on will become incompatible.
626     let bs = Cc["@mozilla.org/extensions/blocklist;1"].
627              getService(Ci.nsIBlocklistService);
628+#ifdef TOR_BUNDLE_UPDATE
629+    let compatVersion = self._update.platformVersion;
630+#else
631+    let compatVersion = self._update.appVersion;
632+#endif
633     if (bs.isAddonBlocklisted(addon.id, install.version,
634-                              gUpdates.update.appVersion,
635+                              compatVersion,
636                               gUpdates.update.platformVersion))
637       return;
638 
639     // Compatibility or new version updates mean the same thing here.
640     this.onCompatibilityUpdateAvailable(addon);
641   },
642 
643   onUpdateFinished: function(addon) {
644@@ -2219,24 +2286,25 @@ UpdateService.prototype = {
645   downloadUpdate: function AUS_downloadUpdate(update, background) {
646     if (!update)
647       throw Cr.NS_ERROR_NULL_POINTER;
648 
649     // Don't download the update if the update's version is less than the
650     // current application's version or the update's version is the same as the
651     // application's version and the build ID is the same as the application's
652     // build ID.
653+    var tbbVersion = getTBBVersion();
654     if (update.appVersion &&
655-        (Services.vc.compare(update.appVersion, Services.appinfo.version) < 0 ||
656+        (Services.vc.compare(update.appVersion, tbbVersion) < 0 ||
657          update.buildID && update.buildID == Services.appinfo.appBuildID &&
658-         update.appVersion == Services.appinfo.version)) {
659+         update.appVersion == tbbVersion)) {
660       LOG("UpdateService:downloadUpdate - canceling download of update since " +
661           "it is for an earlier or same application version and build ID.\n" +
662-          "current application version: " + Services.appinfo.version + "\n" +
663-          "update application version : " + update.appVersion + "\n" +
664+          "current Tor bundle version: " + tbbVersion + "\n" +
665+          "update Tor bundle version : " + update.appVersion + "\n" +
666           "current build ID: " + Services.appinfo.appBuildID + "\n" +
667           "update build ID : " + update.buildID);
668       cleanupActiveUpdate();
669       return STATE_NONE;
670     }
671 
672     // If a download request is in progress vs. a download ready to resume
673     if (this.isDownloading) {
674@@ -2244,17 +2312,17 @@ UpdateService.prototype = {
675           background == this._downloader.background) {
676         LOG("UpdateService:downloadUpdate - no support for downloading more " +
677             "than one update at a time");
678         return readStatusFile(getUpdatesDir());
679       }
680       this._downloader.cancel();
681     }
682     // Set the previous application version prior to downloading the update.
683-    update.previousAppVersion = Services.appinfo.version;
684+    update.previousAppVersion = tbbVersion;
685     this._downloader = new Downloader(background);
686     return this._downloader.downloadUpdate(update);
687   },
688 
689   applyUpdateInBackground: function AUS_applyUpdateInBackground(update) {
690     // If we can't stage an update, then just bail out!
691     if (!gCanStageUpdates) {
692       return;
693@@ -2655,17 +2723,17 @@ Checker.prototype = {
694     }
695 
696     if (!url || url == "") {
697       LOG("Checker:getUpdateURL - update URL not defined");
698       return null;
699     }
700 
701     url = url.replace(/%PRODUCT%/g, Services.appinfo.name);
702-    url = url.replace(/%VERSION%/g, Services.appinfo.version);
703+    url = url.replace(/%VERSION%/g, getTBBVersion());
704     url = url.replace(/%BUILD_ID%/g, Services.appinfo.appBuildID);
705     url = url.replace(/%BUILD_TARGET%/g, Services.appinfo.OS + "_" + gABI);
706     url = url.replace(/%OS_VERSION%/g, gOSVersion);
707     if (/%LOCALE%/.test(url))
708       url = url.replace(/%LOCALE%/g, getLocale());
709     url = url.replace(/%CHANNEL%/g, getUpdateChannel());
710     url = url.replace(/%PLATFORM_VERSION%/g, Services.appinfo.platformVersion);
711     url = url.replace(/%DISTRIBUTION%/g,
712diff --git a/toolkit/mozapps/update/nsUpdateServiceStub.js b/toolkit/mozapps/update/nsUpdateServiceStub.js
713index ce3a4d5..e9f2f8c 100644
714--- a/toolkit/mozapps/update/nsUpdateServiceStub.js
715+++ b/toolkit/mozapps/update/nsUpdateServiceStub.js
716@@ -13,16 +13,18 @@ const DIR_UPDATES         = "updates";
717 const FILE_UPDATE_STATUS  = "update.status";
718 
719 const KEY_APPDIR          = "XCurProcD";
720 
721 #ifdef XP_WIN
722 #define USE_UPDROOT
723 #elifdef ANDROID
724 #define USE_UPDROOT
725+#elifdef TOR_BUNDLE_UPDATE
726+#define USE_UPDROOT
727 #endif
728 
729 #ifdef USE_UPDROOT
730 const KEY_UPDROOT         = "UpdRootD";
731 #endif
732 
733 /**
734 #  Gets the specified directory at the specified hierarchy under the update root
735diff --git a/toolkit/mozapps/update/updater/Makefile.in b/toolkit/mozapps/update/updater/Makefile.in
736index 72ea1d6..62066f8 100644
737--- a/toolkit/mozapps/update/updater/Makefile.in
738+++ b/toolkit/mozapps/update/updater/Makefile.in
739@@ -92,16 +92,20 @@ endif
740 
741 include $(topsrcdir)/config/rules.mk
742 
743 DEFINES += -DNS_NO_XPCOM \
744   -DMAR_CHANNEL_ID='"$(MAR_CHANNEL_ID)"' \
745   -DMOZ_APP_VERSION='"$(MOZ_APP_VERSION)"' \
746   $(NULL)
747 
748+ifdef TOR_BUNDLE_UPDATE
749+DEFINES += -DTOR_BUNDLE_UPDATE
750+endif
751+
752 ifdef _MSC_VER
753 WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
754 WIN32_EXE_LDFLAGS += -DELAYLOAD:wsock32.dll -DELAYLOAD:crypt32.dll -DELAYLOAD:userenv.dll
755 endif
756 
757 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
758 libs:: updater.png
759        $(NSINSTALL) -D $(DIST)/bin/icons
760diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp
761index 2aa67cf..9da2551 100644
762--- a/toolkit/mozapps/update/updater/updater.cpp
763+++ b/toolkit/mozapps/update/updater/updater.cpp
764@@ -1798,29 +1798,52 @@ CopyInstallDirToDestDir()
765   // levels above it.  This is effectively skipping over "updates/0".
766   NS_tchar installDir[MAXPATHLEN];
767   if (!GetInstallationDir(installDir)) {
768     return NO_INSTALLDIR_ERROR;
769   }
770 
771   // These files should not be copied over to the updated app
772 #ifdef XP_WIN
773-#define SKIPLIST_COUNT 3
774+  #ifdef TOR_BUNDLE_UPDATE
775+    #define SKIPLIST_COUNT 5
776+  #else
777+    #define SKIPLIST_COUNT 3
778+  #endif
779 #else
780-#define SKIPLIST_COUNT 2
781+  #ifdef TOR_BUNDLE_UPDATE
782+    #define SKIPLIST_COUNT 4
783+  #else
784+    #define SKIPLIST_COUNT 2
785+  #endif
786 #endif
787   copy_recursive_skiplist<SKIPLIST_COUNT> skiplist;
788 #ifdef XP_MACOSX
789   skiplist.append(0, installDir, NS_T("Updated.app"));
790+#ifdef TOR_BUNDLE_UPDATE
791+  skiplist.append(1, installDir, NS_T("updates/0"));
792+  skiplist.append(2, installDir, NS_T("Data/Browser/profile.default/.parentlock"));
793+  skiplist.append(3, installDir, NS_T("Data/Tor/lock"));
794+#else
795   skiplist.append(1, installDir, NS_T("Contents/MacOS/updates/0"));
796+#endif
797 #else
798   skiplist.append(0, installDir, NS_T("updated"));
799   skiplist.append(1, installDir, NS_T("updates/0"));
800+#ifdef TOR_BUNDLE_UPDATE
801+#ifdef XP_UNIX
802+  skiplist.append(2, installDir, NS_T("Data/Browser/profile.default/.parentlock"));
803+#else
804+  skiplist.append(2, installDir, NS_T("Data/Browser/profile.default/parent.lock"));
805+#endif
806+  skiplist.append(3, installDir, NS_T("Data/Tor/lock"));
807+#endif
808 #ifdef XP_WIN
809-  skiplist.append(2, installDir, NS_T("updated.update_in_progress.lock"));
810+  skiplist.append(SKIPLIST_COUNT - 1, installDir,
811+                  NS_T("updated.update_in_progress.lock"));
812 #endif
813 #endif
814 
815   return ensure_copy_recursive(installDir, gDestinationPath, skiplist);
816 }
817 
818 /*
819  * Replace the application installation directory with the destination
820diff --git a/toolkit/xre/Makefile.in b/toolkit/xre/Makefile.in
821index ae28d72..1f65957 100644
822--- a/toolkit/xre/Makefile.in
823+++ b/toolkit/xre/Makefile.in
824@@ -114,16 +114,20 @@ SHARED_LIBRARY_LIBS += \
825 ifdef MOZ_UPDATER
826 ifneq (android,$(MOZ_WIDGET_TOOLKIT))
827 SHARED_LIBRARY_LIBS += \
828   ../mozapps/update/common/$(LIB_PREFIX)updatecommon.$(LIB_SUFFIX) \
829   $(NULL)
830 endif
831 endif
832 
833+ifdef TOR_BUNDLE_UPDATE
834+DEFINES += -DTOR_BUNDLE_UPDATE
835+endif
836+
837 ifdef MOZ_ENABLE_XREMOTE
838 SHARED_LIBRARY_LIBS += $(DEPTH)/widget/xremoteclient/$(LIB_PREFIX)xremote_client_s.$(LIB_SUFFIX)
839 LOCAL_INCLUDES += -I$(topsrcdir)/widget/xremoteclient
840 endif
841 
842 ifdef MOZ_CRASHREPORTER
843 SHARED_LIBRARY_LIBS += $(DEPTH)/toolkit/crashreporter/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX)
844 ifeq ($(OS_ARCH),WINNT)
845diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
846index fc2446a..ea12767 100644
847--- a/toolkit/xre/nsAppRunner.cpp
848+++ b/toolkit/xre/nsAppRunner.cpp
849@@ -177,16 +177,20 @@ using mozilla::unused;
850 
851 #ifdef MOZ_CRASHREPORTER
852 #include "nsExceptionHandler.h"
853 #include "nsICrashReporter.h"
854 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
855 #include "nsIPrefService.h"
856 #endif
857 
858+#ifdef TOR_BUNDLE_UPDATE
859+#include "mozilla/Preferences.h"
860+#endif
861+
862 #include "base/command_line.h"
863 
864 #include "mozilla/FunctionTimer.h"
865 
866 #ifdef MOZ_WIDGET_ANDROID
867 #include "AndroidBridge.h"
868 #endif
869 
870@@ -3412,22 +3416,32 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
871   // Support for processing an update and exiting. The MOZ_PROCESS_UPDATES
872   // environment variable will be part of the updater's environment and the
873   // application that is relaunched by the updater. When the application is
874   // relaunched by the updater it will be removed below and the application
875   // will exit.
876   if (CheckArg("process-updates")) {
877     SaveToEnv("MOZ_PROCESS_UPDATES=1");
878   }
879+nsCAutoString tmpPath;
880+updRoot->GetNativePath(tmpPath);
881+printf("AppRunner calling ProcessUpdates - updRoot is %s\n", tmpPath.get());
882+  nsCAutoString compatVersion;
883+#ifdef TOR_BUNDLE_UPDATE
884+  // TODO: cannot get prefs yet.  For now, hard-code torbrowser.version
885+  compatVersion = "3.0a0";
886+#else
887+  compatVersion = mAppData->version;
888+#endif
889   ProcessUpdates(mDirProvider.GetGREDir(),
890                  mDirProvider.GetAppDir(),
891                  updRoot,
892                  gRestartArgc,
893                  gRestartArgv,
894-                 mAppData->version);
895+                 compatVersion.get());
896   if (EnvHasValue("MOZ_PROCESS_UPDATES")) {
897     SaveToEnv("MOZ_PROCESS_UPDATES=");
898     *aExitFlag = true;
899     return 0;
900   }
901 #endif
902 
903   rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc));
904diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp
905index 9767918..3dc5b6a 100644
906--- a/toolkit/xre/nsUpdateDriver.cpp
907+++ b/toolkit/xre/nsUpdateDriver.cpp
908@@ -39,16 +39,26 @@
909 #elif defined(XP_OS2)
910 # include <unistd.h>
911 # define INCL_DOSFILEMGR
912 # include <os2.h>
913 #elif defined(XP_UNIX)
914 # include <unistd.h>
915 #endif
916 
917+#ifdef TOR_BUNDLE_UPDATE
918+#ifdef XP_MACOSX
919+#define APP_DIR_TO_INST_ROOT 5
920+#else
921+#define APP_DIR_TO_INST_ROOT 1
922+#endif
923+#elif defined(XP_MACOSX)
924+#define APP_DIR_TO_INST_ROOT 2
925+#endif
926+
927 //
928 // We use execv to spawn the updater process on all UNIX systems except Mac OSX
929 // since it is known to cause problems on the Mac.  Windows has execv, but it
930 // is a faked implementation that doesn't really replace the current process.
931 // Instead it spawns a new process, so we gain nothing from using execv on
932 // Windows.
933 //
934 // On platforms where we are not calling execv, we may need to make the
935@@ -103,16 +113,26 @@ GetCurrentWorkingDir(char *buf, size_t size)
936   strncpy(buf, path.get(), size);
937 #else
938   if(!getcwd(buf, size))
939     return NS_ERROR_FAILURE;
940 #endif
941   return NS_OK;
942 }
943 
944+
945+static void
946+dump_argv(const char *aPrefix, char **argv, int argc)
947+{
948+  printf("%s - %d args\n", aPrefix, argc);
949+  for (int i = 0; i < argc; ++i)
950+    printf("  %d: %s\n", i, argv[i]);
951+}
952+
953+
954 #if defined(XP_MACOSX)
955 // This is a copy of OS X's XRE_GetBinaryPath from nsAppRunner.cpp with the
956 // gBinaryPath check removed so that the updater can reload the stub executable
957 // instead of xulrunner-bin. See bug 349737.
958 static nsresult
959 GetXULRunnerStubPath(const char* argv0, nsIFile* *aResult)
960 {
961   // Works even if we're not bundled.
962@@ -225,16 +245,74 @@ GetUpdateStatus(nsIFile* dir, nsCOMPtr<nsIFile> &statusFile)
963       if (!strncmp(buf, kApplied, sizeof(kApplied) - 1)) {
964         return eAppliedUpdate;
965       }
966     }
967   }
968   return eNoUpdateAction;
969 }
970 
971+// If isUsingRestart, updates are not being applied in the background and
972+// therefore this function does not append "Updated.app" / "updated",
973+// Pass true for checkExists to ensure that the "apply to" directory exists.
974+static nsresult
975+GetApplyToPathFromAppDir(nsIFile *appDir, bool isUsingRestart, bool checkExists,
976+                         nsCString &applyToPath)
977+{
978+  // Get the directory to which the update will be applied. On Mac OSX we need
979+  // to apply the update to the Updated.app directory under the Foo.app
980+  // directory which is the parent of the parent of the appDir. On other
981+  // platforms we will just apply to the appDir/updated.
982+  // Returns the same directory as getInstallDirRoot() within
983+  // toolkit/mozapps/update/nsUpdateService.js
984+  nsCOMPtr<nsIFile> applyToDir = appDir;
985+#ifdef APP_DIR_TO_INST_ROOT
986+  int levelsToRemove = APP_DIR_TO_INST_ROOT;
987+  while (applyToDir && (levelsToRemove > 0)) {
988+    nsCOMPtr<nsIFile> tmpDir;
989+    nsresult rv = applyToDir->GetParent(getter_AddRefs(tmpDir));
990+    NS_ENSURE_SUCCESS(rv, rv);
991+
992+    applyToDir = tmpDir;
993+    --levelsToRemove;
994+  }
995+#endif
996+
997+  if (!isUsingRestart) {
998+#if defined(XP_MACOSX)
999+    NS_NAMED_LITERAL_CSTRING(updatedDirName, "Updated.app");
1000+#else
1001+    NS_NAMED_LITERAL_CSTRING(updatedDirName, "updated");
1002+#endif
1003+    if (!GetFile(applyToDir, updatedDirName, applyToDir))
1004+      return NS_ERROR_FAILURE;
1005+  }
1006+
1007+#if defined(XP_WIN)
1008+  nsAutoString applyToDirW;
1009+  nsresult rv = applyToDir->GetPath(applyToDirW);
1010+
1011+  applyToPath = NS_ConvertUTF16toUTF8(applyToDirW);
1012+#else
1013+  nsresult rv = applyToDir->GetNativePath(applyToPath);
1014+#endif
1015+  NS_ENSURE_SUCCESS(rv, rv);
1016+
1017+  if (checkExists) {
1018+    // Make sure that the updated directory exists
1019+    bool applyToDirExists = false;
1020+    applyToDir->Exists(&applyToDirExists);
1021+    if (!applyToDirExists) {
1022+      return NS_ERROR_FILE_NOT_FOUND;
1023+    }
1024+  }
1025+
1026+  return NS_OK;
1027+}
1028+
1029 static bool
1030 GetVersionFile(nsIFile *dir, nsCOMPtr<nsIFile> &result)
1031 {
1032   return GetFile(dir, NS_LITERAL_CSTRING("update.version"), result);
1033 }
1034 
1035 // Compares the current application version with the update's application
1036 // version.
1037@@ -258,16 +336,17 @@ IsOlderVersion(nsIFile *versionFile, const char *appVersion)
1038     buf[n - 1] = '\0';
1039 
1040   // If the update xml doesn't provide the application version the file will
1041   // contain the string "null" and it is assumed that the update is not older.
1042   const char kNull[] = "null";
1043   if (strncmp(buf, kNull, sizeof(kNull) - 1) == 0)
1044     return false;
1045 
1046+printf("IsOlderVersion checking appVersion %s against updateVersion %s\n", appVersion, buf);
1047   if (mozilla::Version(appVersion) > buf)
1048     return true;
1049 
1050   return false;
1051 }
1052 
1053 static bool
1054 CopyFileIntoUpdateDir(nsIFile *parentDir, const char *leafName, nsIFile *updateDir)
1055@@ -412,71 +491,32 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
1056 
1057   nsCAutoString updaterPath;
1058   rv = updater->GetNativePath(updaterPath);
1059   if (NS_FAILED(rv))
1060     return;
1061 
1062 #endif
1063 
1064-  // Get the directory to which the update will be applied. On Mac OSX we need
1065-  // to apply the update to the Updated.app directory under the Foo.app
1066-  // directory which is the parent of the parent of the appDir. On other
1067-  // platforms we will just apply to the appDir/updated.
1068-  nsCOMPtr<nsIFile> updatedDir;
1069-#if defined(XP_MACOSX)
1070-  nsCAutoString applyToDir;
1071-  {
1072-    nsCOMPtr<nsIFile> parentDir1, parentDir2;
1073-    rv = appDir->GetParent(getter_AddRefs(parentDir1));
1074-    if (NS_FAILED(rv))
1075-      return;
1076-    rv = parentDir1->GetParent(getter_AddRefs(parentDir2));
1077-    if (NS_FAILED(rv))
1078-      return;
1079-    if (!GetFile(parentDir2, NS_LITERAL_CSTRING("Updated.app"), updatedDir))
1080-      return;
1081-    rv = updatedDir->GetNativePath(applyToDir);
1082-  }
1083-#else
1084-  if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir))
1085-    return;
1086-#if defined(XP_WIN)
1087-  nsAutoString applyToDirW;
1088-  rv = updatedDir->GetPath(applyToDirW);
1089-
1090-  NS_ConvertUTF16toUTF8 applyToDir(applyToDirW);
1091-#else
1092+  // Get the "apply to" path.
1093   nsCAutoString applyToDir;
1094-  rv = updatedDir->GetNativePath(applyToDir);
1095-#endif
1096-#endif
1097+  rv = GetApplyToPathFromAppDir(appDir, false, true, applyToDir);
1098   if (NS_FAILED(rv))
1099     return;
1100 
1101-  // Make sure that the updated directory exists
1102-  bool updatedDirExists = false;
1103-  updatedDir->Exists(&updatedDirExists);
1104-  if (!updatedDirExists) {
1105-    return;
1106-  }
1107-
1108 #if defined(XP_WIN)
1109   nsAutoString updateDirPathW;
1110   rv = updateDir->GetPath(updateDirPathW);
1111 
1112   NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW);
1113 #else
1114   nsCAutoString updateDirPath;
1115   rv = updateDir->GetNativePath(updateDirPath);
1116 #endif
1117 
1118-  if (NS_FAILED(rv))
1119-    return;
1120-
1121   // Get the current working directory.
1122   char workingDirPath[MAXPATHLEN];
1123   rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath));
1124   if (NS_FAILED(rv))
1125     return;
1126 
1127   // Construct the PID argument for this process.  If we are using execv, then
1128   // we pass "0" which is then ignored by the updater.
1129@@ -608,59 +648,19 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
1130   
1131   nsCAutoString updaterPath;
1132   rv = updater->GetNativePath(updaterPath);
1133   if (NS_FAILED(rv))
1134     return;
1135 
1136 #endif
1137 
1138-  // Get the directory to which the update will be applied. On Mac OSX we need
1139-  // to apply the update to the Updated.app directory under the Foo.app
1140-  // directory which is the parent of the parent of the appDir. On other
1141-  // platforms we will just apply to the appDir/updated.
1142-  nsCOMPtr<nsIFile> updatedDir;
1143-#if defined(XP_MACOSX)
1144-  nsCAutoString applyToDir;
1145-  {
1146-    nsCOMPtr<nsIFile> parentDir1, parentDir2;
1147-    rv = appDir->GetParent(getter_AddRefs(parentDir1));
1148-    if (NS_FAILED(rv))
1149-      return;
1150-    rv = parentDir1->GetParent(getter_AddRefs(parentDir2));
1151-    if (NS_FAILED(rv))
1152-      return;
1153-    if (restart) {
1154-      // Use the correct directory if we're not applying the update in the
1155-      // background.
1156-      rv = parentDir2->GetNativePath(applyToDir);
1157-    } else {
1158-      if (!GetFile(parentDir2, NS_LITERAL_CSTRING("Updated.app"), updatedDir))
1159-        return;
1160-      rv = updatedDir->GetNativePath(applyToDir);
1161-    }
1162-  }
1163-#else
1164-  if (restart) {
1165-    // Use the correct directory if we're not applying the update in the
1166-    // background.
1167-    updatedDir = do_QueryInterface(appDir);
1168-  } else if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) {
1169-    return;
1170-  }
1171-#if defined(XP_WIN)
1172-  nsAutoString applyToDirW;
1173-  rv = updatedDir->GetPath(applyToDirW);
1174-
1175-  NS_ConvertUTF16toUTF8 applyToDir(applyToDirW);
1176-#else
1177+  // Get the "apply to" directory.
1178   nsCAutoString applyToDir;
1179-  rv = updatedDir->GetNativePath(applyToDir);
1180-#endif
1181-#endif
1182+  rv = GetApplyToPathFromAppDir(appDir, restart, false, applyToDir);
1183   if (NS_FAILED(rv))
1184     return;
1185 
1186 #if defined(XP_WIN)
1187   nsAutoString updateDirPathW;
1188   rv = updateDir->GetPath(updateDirPathW);
1189 
1190   NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW);
1191@@ -738,20 +738,22 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
1192     return;
1193   }
1194 
1195   if (restart) {
1196     // We are going to process an update so we should exit now
1197     _exit(0);
1198   }
1199 #elif defined(XP_MACOSX)
1200+dump_argv("ApplyUpdate before SetupMacCommandLine", argv, argc);
1201   CommandLineServiceMac::SetupMacCommandLine(argc, argv, true);
1202   // LaunchChildMac uses posix_spawnp and prefers the current
1203   // architecture when launching. It doesn't require a
1204   // null-terminated string but it doesn't matter if we pass one.
1205+dump_argv("ApplyUpdate after SetupMacCommandLine", argv, argc);
1206   LaunchChildMac(argc, argv, 0, outpid);
1207   if (restart) {
1208     exit(0);
1209   }
1210 #else
1211   *outpid = PR_CreateProcess(updaterPath.get(), argv, NULL, NULL);
1212   if (restart) {
1213     exit(0);
1214@@ -779,16 +781,19 @@ WaitForProcess(ProcessType pt)
1215 nsresult
1216 ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir,
1217                int argc, char **argv, const char *appVersion,
1218                bool restart, ProcessType *pid)
1219 {
1220   nsresult rv;
1221 
1222   nsCOMPtr<nsIFile> updatesDir;
1223+nsCAutoString path;
1224+updRootDir->GetNativePath(path);
1225+printf("ProcessUpdates updateRootDir: %s appVersion: %s\n", path.get(), appVersion);
1226   rv = updRootDir->Clone(getter_AddRefs(updatesDir));
1227   if (NS_FAILED(rv))
1228     return rv;
1229 
1230   rv = updatesDir->AppendNative(NS_LITERAL_CSTRING("updates"));
1231   if (NS_FAILED(rv))
1232     return rv;
1233 
1234@@ -826,40 +831,48 @@ ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir,
1235     if (backgroundUpdate && *backgroundUpdate) {
1236       restart = false;
1237       pid = &dummyPID;
1238     }
1239   }
1240 
1241   nsCOMPtr<nsIFile> statusFile;
1242   UpdateStatus status = GetUpdateStatus(updatesDir, statusFile);
1243+printf("ProcessUpdates status: %d\n", status);
1244+updatesDir->GetNativePath(path);
1245+printf("ProcessUpdates updatesDir: %s\n", path.get());
1246   switch (status) {
1247   case ePendingUpdate:
1248+printf("pending update\n");
1249   case ePendingService: {
1250+printf("pending service\n");
1251     nsCOMPtr<nsIFile> versionFile;
1252     // Remove the update if the update application version file doesn't exist
1253     // or if the update's application version is less than the current
1254     // application version.
1255     if (!GetVersionFile(updatesDir, versionFile) ||
1256         IsOlderVersion(versionFile, appVersion)) {
1257       updatesDir->Remove(true);
1258     } else {
1259       ApplyUpdate(greDir, updatesDir, statusFile,
1260                   appDir, argc, argv, restart, pid);
1261     }
1262     break;
1263   }
1264   case eAppliedUpdate:
1265+printf("applied update\n");
1266   case eAppliedService:
1267     // An update was applied in the background, so we need to switch to using
1268     // it now.
1269+printf("applied svc\n");
1270     SwitchToUpdatedApp(greDir, updatesDir, statusFile,
1271                        appDir, argc, argv);
1272     break;
1273   case eNoUpdateAction:
1274+printf("no update action\n");
1275     // We don't need to do any special processing here, we'll just continue to
1276     // startup the application.
1277     break;
1278   }
1279 
1280   return NS_OK;
1281 }
1282 
1283@@ -888,17 +901,23 @@ nsUpdateProcessor::ProcessUpdate(nsIUpdate* aUpdate)
1284     nsresult rv = dirProvider->GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
1285                                        getter_AddRefs(updRoot));
1286     // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
1287     if (NS_FAILED(rv))
1288       updRoot = dirProvider->GetAppDir();
1289 
1290     greDir = dirProvider->GetGREDir();
1291     appDir = dirProvider->GetAppDir();
1292+#ifdef TOR_BUNDLE_UPDATE
1293+    mozilla::Preferences::GetDefaultRootBranch()->
1294+                 GetCharPref("torbrowser.version", getter_Copies(appVersion));
1295+#else
1296     appVersion = gAppData->version;
1297+#endif
1298+    printf("nsUpdateProcessor::ProcessUpdate 2a - appVersion is %s\n", appVersion.get());
1299     argc = gRestartArgc;
1300     argv = gRestartArgv;
1301   } else {
1302     // In the xpcshell environment, the usual XRE_main is not run, so things
1303     // like dirProvider and gAppData do not exist.  This code path accesses
1304     // XPCOM (which is not available in the previous code path) in order to get
1305     // the same information.
1306     nsCOMPtr<nsIProperties> ds =
1307@@ -912,16 +931,18 @@ nsUpdateProcessor::ProcessUpdate(nsIUpdate* aUpdate)
1308     NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the GRE dir");
1309     appDir = greDir;
1310 
1311     rv = ds->Get(XRE_UPDATE_ROOT_DIR, NS_GET_IID(nsIFile),
1312                  getter_AddRefs(updRoot));
1313     if (NS_FAILED(rv))
1314       updRoot = appDir;
1315 
1316+    // To support Tor Browser Bundle updates from xpcshell, modify the
1317+    // following code to retrieve the torbrowser.version pref. value.
1318     nsCOMPtr<nsIXULAppInfo> appInfo =
1319       do_GetService("@mozilla.org/xre/app-info;1");
1320     if (appInfo) {
1321       rv = appInfo->GetVersion(appVersion);
1322       NS_ENSURE_SUCCESS(rv, rv);
1323     } else {
1324       appVersion = MOZ_APP_VERSION;
1325     }
1326diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp
1327index ecf56c2..1b836b7 100644
1328--- a/toolkit/xre/nsXREDirProvider.cpp
1329+++ b/toolkit/xre/nsXREDirProvider.cpp
1330@@ -276,17 +276,17 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
1331         rv = file->AppendNative(NS_LITERAL_CSTRING("pref"));
1332     }
1333   }
1334   else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_DIR) ||
1335            !strcmp(aProperty, XRE_USER_APP_DATA_DIR)) {
1336     rv = GetUserAppDataDirectory(getter_AddRefs(file));
1337   }
1338   else if (!strcmp(aProperty, XRE_UPDATE_ROOT_DIR)) {
1339-#if defined(XP_WIN)
1340+#if defined(TOR_BUNDLE_UPDATE) || defined(XP_WIN)
1341     rv = GetUpdateRootDir(getter_AddRefs(file));
1342 #else
1343     // Only supported on Windows, so just immediately fail.
1344     return NS_ERROR_FAILURE;
1345 #endif
1346   }
1347   else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_FILE)) {
1348     rv = GetUserAppDataDirectory(getter_AddRefs(file));
1349@@ -859,17 +859,17 @@ nsXREDirProvider::DoShutdown()
1350 
1351       // Phase 3: Notify observers of a profile change
1352       obsSvc->NotifyObservers(cs, "profile-before-change", kShutdownPersist);
1353     }
1354     mProfileNotified = false;
1355   }
1356 }
1357 
1358-#ifdef XP_WIN
1359+#if defined(XP_WIN)
1360 static nsresult
1361 GetShellFolderPath(int folder, nsAString& _retval)
1362 {
1363   PRUnichar* buf;
1364   uint32_t bufLength = _retval.GetMutableData(&buf, MAXPATHLEN + 3);
1365   NS_ENSURE_TRUE(bufLength >= (MAXPATHLEN + 3), NS_ERROR_OUT_OF_MEMORY);
1366 
1367   nsresult rv = NS_OK;
1368@@ -938,16 +938,43 @@ GetRegWindowsAppDataFolder(bool aLocal, nsAString& _retval)
1369   ::RegCloseKey(key);
1370   if (res != ERROR_SUCCESS) {
1371     _retval.SetLength(0);
1372     return NS_ERROR_NOT_AVAILABLE;
1373   }
1374 
1375   return NS_OK;
1376 }
1377+#endif
1378+
1379+#if defined(TOR_BUNDLE_UPDATE)
1380+nsresult
1381+nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
1382+{
1383+  NS_ENSURE_ARG(aResult);
1384+  nsCOMPtr<nsIFile> updateRootDir = GetAppDir();
1385+#if defined(XP_MACOSX)
1386+  int levelsToRemove = 5;
1387+#else
1388+  int levelsToRemove = 1;
1389+#endif
1390+  while (updateRootDir && (levelsToRemove > 0)) {
1391+    nsCOMPtr<nsIFile> tmpDir;
1392+    nsresult rv = updateRootDir->GetParent(getter_AddRefs(tmpDir));
1393+    NS_ENSURE_SUCCESS(rv, rv);
1394+
1395+    updateRootDir = tmpDir;
1396+    --levelsToRemove;
1397+  }
1398+
1399+  NS_IF_ADDREF(*aResult = updateRootDir);
1400+  return NS_OK;
1401+}
1402+
1403+#elif defined(XP_WIN)
1404 
1405 nsresult
1406 nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
1407 {
1408   nsCOMPtr<nsIFile> appDir = GetAppDir();
1409 
1410   nsAutoString appPath;
1411   nsresult rv = appDir->GetPath(appPath);
1412diff --git a/tools/update-packaging/make_full_update.sh b/tools/update-packaging/make_full_update.sh
1413index 03ba9af..7641866 100755
1414--- a/tools/update-packaging/make_full_update.sh
1415+++ b/tools/update-packaging/make_full_update.sh
1416@@ -53,20 +53,21 @@ mkdir -p "$workdir"
1417 # Info.plist so it launches the right architecture, bug 600098
1418 
1419 # Generate a list of all files in the target directory.
1420 pushd "$targetdir"
1421 if test $? -ne 0 ; then
1422   exit 1
1423 fi
1424 
1425-if [ ! -f "precomplete" ]; then
1426-  notice "precomplete file is missing!"
1427-  exit 1
1428-fi
1429+# TODO: The TBB does not include a file named precomplete.  Is it needed?
1430+#if [ ! -f "precomplete" ]; then
1431+#  notice "precomplete file is missing!"
1432+#  exit 1
1433+#fi
1434 
1435 list_files files
1436 
1437 popd
1438 
1439 notice ""
1440 notice "Adding file add instructions to file 'update.manifest'"
1441 > $updatemanifestv1
1442diff --git a/tools/update-packaging/make_incremental_update.sh b/tools/update-packaging/make_incremental_update.sh
1443index 0363831..cfea9e4 100755
1444--- a/tools/update-packaging/make_incremental_update.sh
1445+++ b/tools/update-packaging/make_incremental_update.sh
1446@@ -106,20 +106,21 @@ list_dirs olddirs
1447 
1448 popd
1449 
1450 pushd "$newdir"
1451 if test $? -ne 0 ; then
1452   exit 1
1453 fi
1454 
1455-if [ ! -f "precomplete" ]; then
1456-  notice "precomplete file is missing!"
1457-  exit 1
1458-fi
1459+# TODO: The TBB does not include a file named precomplete.  Is it needed?
1460+#if [ ! -f "precomplete" ]; then
1461+#  notice "precomplete file is missing!"
1462+#  exit 1
1463+#fi
1464 
1465 list_dirs newdirs
1466 list_files newfiles
1467 
1468 popd
1469 
1470 notice ""
1471 notice "Adding file patch and add instructions to file 'update.manifest'"
1472@@ -134,17 +135,17 @@ for ((i=0; $i<$num_oldfiles; i=$i+1)); do
1473 
1474   # This file is created by Talkback, so we can ignore it
1475   if [ "$f" = "readme.txt" ]; then
1476     continue 1
1477   fi
1478 
1479   # removed-files is excluded by make_incremental_updates.py so it is excluded
1480   # here for consistency.
1481-  if [ `basename $f` = "removed-files" ]; then
1482+  if [ "`basename "$f"`" = "removed-files" ]; then
1483     continue 1
1484   fi
1485 
1486   # If this file exists in the new directory as well, then check if it differs.
1487   if [ -f "$newdir/$f" ]; then
1488 
1489     if check_for_forced_update "$requested_forced_updates" "$f"; then
1490       # The full workdir may not exist yet, so create it if necessary.
1491@@ -193,17 +194,17 @@ notice ""
1492 notice "Adding file add instructions to file 'update.manifest'"
1493 num_newfiles=${#newfiles[*]}
1494 
1495 for ((i=0; $i<$num_newfiles; i=$i+1)); do
1496   f="${newfiles[$i]}"
1497 
1498   # removed-files is excluded by make_incremental_updates.py so it is excluded
1499   # here for consistency.
1500-  if [ `basename $f` = "removed-files" ]; then
1501+  if [ "`basename "$f"`" = "removed-files" ]; then
1502     continue 1
1503   fi
1504 
1505   # If we've already tested this file, then skip it
1506   for ((j=0; $j<$num_oldfiles; j=$j+1)); do
1507     if [ "$f" = "${oldfiles[j]}" ]; then
1508       continue 2
1509     fi
1510diff --git a/xpcom/build/nsXULAppAPI.h b/xpcom/build/nsXULAppAPI.h
1511index a6fb639..dc1773e 100644
1512--- a/xpcom/build/nsXULAppAPI.h
1513+++ b/xpcom/build/nsXULAppAPI.h
1514@@ -111,17 +111,18 @@
1515 /**
1516  * A directory service key which specifies the distribution specific files for
1517  * the application.
1518  */
1519 #define XRE_APP_DISTRIBUTION_DIR "XREAppDist"
1520 
1521 /**
1522  * A directory service key which provides the update directory.
1523- * At present this is supported only on Windows.
1524+ * At present this is supported only on Windows, unless TOR_BUNDLE_UPDATE is
1525+ * defined.
1526  * Windows: Documents and Settings\<User>\Local Settings\Application Data\
1527  *          <Vendor>\<Application>\<relative path to app dir from Program Files>
1528  * If appDir is not under the Program Files, directory service will fail.
1529  * Callers should fallback to appDir.
1530  */
1531 #define XRE_UPDATE_ROOT_DIR "UpdRootD"
1532 
1533 /**