Bug 793767 - Use the executable file location to derive the update root. r=rstrong
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 08 Feb 2013 15:58:52 +0100
changeset 131229 46ee2f9e8f91aa2ca2cc8ba5b9e708d2e5f69390
parent 131228 b871cfbc6cd20632599b9c242efa8bd6bc6c341c
child 131230 d17e8470d7d96a290dd4ee44b85aa385d8877a12
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrstrong
bugs793767
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 793767 - Use the executable file location to derive the update root. r=rstrong
browser/components/test/browser_bug538331.js
js/xpconnect/shell/xpcshell.cpp
toolkit/mozapps/update/nsUpdateService.js
toolkit/mozapps/update/nsUpdateServiceStub.js
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsUpdateDriver.cpp
toolkit/xre/nsXREDirProvider.cpp
--- a/browser/components/test/browser_bug538331.js
+++ b/browser/components/test/browser_bug538331.js
@@ -407,20 +407,19 @@ function reloadUpdateManagerData()
 function writeUpdatesToXMLFile(aText)
 {
   const PERMS_FILE = 0644;
 
   const MODE_WRONLY   = 0x02;
   const MODE_CREATE   = 0x08;
   const MODE_TRUNCATE = 0x20;
 
-  const kIsWin = (navigator.platform.indexOf("Win") == 0);
   let file = Cc["@mozilla.org/file/directory_service;1"].
              getService(Ci.nsIProperties).
-             get(kIsWin ? "UpdRootD" : "XCurProcD", Ci.nsIFile);
+             get("UpdRootD", Ci.nsIFile);
   file.append("updates.xml");
   let fos = Cc["@mozilla.org/network/file-output-stream;1"].
             createInstance(Ci.nsIFileOutputStream);
   if (!file.exists()) {
     file.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
   }
   fos.init(file, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, PERMS_FILE, 0);
   fos.write(aText, aText.length);
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -2096,19 +2096,17 @@ XPCShellDirProvider::GetFile(const char 
 #ifdef MOZ_APP_BASENAME
         localFile->AppendNative(NS_LITERAL_CSTRING(MOZ_APP_BASENAME));
 #endif
         // However app name is always appended.
         localFile->AppendNative(NS_LITERAL_CSTRING(MOZ_APP_NAME));
 #endif
         return localFile->Clone(result);
 #else
-        // Fail on non-Windows platforms, the caller is supposed to fal back on
-        // the app dir.
-        return NS_ERROR_FAILURE;
+        return mAppFile->GetParent(result);
 #endif
     }
 
     return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 XPCShellDirProvider::GetFiles(const char *prop, nsISimpleEnumerator* *result)
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -60,33 +60,24 @@ const PREF_EM_HOTFIX_ID                 
 const URI_UPDATE_PROMPT_DIALOG  = "chrome://mozapps/content/update/updates.xul";
 const URI_UPDATE_HISTORY_DIALOG = "chrome://mozapps/content/update/history.xul";
 const URI_BRAND_PROPERTIES      = "chrome://branding/locale/brand.properties";
 const URI_UPDATES_PROPERTIES    = "chrome://mozapps/locale/update/updates.properties";
 const URI_UPDATE_NS             = "http://www.mozilla.org/2005/app-update";
 
 const CATEGORY_UPDATE_TIMER               = "update-timer";
 
-const KEY_APPDIR          = "XCurProcD";
 const KEY_GRED            = "GreD";
-
-#ifdef XP_WIN
-#define USE_UPDROOT
-#elifdef ANDROID
-#define USE_UPDROOT
-#endif
+const KEY_UPDROOT         = "UpdRootD";
+const KEY_EXECUTABLE      = "XREExeF";
 
 #ifdef MOZ_WIDGET_GONK
 #define USE_UPDATE_ARCHIVE_DIR
 #endif
 
-#ifdef USE_UPDROOT
-const KEY_UPDROOT         = "UpdRootD";
-#endif
-
 #ifdef USE_UPDATE_ARCHIVE_DIR
 const KEY_UPDATE_ARCHIVE_DIR = "UpdArchD"
 #endif
 
 #ifdef XP_WIN
 #define SKIP_STAGE_UPDATES_TEST
 #elifdef MOZ_WIDGET_GONK
 // In Gonk, the updater will remount the /system partition to move staged files
@@ -465,17 +456,18 @@ XPCOMUtils.defineLazyGetter(this, "gCanA
 #      2) UAC is turned off
 #      3) UAC is turned on and the user is not an admin
 #         (e.g. the user does not have a split token)
 #      4) UAC is turned on and the user is already elevated, so they can't be
 #         elevated again
      */
     if (!userCanElevate) {
       // if we're unable to create the test file this will throw an exception.
-      var appDirTestFile = FileUtils.getFile(KEY_APPDIR, [FILE_PERMS_TEST]);
+      var appDirTestFile = getAppBaseDir();
+      appDirTestFile.append(FILE_PERMS_TEST);
       LOG("gCanApplyUpdates - testing write access " + appDirTestFile.path);
       if (appDirTestFile.exists())
         appDirTestFile.remove(false)
       appDirTestFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
       appDirTestFile.remove(false);
     }
 #endif //XP_WIN
   }
@@ -613,35 +605,48 @@ function binaryToHex(input) {
 #  Gets the specified directory at the specified hierarchy under the
 #  update root directory and creates it if it doesn't exist.
 #  @param   pathArray
 #           An array of path components to locate beneath the directory
 #           specified by |key|
 #  @return  nsIFile object for the location specified.
  */
 function getUpdateDirCreate(pathArray) {
-#ifdef USE_UPDROOT
-  try {
-    let dir = FileUtils.getDir(KEY_UPDROOT, pathArray, true);
-    return dir;
-  } catch (e) {
-  }
-#endif
-  return FileUtils.getDir(KEY_APPDIR, pathArray, true);
+  return FileUtils.getDir(KEY_UPDROOT, pathArray, true);
+}
+
+ /**
+ #  Gets the specified directory at the specified hierarchy under the
+ #  update root directory and without creating it if it doesn't exist.
+ #  @param   pathArray
+ #           An array of path components to locate beneath the directory
+ #           specified by |key|
+ #  @return  nsIFile object for the location specified.
+  */
+function getUpdateDirNoCreate(pathArray) {
+  return FileUtils.getDir(KEY_UPDROOT, pathArray, false);
+}
+
+/**
+#  Gets the application base directory.
+#  @return  nsIFile object for the application base directory.
+ */
+function getAppBaseDir() {
+  return Services.dirsvc.get(KEY_EXECUTABLE, Ci.nsIFile).parent;
 }
 
 /**
  * Gets the root of the installation directory which is the application
  * bundle directory on Mac OS X and the location of the application binary
  * on all other platforms.
  *
  * @return nsIFile object for the directory
  */
 function getInstallDirRoot() {
-  var dir = FileUtils.getDir(KEY_APPDIR, [], false);
+  var dir = getAppBaseDir();
 #ifdef XP_MACOSX
   // On Mac, we store the Updated.app directory inside the bundle directory.
   dir = dir.parent.parent;
 #endif
   return dir;
 }
 
 /**
@@ -691,40 +696,38 @@ function getStatusTextFromCode(code, def
  * @return The active updates directory, as a nsIFile object
  */
 function getUpdatesDir() {
   // Right now, we only support downloading one patch at a time, so we always
   // use the same target directory.
   return getUpdateDirCreate([DIR_UPDATES, "0"]);
 }
 
-#ifndef USE_UPDROOT
 /**
  * Get the Active Updates directory inside the directory where we apply the
  * background updates.
  * @return The active updates directory inside the updated directory, as a
  *         nsIFile object.
  */
 function getUpdatesDirInApplyToDir() {
-  var dir = FileUtils.getDir(KEY_APPDIR, []);
+  var dir = getAppBaseDir();
 #ifdef XP_MACOSX
   dir = dir.parent.parent; // the bundle directory
 #endif
   dir.append(UPDATED_DIR);
 #ifdef XP_MACOSX
   dir.append("Contents");
   dir.append("MacOS");
 #endif
   dir.append(DIR_UPDATES);
   if (!dir.exists()) {
     dir.create(Ci.nsILocalFile.DIRECTORY_TYPE, 0755);
   }
   return dir;
 }
-#endif
 
 /**
  * Reads the update state from the update.status file in the specified
  * directory.
  * @param   dir
  *          The dir to look for an update.status file in
  * @return  The status value of the update.
  */
@@ -946,36 +949,26 @@ function cleanUpUpdatesDir(aBackgroundUp
 
   var e = updateDir.directoryEntries;
   while (e.hasMoreElements()) {
     var f = e.getNext().QueryInterface(Ci.nsIFile);
     // Preserve the last update log file for debugging purposes
     if (f.leafName == FILE_UPDATE_LOG) {
       var dir;
       try {
-#ifdef USE_UPDROOT
-        // If we're on a platform which uses the update root directory, the log
-        // files are written outside of the application directory, so they will
-        // not get overwritten when we replace the directories after a
-        // background update.  Therefore, we don't need any special logic for
-        // that case here.
-        // Note that this currently only applies to Windows.
-        dir = f.parent.parent;
-#else
         // If we don't use the update root directory, the log files are written
         // inside the application directory.  In that case, we want to write
         // the log files to the updated directory in the case of background
         // updates, so that they would be available when we replace that
         // directory with the application directory later on.
-        if (aBackgroundUpdate) {
+        if (aBackgroundUpdate && getUpdateDirNoCreate([]).equals(getAppBaseDir())) {
           dir = getUpdatesDirInApplyToDir();
         } else {
           dir = f.parent.parent;
         }
-#endif
         var logFile = dir.clone();
         logFile.append(FILE_LAST_LOG);
         if (logFile.exists()) {
           try {
             logFile.moveTo(dir, FILE_BACKUP_LOG);
           }
           catch (e) {
             LOG("cleanUpUpdatesDir - failed to rename file " + logFile.path +
@@ -1054,18 +1047,18 @@ function getLocale() {
       gLocale = readStringFromInputStream(inputStream);
     } catch(e) {}
     if (gLocale)
       break;
   }
 
   if (!gLocale)
     throw Components.Exception(FILE_UPDATE_LOCALE + " file doesn't exist in " +
-                               "either the " + KEY_APPDIR + " or " + KEY_GRED +
-                               " directories", Cr.NS_ERROR_FILE_NOT_FOUND);
+                               "either the application or GRE directories",
+                               Cr.NS_ERROR_FILE_NOT_FOUND);
 
   LOG("getLocale - getting locale from file: " + channel.originalURI.spec +
       ", locale: " + gLocale);
   return gLocale;
 }
 
 /* Get the distribution pref values, from defaults only */
 function getDistributionPrefValue(aPrefName) {
--- a/toolkit/mozapps/update/nsUpdateServiceStub.js
+++ b/toolkit/mozapps/update/nsUpdateServiceStub.js
@@ -7,45 +7,28 @@
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/FileUtils.jsm");
 
 const Ci = Components.interfaces;
 
 const DIR_UPDATES         = "updates";
 const FILE_UPDATE_STATUS  = "update.status";
 
-const KEY_APPDIR          = "XCurProcD";
-
-#ifdef XP_WIN
-#define USE_UPDROOT
-#elifdef ANDROID
-#define USE_UPDROOT
-#endif
-
-#ifdef USE_UPDROOT
 const KEY_UPDROOT         = "UpdRootD";
-#endif
 
 /**
 #  Gets the specified directory at the specified hierarchy under the update root
 #  directory without creating it if it doesn't exist.
 #  @param   pathArray
 #           An array of path components to locate beneath the directory
 #           specified by |key|
 #  @return  nsIFile object for the location specified.
  */
 function getUpdateDirNoCreate(pathArray) {
-#ifdef USE_UPDROOT
-  try {
-    let dir = FileUtils.getDir(KEY_UPDROOT, pathArray, false);
-    return dir;
-  } catch (e) {
-  }
-#endif
-  return FileUtils.getDir(KEY_APPDIR, pathArray, false);
+  return FileUtils.getDir(KEY_UPDROOT, pathArray, false);
 }
 
 function UpdateServiceStub() {
   let statusFile = getUpdateDirNoCreate([DIR_UPDATES, "0"]);
   statusFile.append(FILE_UPDATE_STATUS);
   // If the update.status file exists then initiate post update processing.
   if (statusFile.exists()) {
     let aus = Components.classes["@mozilla.org/updates/update-service;1"].
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -3446,18 +3446,24 @@ XREMain::XRE_mainStartup(bool* aExitFlag
   // Support for processing an update and exiting. The MOZ_PROCESS_UPDATES
   // environment variable will be part of the updater's environment and the
   // application that is relaunched by the updater. When the application is
   // relaunched by the updater it will be removed below and the application
   // will exit.
   if (CheckArg("process-updates")) {
     SaveToEnv("MOZ_PROCESS_UPDATES=1");
   }
+  nsCOMPtr<nsIFile> exeFile, exeDir;
+  rv = mDirProvider.GetFile(XRE_EXECUTABLE_FILE, &persistent,
+                            getter_AddRefs(exeFile));
+  NS_ENSURE_SUCCESS(rv, 1);
+  rv = exeFile->GetParent(getter_AddRefs(exeDir));
+  NS_ENSURE_SUCCESS(rv, 1);
   ProcessUpdates(mDirProvider.GetGREDir(),
-                 mDirProvider.GetAppDir(),
+                 exeDir,
                  updRoot,
                  gRestartArgc,
                  gRestartArgv,
                  mAppData->version);
   if (EnvHasValue("MOZ_PROCESS_UPDATES")) {
     SaveToEnv("MOZ_PROCESS_UPDATES=");
     *aExitFlag = true;
     return 0;
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -1031,17 +1031,25 @@ nsUpdateProcessor::ProcessUpdate(nsIUpda
       rv = dirProvider->GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
                                 getter_AddRefs(updRoot));
     }
     // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
     if (NS_FAILED(rv))
       updRoot = dirProvider->GetAppDir();
 
     greDir = dirProvider->GetGREDir();
-    appDir = dirProvider->GetAppDir();
+    nsCOMPtr<nsIFile> exeFile;
+    rv = dirProvider->GetFile(XRE_EXECUTABLE_FILE, &persistent,
+                              getter_AddRefs(exeFile));
+    if (NS_SUCCEEDED(rv))
+      rv = exeFile->GetParent(getter_AddRefs(appDir));
+
+    if (NS_FAILED(rv))
+      appDir = dirProvider->GetAppDir();
+
     appVersion = gAppData->version;
     argc = gRestartArgc;
     argv = gRestartArgv;
   } else {
     // In the xpcshell environment, the usual XRE_main is not run, so things
     // like dirProvider and gAppData do not exist.  This code path accesses
     // XPCOM (which is not available in the previous code path) in order to get
     // the same information.
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -302,22 +302,17 @@ nsXREDirProvider::GetFile(const char* aP
         rv = file->AppendNative(NS_LITERAL_CSTRING("pref"));
     }
   }
   else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_DIR) ||
            !strcmp(aProperty, XRE_USER_APP_DATA_DIR)) {
     rv = GetUserAppDataDirectory(getter_AddRefs(file));
   }
   else if (!strcmp(aProperty, XRE_UPDATE_ROOT_DIR)) {
-#if defined(XP_WIN) || defined(MOZ_WIDGET_GONK)
     rv = GetUpdateRootDir(getter_AddRefs(file));
-#else
-    // Only supported on Windows, so just immediately fail.
-    return NS_ERROR_FAILURE;
-#endif
   }
   else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_FILE)) {
     rv = GetUserAppDataDirectory(getter_AddRefs(file));
     if (NS_SUCCEEDED(rv))
       rv = file->AppendNative(NS_LITERAL_CSTRING(APP_REGISTRY_NAME));
   }
   else if (!strcmp(aProperty, NS_APP_USER_PROFILES_ROOT_DIR)) {
     rv = GetUserProfilesRootDir(getter_AddRefs(file), nullptr, nullptr, nullptr);
@@ -941,24 +936,40 @@ GetRegWindowsAppDataFolder(bool aLocal, 
   ::RegCloseKey(key);
   if (res != ERROR_SUCCESS) {
     _retval.SetLength(0);
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return NS_OK;
 }
+#endif
 
 nsresult
 nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
 {
-  nsCOMPtr<nsIFile> appDir = GetAppDir();
+  nsCOMPtr<nsIFile> updRoot;
+#if defined(MOZ_WIDGET_GONK)
+
+  nsresult rv = NS_NewNativeLocalFile(nsDependentCString("/data/local"),
+                                      true,
+                                      getter_AddRefs(updRoot));
+  NS_ENSURE_SUCCESS(rv, rv);
 
+#else
+  nsCOMPtr<nsIFile> appFile;
+  bool per = false;
+  nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(appFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = appFile->GetParent(getter_AddRefs(updRoot));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+#ifdef XP_WIN
   nsAutoString appPath;
-  nsresult rv = appDir->GetPath(appPath);
+  rv = updRoot->GetPath(appPath);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // AppDir may be a short path. Convert to long path to make sure
   // the consistency of the update folder location
   nsString longPath;
   PRUnichar* buf;
 
   uint32_t bufLength = longPath.GetMutableData(&buf, MAXPATHLEN);
@@ -991,43 +1002,27 @@ nsXREDirProvider::GetUpdateRootDir(nsIFi
   } else {
     // We need the update root directory to live outside of the installation
     // directory, because otherwise the updater writing the log file can cause
     // the directory to be locked, which prevents it from being replaced after
     // background updates.
     programName.AssignASCII(MOZ_APP_NAME);
   }
 
-  nsCOMPtr<nsIFile> updRoot;
   rv = GetUserLocalDataDirectory(getter_AddRefs(updRoot));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = updRoot->AppendRelativePath(programName);
   NS_ENSURE_SUCCESS(rv, rv);
 
+#endif
+#endif
   NS_ADDREF(*aResult = updRoot);
   return NS_OK;
 }
-#endif
-
-#if defined(MOZ_WIDGET_GONK)
-nsresult
-nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
-{
-  nsCOMPtr<nsIFile> updRoot;
-
-  nsresult rv = NS_NewNativeLocalFile(nsDependentCString("/data/local"),
-                                      true,
-                                      getter_AddRefs(updRoot));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  NS_IF_ADDREF(*aResult = updRoot);
-  return NS_OK;
-}
-#endif
 
 nsresult
 nsXREDirProvider::GetProfileStartupDir(nsIFile* *aResult)
 {
   if (mProfileDir)
     return mProfileDir->Clone(aResult);
 
   if (mAppProvider) {