[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [tor-browser/tor-browser-91.5.0esr-11.5-2] Bug 9173: Change the default Firefox profile directory to be TBB-relative.



commit 17e615981256302ae70f0d6e2007ab27d2a93d10
Author: Kathy Brade <brade@xxxxxxxxxxxxxxxxx>
Date:   Fri Oct 18 15:20:06 2013 -0400

    Bug 9173: Change the default Firefox profile directory to be TBB-relative.
    
    This should eliminate our need to rely on a wrapper script that
    sets /Users/arthur and launches Firefox with -profile.
    
    Bug 13252: Do not store data in the app bundle
    
    When --enable-tor-browser-data-outside-app-dir is enabled,
    all user data is stored in a directory named
    TorBrowser-Data which is located next to the application directory.
    
    Display an informative error message if the TorBrowser-Data
    directory cannot be created due to an "access denied" or a
    "read only volume" error.
    
    On Mac OS, add support for the --invisible command line option which
    is used by the meek-http-helper to avoid showing an icon for the
    helper browser on the dock.
---
 toolkit/profile/nsToolkitProfileService.cpp |   5 +-
 toolkit/xre/nsAppRunner.cpp                 |  75 +++++++++++---
 toolkit/xre/nsConsoleWriter.cpp             |   2 +-
 toolkit/xre/nsXREDirProvider.cpp            | 150 ++++++----------------------
 toolkit/xre/nsXREDirProvider.h              |  22 ++--
 xpcom/io/TorFileUtils.cpp                   | 133 ++++++++++++++++++++++++
 xpcom/io/TorFileUtils.h                     |  32 ++++++
 xpcom/io/moz.build                          |   5 +
 xpcom/io/nsAppFileLocationProvider.cpp      |  98 ++++++------------
 9 files changed, 315 insertions(+), 207 deletions(-)

diff --git a/toolkit/profile/nsToolkitProfileService.cpp b/toolkit/profile/nsToolkitProfileService.cpp
index b2920c88345d..154806ebbccf 100644
--- a/toolkit/profile/nsToolkitProfileService.cpp
+++ b/toolkit/profile/nsToolkitProfileService.cpp
@@ -819,10 +819,11 @@ nsresult nsToolkitProfileService::Init() {
   NS_ASSERTION(gDirServiceProvider, "No dirserviceprovider!");
   nsresult rv;
 
-  rv = nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(mAppData));
+  rv = gDirServiceProvider->GetUserAppDataDirectory(getter_AddRefs(mAppData));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = nsXREDirProvider::GetUserLocalDataDirectory(getter_AddRefs(mTempData));
+  rv =
+      gDirServiceProvider->GetUserLocalDataDirectory(getter_AddRefs(mTempData));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mAppData->Clone(getter_AddRefs(mProfileDBFile));
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
index d3bb8096ad02..75c381724deb 100644
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -2368,6 +2368,8 @@ static nsresult ProfileMissingDialog(nsINativeAppSupport* aNative) {
   }
 }
 
+// If aUnlocker is NULL, it is also OK for the following arguments to be NULL:
+//   aProfileDir, aProfileLocalDir, aResult.
 static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
                                               nsIFile* aProfileLocalDir,
                                               nsIProfileUnlocker* aUnlocker,
@@ -2375,17 +2377,19 @@ static ReturnAbortOnError ProfileLockedDialog(nsIFile* aProfileDir,
                                               nsIProfileLock** aResult) {
   nsresult rv;
 
-  bool exists;
-  aProfileDir->Exists(&exists);
-  if (!exists) {
-    return ProfileMissingDialog(aNative);
+  if (aProfileDir) {
+    bool exists;
+    aProfileDir->Exists(&exists);
+    if (!exists) {
+      return ProfileMissingDialog(aNative);
+    }
   }
 
   ScopedXPCOMStartup xpcom;
   rv = xpcom.Initialize();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
+  if (aProfileDir) mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
 
   rv = xpcom.SetWindowCreator(aNative);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
@@ -2581,6 +2585,23 @@ static ReturnAbortOnError ShowProfileManager(
   return LaunchChild(false, true);
 }
 
+#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+static ProfileStatus CheckTorBrowserDataWriteAccess(nsIFile* aAppDir) {
+  // Check whether we can write to the directory that will contain
+  // TorBrowser-Data.
+  nsCOMPtr<nsIFile> tbDataDir;
+  RefPtr<nsXREDirProvider> dirProvider = nsXREDirProvider::GetSingleton();
+  if (!dirProvider) return PROFILE_STATUS_OTHER_ERROR;
+  nsresult rv =
+      dirProvider->GetTorBrowserUserDataDir(getter_AddRefs(tbDataDir));
+  NS_ENSURE_SUCCESS(rv, PROFILE_STATUS_OTHER_ERROR);
+  nsCOMPtr<nsIFile> tbDataDirParent;
+  rv = tbDataDir->GetParent(getter_AddRefs(tbDataDirParent));
+  NS_ENSURE_SUCCESS(rv, PROFILE_STATUS_OTHER_ERROR);
+  return nsToolkitProfileService::CheckProfileWriteAccess(tbDataDirParent);
+}
+#endif
+
 static bool gDoMigration = false;
 static bool gDoProfileReset = false;
 static nsCOMPtr<nsIToolkitProfile> gResetOldProfile;
@@ -3610,6 +3631,14 @@ int XREMain::XRE_mainInit(bool* aExitFlag) {
   if (PR_GetEnv("XRE_MAIN_BREAK")) NS_BREAK();
 #endif
 
+#if defined(XP_MACOSX) && defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
+  bool hideDockIcon = (CheckArg("invisible") == ARG_FOUND);
+  if (hideDockIcon) {
+    ProcessSerialNumber psn = {0, kCurrentProcess};
+    TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
+  }
+#endif
+
   IncreaseDescriptorLimits();
 
 #ifdef USE_GLX_TEST
@@ -3729,7 +3758,7 @@ int XREMain::XRE_mainInit(bool* aExitFlag) {
   if ((mAppData->flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
       NS_SUCCEEDED(CrashReporter::SetExceptionHandler(xreBinDirectory))) {
     nsCOMPtr<nsIFile> file;
-    rv = nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(file));
+    rv = mDirProvider.GetUserAppDataDirectory(getter_AddRefs(file));
     if (NS_SUCCEEDED(rv)) {
       CrashReporter::SetUserAppDataDirectory(file);
     }
@@ -4447,7 +4476,34 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
   }
 #endif
 
+#if (defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)) || \
+    defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
+  nsCOMPtr<nsIFile> exeFile, exeDir;
+  bool persistent;
+  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);
+#endif
+
   rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc));
+#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+  if (NS_FAILED(rv)) {
+    // NS_NewToolkitProfileService() returns a generic NS_ERROR_FAILURE error
+    // if creation of the TorBrowser-Data directory fails due to access denied
+    // or because of a read-only disk volume. Do an extra check here to detect
+    // these errors so we can display an informative error message.
+    ProfileStatus status = CheckTorBrowserDataWriteAccess(exeDir);
+    if ((PROFILE_STATUS_ACCESS_DENIED == status) ||
+        (PROFILE_STATUS_READ_ONLY == status)) {
+      ProfileErrorDialog(nullptr, nullptr, status, nullptr, mNativeApp,
+                         nullptr);
+      return 1;
+    }
+  }
+#endif
+
   if (rv == NS_ERROR_FILE_ACCESS_DENIED) {
     PR_fprintf(PR_STDERR,
                "Error: Access was denied while trying to open files in "
@@ -4517,7 +4573,6 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
   if (ShouldProcessUpdates(mDirProvider)) {
     // Check for and process any available updates
     nsCOMPtr<nsIFile> updRoot;
-    bool persistent;
     rv = mDirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
                               getter_AddRefs(updRoot));
     // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
@@ -4553,12 +4608,6 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
     if (CheckArg("test-process-updates")) {
       SaveToEnv("MOZ_TEST_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(), exeDir, updRoot, gRestartArgc,
                    gRestartArgv, mAppData->version);
     if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
diff --git a/toolkit/xre/nsConsoleWriter.cpp b/toolkit/xre/nsConsoleWriter.cpp
index d89ea3bde31d..4a9a6d28034a 100644
--- a/toolkit/xre/nsConsoleWriter.cpp
+++ b/toolkit/xre/nsConsoleWriter.cpp
@@ -29,7 +29,7 @@ void WriteConsoleLog() {
   } else {
     if (!gLogConsoleErrors) return;
 
-    rv = nsXREDirProvider::GetUserAppDataDirectory(getter_AddRefs(lfile));
+    rv = gDirServiceProvider->GetUserAppDataDirectory(getter_AddRefs(lfile));
     if (NS_FAILED(rv)) return;
 
     lfile->AppendNative("console.log"_ns);
diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp
index d6def8aee83d..2e965b3526ad 100644
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -32,6 +32,7 @@
 #include "nsArrayEnumerator.h"
 #include "nsEnumeratorUtils.h"
 #include "nsReadableUtils.h"
+#include "nsXPCOMPrivate.h"  // for XPCOM_FILE_PATH_SEPARATOR
 
 #include "SpecialSystemDirectory.h"
 
@@ -56,6 +57,8 @@
 #  include "nsIPK11Token.h"
 #endif
 
+#include "TorFileUtils.h"
+
 #include <stdlib.h>
 
 #ifdef XP_WIN
@@ -255,9 +258,6 @@ nsresult nsXREDirProvider::GetUserProfilesRootDir(nsIFile** aResult) {
   nsresult rv = GetUserDataDirectory(getter_AddRefs(file), false);
 
   if (NS_SUCCEEDED(rv)) {
-#if !defined(XP_UNIX) || defined(XP_MACOSX)
-    rv = file->AppendNative("Profiles"_ns);
-#endif
     // We must create the profile directory here if it does not exist.
     nsresult tmp = EnsureDirectoryExists(file);
     if (NS_FAILED(tmp)) {
@@ -273,9 +273,6 @@ nsresult nsXREDirProvider::GetUserProfilesLocalDir(nsIFile** aResult) {
   nsresult rv = GetUserDataDirectory(getter_AddRefs(file), true);
 
   if (NS_SUCCEEDED(rv)) {
-#if !defined(XP_UNIX) || defined(XP_MACOSX)
-    rv = file->AppendNative("Profiles"_ns);
-#endif
     // We must create the profile directory here if it does not exist.
     nsresult tmp = EnsureDirectoryExists(file);
     if (NS_FAILED(tmp)) {
@@ -1370,7 +1367,7 @@ nsresult nsXREDirProvider::SetUserDataProfileDirectory(nsCOMPtr<nsIFile>& aFile,
 nsresult nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile,
                                                     bool aLocal) {
   // Copied from nsAppFileLocationProvider (more or less)
-  nsresult rv;
+  NS_ENSURE_ARG_POINTER(aFile);
   nsCOMPtr<nsIFile> localDir;
 
   if (aLocal && gDataDirHomeLocal) {
@@ -1380,80 +1377,23 @@ nsresult nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile,
     return gDataDirHome->Clone(aFile);
   }
 
-#if defined(XP_MACOSX)
-  FSRef fsRef;
-  OSType folderType;
-  if (aLocal) {
-    folderType = kCachedDataFolderType;
-  } else {
-#  ifdef MOZ_THUNDERBIRD
-    folderType = kDomainLibraryFolderType;
-#  else
-    folderType = kApplicationSupportFolderType;
-#  endif
-  }
-  OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
-  NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
-
-  rv = NS_NewNativeLocalFile(""_ns, true, getter_AddRefs(localDir));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir);
-  NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED);
-
-  rv = dirFileMac->InitWithFSRef(&fsRef);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  localDir = dirFileMac;
-#elif defined(XP_IOS)
-  nsAutoCString userDir;
-  if (GetUIKitDirectory(aLocal, userDir)) {
-    rv = NS_NewNativeLocalFile(userDir, true, getter_AddRefs(localDir));
-  } else {
-    rv = NS_ERROR_FAILURE;
-  }
-  NS_ENSURE_SUCCESS(rv, rv);
-#elif defined(XP_WIN)
-  nsString path;
-  if (aLocal) {
-    rv = GetShellFolderPath(FOLDERID_LocalAppData, path);
-    if (NS_FAILED(rv)) rv = GetRegWindowsAppDataFolder(aLocal, path);
-  }
-  if (!aLocal || NS_FAILED(rv)) {
-    rv = GetShellFolderPath(FOLDERID_RoamingAppData, path);
-    if (NS_FAILED(rv)) {
-      if (!aLocal) rv = GetRegWindowsAppDataFolder(aLocal, path);
-    }
-  }
+  nsresult rv = GetTorBrowserUserDataDir(getter_AddRefs(localDir));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = NS_NewLocalFile(path, true, getter_AddRefs(localDir));
-#elif defined(XP_UNIX)
-  const char* homeDir = getenv("HOME");
-  if (!homeDir || !*homeDir) return NS_ERROR_FAILURE;
-
-#  ifdef ANDROID /* We want (ProfD == ProfLD) on Android. */
-  aLocal = false;
+#if !defined(ANDROID)
+#  ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+  rv = localDir->AppendNative("Browser"_ns);
+#  else
+  rv = localDir->AppendRelativeNativePath("Data" XPCOM_FILE_PATH_SEPARATOR
+                                          "Browser"_ns);
 #  endif
+  NS_ENSURE_SUCCESS(rv, rv);
+#endif
 
   if (aLocal) {
-    // If $XDG_CACHE_HOME is defined use it, otherwise use $HOME/.cache.
-    const char* cacheHome = getenv("XDG_CACHE_HOME");
-    if (cacheHome && *cacheHome) {
-      rv = NS_NewNativeLocalFile(nsDependentCString(cacheHome), true,
-                                 getter_AddRefs(localDir));
-    } else {
-      rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
-                                 getter_AddRefs(localDir));
-      if (NS_SUCCEEDED(rv)) rv = localDir->AppendNative(".cache"_ns);
-    }
-  } else {
-    rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
-                               getter_AddRefs(localDir));
+    rv = localDir->AppendNative("Caches"_ns);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
-#else
-#  error "Don't know how to get product dir on your platform"
-#endif
 
   NS_IF_ADDREF(*aFile = localDir);
   return rv;
@@ -1554,6 +1494,15 @@ nsresult nsXREDirProvider::GetUserDataDirectory(nsIFile** aFile, bool aLocal) {
   return NS_OK;
 }
 
+nsresult nsXREDirProvider::GetTorBrowserUserDataDir(nsIFile** aFile) {
+  NS_ENSURE_ARG_POINTER(aFile);
+  nsCOMPtr<nsIFile> exeFile;
+  bool per = false;
+  nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(exeFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+  return TorBrowser_GetUserDataDir(exeFile, aFile);
+}
+
 nsresult nsXREDirProvider::EnsureDirectoryExists(nsIFile* aDirectory) {
   nsresult rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0700);
 
@@ -1636,39 +1585,23 @@ nsresult nsXREDirProvider::AppendProfilePath(nsIFile* aFile, bool aLocal) {
   }
 
   nsAutoCString profile;
-  nsAutoCString appName;
-  nsAutoCString vendor;
   if (gAppData->profile) {
     profile = gAppData->profile;
-  } else {
-    appName = gAppData->name;
-    vendor = gAppData->vendor;
   }
 
-  nsresult rv = NS_OK;
+  nsresult rv = NS_ERROR_FAILURE;
 
 #if defined(XP_MACOSX)
   if (!profile.IsEmpty()) {
     rv = AppendProfileString(aFile, profile.get());
-  } else {
-    // Note that MacOS ignores the vendor when creating the profile hierarchy -
-    // all application preferences directories live alongside one another in
-    // ~/Library/Application Support/
-    rv = aFile->AppendNative(appName);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
-  NS_ENSURE_SUCCESS(rv, rv);
 
 #elif defined(XP_WIN)
   if (!profile.IsEmpty()) {
     rv = AppendProfileString(aFile, profile.get());
-  } else {
-    if (!vendor.IsEmpty()) {
-      rv = aFile->AppendNative(vendor);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    rv = aFile->AppendNative(appName);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
-  NS_ENSURE_SUCCESS(rv, rv);
 
 #elif defined(ANDROID)
   // The directory used for storing profiles
@@ -1678,11 +1611,6 @@ nsresult nsXREDirProvider::AppendProfilePath(nsIFile* aFile, bool aLocal) {
   rv = aFile->AppendNative(nsDependentCString("mozilla"));
   NS_ENSURE_SUCCESS(rv, rv);
 #elif defined(XP_UNIX)
-  nsAutoCString folder;
-  // Make it hidden (by starting with "."), except when local (the
-  // profile is already under ~/.cache or XDG_CACHE_HOME).
-  if (!aLocal) folder.Assign('.');
-
   if (!profile.IsEmpty()) {
     // Skip any leading path characters
     const char* profileStart = profile.get();
@@ -1690,32 +1618,16 @@ nsresult nsXREDirProvider::AppendProfilePath(nsIFile* aFile, bool aLocal) {
 
     // On the off chance that someone wanted their folder to be hidden don't
     // let it become ".."
-    if (*profileStart == '.' && !aLocal) profileStart++;
+    if (*profileStart == '.') profileStart++;
 
+    // Make it hidden (by starting with ".").
+    nsAutoCString folder(".");
     folder.Append(profileStart);
     ToLowerCase(folder);
 
     rv = AppendProfileString(aFile, folder.BeginReading());
-  } else {
-    if (!vendor.IsEmpty()) {
-      folder.Append(vendor);
-      ToLowerCase(folder);
-
-      rv = aFile->AppendNative(folder);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      folder.Truncate();
-    }
-
-    // This can be the case in tests.
-    if (!appName.IsEmpty()) {
-      folder.Append(appName);
-      ToLowerCase(folder);
-
-      rv = aFile->AppendNative(folder);
-    }
+    NS_ENSURE_SUCCESS(rv, rv);
   }
-  NS_ENSURE_SUCCESS(rv, rv);
 
 #else
 #  error "Don't know how to get profile path on your platform"
diff --git a/toolkit/xre/nsXREDirProvider.h b/toolkit/xre/nsXREDirProvider.h
index e28a4fef5bc6..98ef4ad770ea 100644
--- a/toolkit/xre/nsXREDirProvider.h
+++ b/toolkit/xre/nsXREDirProvider.h
@@ -63,15 +63,19 @@ class nsXREDirProvider final : public nsIDirectoryServiceProvider2,
 
   void DoShutdown();
 
-  static nsresult GetUserAppDataDirectory(nsIFile** aFile) {
+  nsresult GetUserAppDataDirectory(nsIFile** aFile) {
     return GetUserDataDirectory(aFile, false);
   }
-  static nsresult GetUserLocalDataDirectory(nsIFile** aFile) {
+  nsresult GetUserLocalDataDirectory(nsIFile** aFile) {
     return GetUserDataDirectory(aFile, true);
   }
 
   // GetUserDataDirectory gets the profile path from gAppData.
-  static nsresult GetUserDataDirectory(nsIFile** aFile, bool aLocal);
+
+  // This function now calls GetAppDir(), so it cannot be static anymore.
+  // The same happens with all the functions (in)directly calling this one (the
+  // rest of Get*Directory functions in this file)
+  nsresult GetUserDataDirectory(nsIFile** aFile, bool aLocal);
 
   /* make sure you clone it, if you need to do stuff to it */
   nsIFile* GetGREDir() { return mGREDir; }
@@ -109,12 +113,18 @@ class nsXREDirProvider final : public nsIDirectoryServiceProvider2,
    */
   nsresult GetProfileDir(nsIFile** aResult);
 
+  /**
+   * Get the TorBrowser user data directory by calling the
+   * TorBrowser_GetUserDataDir() utility function.
+   */
+  nsresult GetTorBrowserUserDataDir(nsIFile** aFile);
+
  protected:
   nsresult GetFilesInternal(const char* aProperty,
                             nsISimpleEnumerator** aResult);
-  static nsresult GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal);
-  static nsresult GetSysUserExtensionsDirectory(nsIFile** aFile);
-  static nsresult GetSysUserExtensionsDevDirectory(nsIFile** aFile);
+  nsresult GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal);
+  nsresult GetSysUserExtensionsDirectory(nsIFile** aFile);
+  nsresult GetSysUserExtensionsDevDirectory(nsIFile** aFile);
 #if defined(XP_UNIX) || defined(XP_MACOSX)
   static nsresult GetSystemExtensionsDirectory(nsIFile** aFile);
 #endif
diff --git a/xpcom/io/TorFileUtils.cpp b/xpcom/io/TorFileUtils.cpp
new file mode 100644
index 000000000000..6bd03f1f7fed
--- /dev/null
+++ b/xpcom/io/TorFileUtils.cpp
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TorFileUtils.h"
+#include "nsString.h"
+#ifdef MOZ_WIDGET_COCOA
+#  include <Carbon/Carbon.h>
+#  include "nsILocalFileMac.h"
+#endif
+
+static nsresult GetAppRootDir(nsIFile* aExeFile, nsIFile** aFile);
+
+//-----------------------------------------------------------------------------
+nsresult TorBrowser_GetUserDataDir(nsIFile* aExeFile, nsIFile** aFile) {
+  NS_ENSURE_ARG_POINTER(aFile);
+  nsCOMPtr<nsIFile> tbDataDir;
+
+#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+  nsAutoCString tbDataLeafName("TorBrowser-Data"_ns);
+  nsCOMPtr<nsIFile> appRootDir;
+  nsresult rv = GetAppRootDir(aExeFile, getter_AddRefs(appRootDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+#  ifndef XP_MACOSX
+  // On all platforms except Mac OS, we always operate in a "portable" mode
+  // where the TorBrowser-Data directory is located next to the application.
+  rv = appRootDir->GetParent(getter_AddRefs(tbDataDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = tbDataDir->AppendNative(tbDataLeafName);
+  NS_ENSURE_SUCCESS(rv, rv);
+#  else
+  // For Mac OS, determine whether we should store user data in the OS's
+  // standard location (i.e., under ~/Library/Application Support). We use
+  // the OS location if (1) the application is installed in a directory whose
+  // path contains "/Applications" or (2) the TorBrowser-Data directory does
+  // not exist and cannot be created (which probably means we lack write
+  // permission to the directory that contains the application).
+  nsAutoString appRootPath;
+  rv = appRootDir->GetPath(appRootPath);
+  NS_ENSURE_SUCCESS(rv, rv);
+  bool useOSLocation =
+      (appRootPath.Find("/Applications", true /* ignore case */) >= 0);
+  if (!useOSLocation) {
+    // We hope to use the portable (aka side-by-side) approach, but before we
+    // commit to that, let's ensure that we can create the TorBrowser-Data
+    // directory. If it already exists, we will try to use it; if not and we
+    // fail to create it, we will switch to ~/Library/Application Support.
+    rv = appRootDir->GetParent(getter_AddRefs(tbDataDir));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = tbDataDir->AppendNative(tbDataLeafName);
+    NS_ENSURE_SUCCESS(rv, rv);
+    bool exists = false;
+    rv = tbDataDir->Exists(&exists);
+    if (NS_SUCCEEDED(rv) && !exists)
+      rv = tbDataDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
+    useOSLocation = NS_FAILED(rv);
+  }
+
+  if (useOSLocation) {
+    // We are using ~/Library/Application Support/TorBrowser-Data. We do not
+    // need to create that directory here because the code in nsXREDirProvider
+    // will do so (and the user should always have write permission for
+    // ~/Library/Application Support; if they do not we have no more options).
+    FSRef fsRef;
+    OSErr err = ::FSFindFolder(kUserDomain, kApplicationSupportFolderType,
+                               kCreateFolder, &fsRef);
+    NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
+    // To convert the FSRef returned by FSFindFolder() into an nsIFile that
+    // points to ~/Library/Application Support, we first create an empty
+    // nsIFile object (no path) and then use InitWithFSRef() to set the
+    // path.
+    rv = NS_NewNativeLocalFile(""_ns, true, getter_AddRefs(tbDataDir));
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(tbDataDir);
+    if (!dirFileMac) return NS_ERROR_UNEXPECTED;
+    rv = dirFileMac->InitWithFSRef(&fsRef);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = tbDataDir->AppendNative(tbDataLeafName);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+#  endif
+
+#elif defined(ANDROID)
+  // Tor Browser Android stores data in the app home directory.
+  const char* homeDir = getenv("HOME");
+  if (!homeDir || !*homeDir) return NS_ERROR_FAILURE;
+  nsresult rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
+                                      getter_AddRefs(tbDataDir));
+#else
+  // User data is embedded within the application directory (i.e.,
+  // TOR_BROWSER_DATA_OUTSIDE_APP_DIR is not defined).
+  nsresult rv = GetAppRootDir(aExeFile, getter_AddRefs(tbDataDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = tbDataDir->AppendNative("TorBrowser"_ns);
+  NS_ENSURE_SUCCESS(rv, rv);
+#endif
+
+  tbDataDir.forget(aFile);
+  return NS_OK;
+}
+
+static nsresult GetAppRootDir(nsIFile* aExeFile, nsIFile** aFile) {
+  NS_ENSURE_ARG_POINTER(aExeFile);
+  NS_ENSURE_ARG_POINTER(aFile);
+  nsCOMPtr<nsIFile> appRootDir = aExeFile;
+
+  int levelsToRemove = 1;  // Remove firefox (the executable file).
+#if defined(XP_MACOSX)
+  levelsToRemove += 2;  // On Mac OS, we must also remove Contents/MacOS.
+#endif
+  while (appRootDir && (levelsToRemove > 0)) {
+    // When crawling up the hierarchy, components named "." do not count.
+    nsAutoCString removedName;
+    nsresult rv = appRootDir->GetNativeLeafName(removedName);
+    NS_ENSURE_SUCCESS(rv, rv);
+    bool didRemove = !removedName.Equals(".");
+
+    // Remove a directory component.
+    nsCOMPtr<nsIFile> parentDir;
+    rv = appRootDir->GetParent(getter_AddRefs(parentDir));
+    NS_ENSURE_SUCCESS(rv, rv);
+    appRootDir = parentDir;
+
+    if (didRemove) --levelsToRemove;
+  }
+
+  if (!appRootDir) return NS_ERROR_FAILURE;
+
+  appRootDir.forget(aFile);
+  return NS_OK;
+}
diff --git a/xpcom/io/TorFileUtils.h b/xpcom/io/TorFileUtils.h
new file mode 100644
index 000000000000..31e70a7e0d3a
--- /dev/null
+++ b/xpcom/io/TorFileUtils.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TorFileUtils_h__
+#define TorFileUtils_h__
+
+#include "nsIFile.h"
+
+/**
+ * TorBrowser_GetUserDataDir
+ *
+ * Retrieve the Tor Browser user data directory.
+ * When built with --enable-tor-browser-data-outside-app-dir, the directory
+ * is next to the application directory, except on Mac OS where it may be
+ * there or it may be at ~/Library/Application Support/TorBrowser-Data (the
+ * latter location is used if the .app bundle is in a directory whose path
+ * contains /Applications or if we lack write access to the directory that
+ * contains the .app).
+ * When built without --enable-tor-browser-data-outside-app-dir, this
+ * directory is TorBrowser.app/TorBrowser.
+ *
+ * @param aExeFile  The firefox executable.
+ * @param aFile     Out parameter that is set to the Tor Browser user data
+ *                  directory.
+ * @return NS_OK on success.  Error otherwise.
+ */
+extern nsresult TorBrowser_GetUserDataDir(nsIFile* aExeFile, nsIFile** aFile);
+
+#endif  // !TorFileUtils_h__
diff --git a/xpcom/io/moz.build b/xpcom/io/moz.build
index d28c426e7bd7..af7b5be04f6e 100644
--- a/xpcom/io/moz.build
+++ b/xpcom/io/moz.build
@@ -86,6 +86,7 @@ EXPORTS += [
     "nsUnicharInputStream.h",
     "nsWildCard.h",
     "SpecialSystemDirectory.h",
+    "TorFileUtils.h",
 ]
 
 EXPORTS.mozilla += [
@@ -137,6 +138,10 @@ UNIFIED_SOURCES += [
     "SpecialSystemDirectory.cpp",
 ]
 
+SOURCES += [
+    "TorFileUtils.cpp",
+]
+
 if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
     SOURCES += [
         "CocoaFileUtils.mm",
diff --git a/xpcom/io/nsAppFileLocationProvider.cpp b/xpcom/io/nsAppFileLocationProvider.cpp
index ef974f99048f..66f6940beff6 100644
--- a/xpcom/io/nsAppFileLocationProvider.cpp
+++ b/xpcom/io/nsAppFileLocationProvider.cpp
@@ -15,6 +15,7 @@
 #include "nsSimpleEnumerator.h"
 #include "prenv.h"
 #include "nsCRT.h"
+#include "nsXPCOMPrivate.h"  // for XPCOM_FILE_PATH_SEPARATOR
 #if defined(MOZ_WIDGET_COCOA)
 #  include <Carbon/Carbon.h>
 #  include "nsILocalFileMac.h"
@@ -27,6 +28,8 @@
 #  include <sys/param.h>
 #endif
 
+#include "TorFileUtils.h"
+
 // WARNING: These hard coded names need to go away. They need to
 // come from localizable resources
 
@@ -233,9 +236,14 @@ nsresult nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile** aLocalFile) {
 // GetProductDirectory - Gets the directory which contains the application data
 // folder
 //
-// UNIX   : ~/.mozilla/
-// WIN    : <Application Data folder on user's machine>\Mozilla
-// Mac    : :Documents:Mozilla:
+#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+// UNIX and WIN   : <App Folder>/../TorBrowser-Data/Browser
+// Mac            : <App Folder>/../../../TorBrowser-Data/Browser OR
+//                  ~/Library/Application Support/TorBrowser-Data/Browser
+#else
+// UNIX and WIN   : <App Folder>/TorBrowser/Data/Browser
+// Mac            : <App Folder>/../../TorBrowser/Data/Browser
+#endif
 //----------------------------------------------------------------------------------------
 nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
                                                         bool aLocal) {
@@ -243,53 +251,32 @@ nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
     return NS_ERROR_INVALID_ARG;
   }
 
-  nsresult rv;
+  nsresult rv = NS_ERROR_UNEXPECTED;
   bool exists;
-  nsCOMPtr<nsIFile> localDir;
-
-#if defined(MOZ_WIDGET_COCOA)
-  FSRef fsRef;
-  OSType folderType =
-      aLocal ? (OSType)kCachedDataFolderType : (OSType)kDomainLibraryFolderType;
-  OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
-  if (err) {
-    return NS_ERROR_FAILURE;
-  }
-  NS_NewLocalFile(u""_ns, true, getter_AddRefs(localDir));
-  if (!localDir) {
-    return NS_ERROR_FAILURE;
-  }
-  nsCOMPtr<nsILocalFileMac> localDirMac(do_QueryInterface(localDir));
-  rv = localDirMac->InitWithFSRef(&fsRef);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-#elif defined(XP_WIN)
-  nsCOMPtr<nsIProperties> directoryService =
-      do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  const char* prop = aLocal ? NS_WIN_LOCAL_APPDATA_DIR : NS_WIN_APPDATA_DIR;
-  rv = directoryService->Get(prop, NS_GET_IID(nsIFile),
-                             getter_AddRefs(localDir));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-#elif defined(XP_UNIX)
-  rv = NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), true,
-                             getter_AddRefs(localDir));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
+  nsCOMPtr<nsIFile> localDir, exeFile;
+
+  nsCOMPtr<nsIProperties> directoryService(
+      do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = directoryService->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile),
+                             getter_AddRefs(exeFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = TorBrowser_GetUserDataDir(exeFile, getter_AddRefs(localDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+  rv = localDir->AppendNative("Browser"_ns);
 #else
-#  error dont_know_how_to_get_product_dir_on_your_platform
+  rv = localDir->AppendRelativeNativePath("Data" XPCOM_FILE_PATH_SEPARATOR
+                                          "Browser"_ns);
 #endif
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = localDir->AppendRelativeNativePath(DEFAULT_PRODUCT_DIR);
-  if (NS_FAILED(rv)) {
-    return rv;
+  if (aLocal) {
+    rv = localDir->AppendNative("Caches"_ns);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
+
   rv = localDir->Exists(&exists);
 
   if (NS_SUCCEEDED(rv) && !exists) {
@@ -308,10 +295,6 @@ nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
 //----------------------------------------------------------------------------------------
 // GetDefaultUserProfileRoot - Gets the directory which contains each user
 // profile dir
-//
-// UNIX   : ~/.mozilla/
-// WIN    : <Application Data folder on user's machine>\Mozilla\Profiles
-// Mac    : :Documents:Mozilla:Profiles:
 //----------------------------------------------------------------------------------------
 nsresult nsAppFileLocationProvider::GetDefaultUserProfileRoot(
     nsIFile** aLocalFile, bool aLocal) {
@@ -327,23 +310,6 @@ nsresult nsAppFileLocationProvider::GetDefaultUserProfileRoot(
     return rv;
   }
 
-#if defined(MOZ_WIDGET_COCOA) || defined(XP_WIN)
-  // These 3 platforms share this part of the path - do them as one
-  rv = localDir->AppendRelativeNativePath("Profiles"_ns);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  bool exists;
-  rv = localDir->Exists(&exists);
-  if (NS_SUCCEEDED(rv) && !exists) {
-    rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
-  }
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-#endif
-
   localDir.forget(aLocalFile);
 
   return rv;



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits