toolkit/xre/nsXREDirProvider.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/xre/nsXREDirProvider.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1466 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsAppRunner.h"
    1.10 +#include "nsToolkitCompsCID.h"
    1.11 +#include "nsXREDirProvider.h"
    1.12 +
    1.13 +#include "jsapi.h"
    1.14 +
    1.15 +#include "nsIJSRuntimeService.h"
    1.16 +#include "nsIAppStartup.h"
    1.17 +#include "nsIDirectoryEnumerator.h"
    1.18 +#include "nsIFile.h"
    1.19 +#include "nsIObserver.h"
    1.20 +#include "nsIObserverService.h"
    1.21 +#include "nsISimpleEnumerator.h"
    1.22 +#include "nsIToolkitChromeRegistry.h"
    1.23 +
    1.24 +#include "nsAppDirectoryServiceDefs.h"
    1.25 +#include "nsDirectoryServiceDefs.h"
    1.26 +#include "nsDirectoryServiceUtils.h"
    1.27 +#include "nsXULAppAPI.h"
    1.28 +#include "nsCategoryManagerUtils.h"
    1.29 +
    1.30 +#include "nsINIParser.h"
    1.31 +#include "nsDependentString.h"
    1.32 +#include "nsCOMArray.h"
    1.33 +#include "nsArrayEnumerator.h"
    1.34 +#include "nsEnumeratorUtils.h"
    1.35 +#include "nsReadableUtils.h"
    1.36 +#include "nsXPCOMPrivate.h"  // for XPCOM_FILE_PATH_SEPARATOR
    1.37 +#include "mozilla/Services.h"
    1.38 +#include "mozilla/Omnijar.h"
    1.39 +#include "mozilla/Preferences.h"
    1.40 +#include "mozilla/Telemetry.h"
    1.41 +
    1.42 +#include <stdlib.h>
    1.43 +
    1.44 +#ifdef XP_WIN
    1.45 +#include <windows.h>
    1.46 +#include <shlobj.h>
    1.47 +#endif
    1.48 +#ifdef XP_MACOSX
    1.49 +#include "nsILocalFileMac.h"
    1.50 +// for chflags()
    1.51 +#include <sys/stat.h>
    1.52 +#include <unistd.h>
    1.53 +#endif
    1.54 +#ifdef XP_UNIX
    1.55 +#include <ctype.h>
    1.56 +#endif
    1.57 +
    1.58 +#if defined(XP_MACOSX)
    1.59 +#define APP_REGISTRY_NAME "Application Registry"
    1.60 +#elif defined(XP_WIN)
    1.61 +#define APP_REGISTRY_NAME "registry.dat"
    1.62 +#else
    1.63 +#define APP_REGISTRY_NAME "appreg"
    1.64 +#endif
    1.65 +
    1.66 +#define PREF_OVERRIDE_DIRNAME "preferences"
    1.67 +
    1.68 +static already_AddRefed<nsIFile>
    1.69 +CloneAndAppend(nsIFile* aFile, const char* name)
    1.70 +{
    1.71 +  nsCOMPtr<nsIFile> file;
    1.72 +  aFile->Clone(getter_AddRefs(file));
    1.73 +  file->AppendNative(nsDependentCString(name));
    1.74 +  return file.forget();
    1.75 +}
    1.76 +
    1.77 +nsXREDirProvider* gDirServiceProvider = nullptr;
    1.78 +
    1.79 +nsXREDirProvider::nsXREDirProvider() :
    1.80 +  mProfileNotified(false)
    1.81 +{
    1.82 +  gDirServiceProvider = this;
    1.83 +}
    1.84 +
    1.85 +nsXREDirProvider::~nsXREDirProvider()
    1.86 +{
    1.87 +  gDirServiceProvider = nullptr;
    1.88 +}
    1.89 +
    1.90 +nsXREDirProvider*
    1.91 +nsXREDirProvider::GetSingleton()
    1.92 +{
    1.93 +  return gDirServiceProvider;
    1.94 +}
    1.95 +
    1.96 +nsresult
    1.97 +nsXREDirProvider::Initialize(nsIFile *aXULAppDir,
    1.98 +                             nsIFile *aGREDir,
    1.99 +                             nsIDirectoryServiceProvider* aAppProvider)
   1.100 +{
   1.101 +  NS_ENSURE_ARG(aXULAppDir);
   1.102 +  NS_ENSURE_ARG(aGREDir);
   1.103 +
   1.104 +  mAppProvider = aAppProvider;
   1.105 +  mXULAppDir = aXULAppDir;
   1.106 +  mGREDir = aGREDir;
   1.107 +
   1.108 +  if (!mProfileDir) {
   1.109 +    nsCOMPtr<nsIDirectoryServiceProvider> app(do_QueryInterface(mAppProvider));
   1.110 +    if (app) {
   1.111 +      bool per = false;
   1.112 +      app->GetFile(NS_APP_USER_PROFILE_50_DIR, &per, getter_AddRefs(mProfileDir));
   1.113 +      NS_ASSERTION(per, "NS_APP_USER_PROFILE_50_DIR must be persistent!"); 
   1.114 +      NS_ASSERTION(mProfileDir, "NS_APP_USER_PROFILE_50_DIR not defined! This shouldn't happen!"); 
   1.115 +    }
   1.116 +  }
   1.117 +
   1.118 +  LoadAppBundleDirs();
   1.119 +  return NS_OK;
   1.120 +}
   1.121 +
   1.122 +nsresult
   1.123 +nsXREDirProvider::SetProfile(nsIFile* aDir, nsIFile* aLocalDir)
   1.124 +{
   1.125 +  NS_ASSERTION(aDir && aLocalDir, "We don't support no-profile apps yet!");
   1.126 +
   1.127 +  nsresult rv;
   1.128 +
   1.129 +  rv = EnsureDirectoryExists(aDir);
   1.130 +  if (NS_FAILED(rv))
   1.131 +    return rv;
   1.132 +
   1.133 +  rv = EnsureDirectoryExists(aLocalDir);
   1.134 +  if (NS_FAILED(rv))
   1.135 +    return rv;
   1.136 +
   1.137 +#ifdef XP_MACOSX
   1.138 +  bool same;
   1.139 +  if (NS_SUCCEEDED(aDir->Equals(aLocalDir, &same)) && !same) {
   1.140 +    // Ensure that the cache directory is not indexed by Spotlight
   1.141 +    // (bug 718910).  At least on OS X, the cache directory (under
   1.142 +    // ~/Library/Caches/) is always the "local" user profile
   1.143 +    // directory.  This is confusing, since *both* user profile
   1.144 +    // directories are "local" (they both exist under the user's
   1.145 +    // home directory).  But this usage dates back at least as far
   1.146 +    // as the patch for bug 291033, where "local" seems to mean
   1.147 +    // "suitable for temporary storage".  Don't hide the cache
   1.148 +    // directory if by some chance it and the "non-local" profile
   1.149 +    // directory are the same -- there are bad side effects from
   1.150 +    // hiding a profile directory under /Library/Application Support/
   1.151 +    // (see bug 801883).
   1.152 +    nsAutoCString cacheDir;
   1.153 +    if (NS_SUCCEEDED(aLocalDir->GetNativePath(cacheDir))) {
   1.154 +      if (chflags(cacheDir.get(), UF_HIDDEN)) {
   1.155 +        NS_WARNING("Failed to set Cache directory to HIDDEN.");
   1.156 +      }
   1.157 +    }
   1.158 +  }
   1.159 +#endif
   1.160 +
   1.161 +  mProfileDir = aDir;
   1.162 +  mProfileLocalDir = aLocalDir;
   1.163 +  return NS_OK;
   1.164 +}
   1.165 +
   1.166 +NS_IMPL_QUERY_INTERFACE(nsXREDirProvider,
   1.167 +                        nsIDirectoryServiceProvider,
   1.168 +                        nsIDirectoryServiceProvider2,
   1.169 +                        nsIProfileStartup)
   1.170 +
   1.171 +NS_IMETHODIMP_(MozExternalRefCountType)
   1.172 +nsXREDirProvider::AddRef()
   1.173 +{
   1.174 +  return 1;
   1.175 +}
   1.176 +
   1.177 +NS_IMETHODIMP_(MozExternalRefCountType)
   1.178 +nsXREDirProvider::Release()
   1.179 +{
   1.180 +  return 0;
   1.181 +}
   1.182 +
   1.183 +nsresult
   1.184 +nsXREDirProvider::GetUserProfilesRootDir(nsIFile** aResult,
   1.185 +                                         const nsACString* aProfileName,
   1.186 +                                         const nsACString* aAppName,
   1.187 +                                         const nsACString* aVendorName)
   1.188 +{
   1.189 +  nsCOMPtr<nsIFile> file;
   1.190 +  nsresult rv = GetUserDataDirectory(getter_AddRefs(file),
   1.191 +                                     false,
   1.192 +                                     aProfileName, aAppName, aVendorName);
   1.193 +
   1.194 +  if (NS_SUCCEEDED(rv)) {
   1.195 +    // We must create the profile directory here if it does not exist.
   1.196 +    nsresult tmp = EnsureDirectoryExists(file);
   1.197 +    if (NS_FAILED(tmp)) {
   1.198 +      rv = tmp;
   1.199 +    }
   1.200 +  }
   1.201 +  file.swap(*aResult);
   1.202 +  return rv;
   1.203 +}
   1.204 +
   1.205 +nsresult
   1.206 +nsXREDirProvider::GetUserProfilesLocalDir(nsIFile** aResult,
   1.207 +                                          const nsACString* aProfileName,
   1.208 +                                          const nsACString* aAppName,
   1.209 +                                          const nsACString* aVendorName)
   1.210 +{
   1.211 +  nsCOMPtr<nsIFile> file;
   1.212 +  nsresult rv = GetUserDataDirectory(getter_AddRefs(file),
   1.213 +                                     true,
   1.214 +                                     aProfileName, aAppName, aVendorName);
   1.215 +
   1.216 +  if (NS_SUCCEEDED(rv)) {
   1.217 +    // We must create the profile directory here if it does not exist.
   1.218 +    nsresult tmp = EnsureDirectoryExists(file);
   1.219 +    if (NS_FAILED(tmp)) {
   1.220 +      rv = tmp;
   1.221 +    }
   1.222 +  }
   1.223 +  file.swap(*aResult);
   1.224 +  return NS_OK;
   1.225 +}
   1.226 +
   1.227 +NS_IMETHODIMP
   1.228 +nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
   1.229 +			  nsIFile** aFile)
   1.230 +{
   1.231 +  nsresult rv;
   1.232 +
   1.233 +  bool gettingProfile = false;
   1.234 +
   1.235 +  if (!strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR)) {
   1.236 +    // If XRE_NotifyProfile hasn't been called, don't fall through to
   1.237 +    // mAppProvider on the profile keys.
   1.238 +    if (!mProfileNotified)
   1.239 +      return NS_ERROR_FAILURE;
   1.240 +
   1.241 +    if (mProfileLocalDir)
   1.242 +      return mProfileLocalDir->Clone(aFile);
   1.243 +
   1.244 +    if (mAppProvider)
   1.245 +      return mAppProvider->GetFile(aProperty, aPersistent, aFile);
   1.246 +
   1.247 +    // This falls through to the case below
   1.248 +    gettingProfile = true;
   1.249 +  }
   1.250 +  if (!strcmp(aProperty, NS_APP_USER_PROFILE_50_DIR) || gettingProfile) {
   1.251 +    if (!mProfileNotified)
   1.252 +      return NS_ERROR_FAILURE;
   1.253 +
   1.254 +    if (mProfileDir)
   1.255 +      return mProfileDir->Clone(aFile);
   1.256 +
   1.257 +    if (mAppProvider)
   1.258 +      return mAppProvider->GetFile(aProperty, aPersistent, aFile);
   1.259 +
   1.260 +    // If we don't succeed here, bail early so that we aren't reentrant
   1.261 +    // through the "GetProfileDir" call below.
   1.262 +    return NS_ERROR_FAILURE;
   1.263 +  }
   1.264 +
   1.265 +  if (mAppProvider) {
   1.266 +    rv = mAppProvider->GetFile(aProperty, aPersistent, aFile);
   1.267 +    if (NS_SUCCEEDED(rv) && *aFile)
   1.268 +      return rv;
   1.269 +  }
   1.270 +
   1.271 +  *aPersistent = true;
   1.272 +
   1.273 +  if (!strcmp(aProperty, NS_GRE_DIR)) {
   1.274 +    return mGREDir->Clone(aFile);
   1.275 +  }
   1.276 +  else if (!strcmp(aProperty, NS_OS_CURRENT_PROCESS_DIR) ||
   1.277 +      !strcmp(aProperty, NS_APP_INSTALL_CLEANUP_DIR)) {
   1.278 +    return GetAppDir()->Clone(aFile);
   1.279 +  }
   1.280 +
   1.281 +  rv = NS_ERROR_FAILURE;
   1.282 +  nsCOMPtr<nsIFile> file;
   1.283 +
   1.284 +  if (!strcmp(aProperty, NS_APP_PROFILE_DEFAULTS_50_DIR) ||
   1.285 +           !strcmp(aProperty, NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR)) {
   1.286 +    return GetProfileDefaultsDir(aFile);
   1.287 +  }
   1.288 +  else if (!strcmp(aProperty, NS_APP_PREF_DEFAULTS_50_DIR))
   1.289 +  {
   1.290 +    // return the GRE default prefs directory here, and the app default prefs
   1.291 +    // directory (if applicable) in NS_APP_PREFS_DEFAULTS_DIR_LIST.
   1.292 +    rv = mGREDir->Clone(getter_AddRefs(file));
   1.293 +    if (NS_SUCCEEDED(rv)) {
   1.294 +      rv = file->AppendNative(NS_LITERAL_CSTRING("defaults"));
   1.295 +      if (NS_SUCCEEDED(rv))
   1.296 +        rv = file->AppendNative(NS_LITERAL_CSTRING("pref"));
   1.297 +    }
   1.298 +  }
   1.299 +  else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_DIR) ||
   1.300 +           !strcmp(aProperty, XRE_USER_APP_DATA_DIR)) {
   1.301 +    rv = GetUserAppDataDirectory(getter_AddRefs(file));
   1.302 +  }
   1.303 +  else if (!strcmp(aProperty, XRE_UPDATE_ROOT_DIR)) {
   1.304 +    rv = GetUpdateRootDir(getter_AddRefs(file));
   1.305 +  }
   1.306 +  else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_FILE)) {
   1.307 +    rv = GetUserAppDataDirectory(getter_AddRefs(file));
   1.308 +    if (NS_SUCCEEDED(rv))
   1.309 +      rv = file->AppendNative(NS_LITERAL_CSTRING(APP_REGISTRY_NAME));
   1.310 +  }
   1.311 +  else if (!strcmp(aProperty, NS_APP_USER_PROFILES_ROOT_DIR)) {
   1.312 +    rv = GetUserProfilesRootDir(getter_AddRefs(file), nullptr, nullptr, nullptr);
   1.313 +  }
   1.314 +  else if (!strcmp(aProperty, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR)) {
   1.315 +    rv = GetUserProfilesLocalDir(getter_AddRefs(file), nullptr, nullptr, nullptr);
   1.316 +  }
   1.317 +  else if (!strcmp(aProperty, XRE_EXECUTABLE_FILE) && gArgv[0]) {
   1.318 +    nsCOMPtr<nsIFile> lf;
   1.319 +    rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
   1.320 +    if (NS_SUCCEEDED(rv))
   1.321 +      file = lf;
   1.322 +  }
   1.323 +
   1.324 +  else if (!strcmp(aProperty, NS_APP_PROFILE_DIR_STARTUP) && mProfileDir) {
   1.325 +    return mProfileDir->Clone(aFile);
   1.326 +  }
   1.327 +  else if (!strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP)) {
   1.328 +    if (mProfileLocalDir)
   1.329 +      return mProfileLocalDir->Clone(aFile);
   1.330 +
   1.331 +    if (mProfileDir)
   1.332 +      return mProfileDir->Clone(aFile);
   1.333 +
   1.334 +    if (mAppProvider)
   1.335 +      return mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP, aPersistent,
   1.336 +                                   aFile);
   1.337 +  }
   1.338 +#if defined(XP_UNIX) || defined(XP_MACOSX)
   1.339 +  else if (!strcmp(aProperty, XRE_SYS_LOCAL_EXTENSION_PARENT_DIR)) {
   1.340 +#ifdef ENABLE_SYSTEM_EXTENSION_DIRS
   1.341 +    return GetSystemExtensionsDirectory(aFile);
   1.342 +#else
   1.343 +    return NS_ERROR_FAILURE;
   1.344 +#endif
   1.345 +  }
   1.346 +#endif
   1.347 +#if defined(XP_UNIX) && !defined(XP_MACOSX)
   1.348 +  else if (!strcmp(aProperty, XRE_SYS_SHARE_EXTENSION_PARENT_DIR)) {
   1.349 +#ifdef ENABLE_SYSTEM_EXTENSION_DIRS
   1.350 +#if defined(__OpenBSD__) || defined(__FreeBSD__)
   1.351 +    static const char *const sysLExtDir = "/usr/local/share/mozilla/extensions";
   1.352 +#else
   1.353 +    static const char *const sysLExtDir = "/usr/share/mozilla/extensions";
   1.354 +#endif
   1.355 +    return NS_NewNativeLocalFile(nsDependentCString(sysLExtDir),
   1.356 +                                 false, aFile);
   1.357 +#else
   1.358 +    return NS_ERROR_FAILURE;
   1.359 +#endif
   1.360 +  }
   1.361 +#endif
   1.362 +  else if (!strcmp(aProperty, XRE_USER_SYS_EXTENSION_DIR)) {
   1.363 +#ifdef ENABLE_SYSTEM_EXTENSION_DIRS
   1.364 +    return GetSysUserExtensionsDirectory(aFile);
   1.365 +#else
   1.366 +    return NS_ERROR_FAILURE;
   1.367 +#endif
   1.368 +  }
   1.369 +  else if (!strcmp(aProperty, XRE_APP_DISTRIBUTION_DIR)) {
   1.370 +    bool persistent = false;
   1.371 +    rv = GetFile(XRE_EXECUTABLE_FILE, &persistent, getter_AddRefs(file));
   1.372 +    if (NS_SUCCEEDED(rv))
   1.373 +      rv = file->SetNativeLeafName(NS_LITERAL_CSTRING("distribution"));
   1.374 +  }
   1.375 +  else if (NS_SUCCEEDED(GetProfileStartupDir(getter_AddRefs(file)))) {
   1.376 +    // We need to allow component, xpt, and chrome registration to
   1.377 +    // occur prior to the profile-after-change notification.
   1.378 +    if (!strcmp(aProperty, NS_APP_USER_CHROME_DIR)) {
   1.379 +      rv = file->AppendNative(NS_LITERAL_CSTRING("chrome"));
   1.380 +    }
   1.381 +  }
   1.382 +
   1.383 +  if (NS_SUCCEEDED(rv) && file) {
   1.384 +    NS_ADDREF(*aFile = file);
   1.385 +    return NS_OK;
   1.386 +  }
   1.387 +
   1.388 +  bool ensureFilePermissions = false;
   1.389 +
   1.390 +  if (NS_SUCCEEDED(GetProfileDir(getter_AddRefs(file)))) {
   1.391 +    if (!strcmp(aProperty, NS_APP_PREFS_50_DIR)) {
   1.392 +      rv = NS_OK;
   1.393 +    }
   1.394 +    else if (!strcmp(aProperty, NS_APP_PREFS_50_FILE)) {
   1.395 +      rv = file->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
   1.396 +    }
   1.397 +    else if (!strcmp(aProperty, NS_METRO_APP_PREFS_50_FILE)) {
   1.398 +      rv = file->AppendNative(NS_LITERAL_CSTRING("metro-prefs.js"));
   1.399 +    }
   1.400 +    else if (!strcmp(aProperty, NS_LOCALSTORE_UNSAFE_FILE)) {
   1.401 +      rv = file->AppendNative(NS_LITERAL_CSTRING("localstore.rdf"));
   1.402 +    }
   1.403 +    else if (!strcmp(aProperty, NS_APP_LOCALSTORE_50_FILE)) {
   1.404 +      if (gSafeMode) {
   1.405 +        rv = file->AppendNative(NS_LITERAL_CSTRING("localstore-safe.rdf"));
   1.406 +        file->Remove(false);
   1.407 +      }
   1.408 +      else {
   1.409 +        rv = file->AppendNative(NS_LITERAL_CSTRING("localstore.rdf"));
   1.410 +        EnsureProfileFileExists(file);
   1.411 +        ensureFilePermissions = true;
   1.412 +      }
   1.413 +    }
   1.414 +    else if (!strcmp(aProperty, NS_APP_USER_MIMETYPES_50_FILE)) {
   1.415 +      rv = file->AppendNative(NS_LITERAL_CSTRING("mimeTypes.rdf"));
   1.416 +      EnsureProfileFileExists(file);
   1.417 +      ensureFilePermissions = true;
   1.418 +    }
   1.419 +    else if (!strcmp(aProperty, NS_APP_DOWNLOADS_50_FILE)) {
   1.420 +      rv = file->AppendNative(NS_LITERAL_CSTRING("downloads.rdf"));
   1.421 +    }
   1.422 +    else if (!strcmp(aProperty, NS_APP_PREFS_OVERRIDE_DIR)) {
   1.423 +      rv = mProfileDir->Clone(getter_AddRefs(file));
   1.424 +      nsresult tmp = file->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
   1.425 +      if (NS_FAILED(tmp)) {
   1.426 +        rv = tmp;
   1.427 +      }
   1.428 +      tmp = EnsureDirectoryExists(file);
   1.429 +      if (NS_FAILED(tmp)) {
   1.430 +        rv = tmp;
   1.431 +      }
   1.432 +    }
   1.433 +  }
   1.434 +  if (NS_FAILED(rv) || !file)
   1.435 +    return NS_ERROR_FAILURE;
   1.436 +
   1.437 +  if (ensureFilePermissions) {
   1.438 +    bool fileToEnsureExists;
   1.439 +    bool isWritable;
   1.440 +    if (NS_SUCCEEDED(file->Exists(&fileToEnsureExists)) && fileToEnsureExists
   1.441 +        && NS_SUCCEEDED(file->IsWritable(&isWritable)) && !isWritable) {
   1.442 +      uint32_t permissions;
   1.443 +      if (NS_SUCCEEDED(file->GetPermissions(&permissions))) {
   1.444 +        rv = file->SetPermissions(permissions | 0600);
   1.445 +        NS_ASSERTION(NS_SUCCEEDED(rv), "failed to ensure file permissions");
   1.446 +      }
   1.447 +    }
   1.448 +  }
   1.449 +
   1.450 +  NS_ADDREF(*aFile = file);
   1.451 +  return NS_OK;
   1.452 +}
   1.453 +
   1.454 +static void
   1.455 +LoadDirIntoArray(nsIFile* dir,
   1.456 +                 const char *const *aAppendList,
   1.457 +                 nsCOMArray<nsIFile>& aDirectories)
   1.458 +{
   1.459 +  if (!dir)
   1.460 +    return;
   1.461 +
   1.462 +  nsCOMPtr<nsIFile> subdir;
   1.463 +  dir->Clone(getter_AddRefs(subdir));
   1.464 +  if (!subdir)
   1.465 +    return;
   1.466 +
   1.467 +  for (const char *const *a = aAppendList; *a; ++a) {
   1.468 +    subdir->AppendNative(nsDependentCString(*a));
   1.469 +  }
   1.470 +
   1.471 +  bool exists;
   1.472 +  if (NS_SUCCEEDED(subdir->Exists(&exists)) && exists) {
   1.473 +    aDirectories.AppendObject(subdir);
   1.474 +  }
   1.475 +}
   1.476 +
   1.477 +static void
   1.478 +LoadDirsIntoArray(nsCOMArray<nsIFile>& aSourceDirs,
   1.479 +                  const char *const* aAppendList,
   1.480 +                  nsCOMArray<nsIFile>& aDirectories)
   1.481 +{
   1.482 +  nsCOMPtr<nsIFile> appended;
   1.483 +  bool exists;
   1.484 +
   1.485 +  for (int32_t i = 0; i < aSourceDirs.Count(); ++i) {
   1.486 +    aSourceDirs[i]->Clone(getter_AddRefs(appended));
   1.487 +    if (!appended)
   1.488 +      continue;
   1.489 +
   1.490 +    nsAutoCString leaf;
   1.491 +    appended->GetNativeLeafName(leaf);
   1.492 +    if (!Substring(leaf, leaf.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi"))) {
   1.493 +      LoadDirIntoArray(appended,
   1.494 +                       aAppendList,
   1.495 +                       aDirectories);
   1.496 +    }
   1.497 +    else if (NS_SUCCEEDED(appended->Exists(&exists)) && exists)
   1.498 +      aDirectories.AppendObject(appended);
   1.499 +  }
   1.500 +}
   1.501 +
   1.502 +NS_IMETHODIMP
   1.503 +nsXREDirProvider::GetFiles(const char* aProperty, nsISimpleEnumerator** aResult)
   1.504 +{
   1.505 +  nsresult rv;
   1.506 +
   1.507 +  nsCOMPtr<nsISimpleEnumerator> appEnum;
   1.508 +  nsCOMPtr<nsIDirectoryServiceProvider2>
   1.509 +    appP2(do_QueryInterface(mAppProvider));
   1.510 +  if (appP2) {
   1.511 +    rv = appP2->GetFiles(aProperty, getter_AddRefs(appEnum));
   1.512 +    if (NS_FAILED(rv)) {
   1.513 +      appEnum = nullptr;
   1.514 +    }
   1.515 +    else if (rv != NS_SUCCESS_AGGREGATE_RESULT) {
   1.516 +      NS_ADDREF(*aResult = appEnum);
   1.517 +      return NS_OK;
   1.518 +    }
   1.519 +  }
   1.520 +
   1.521 +  nsCOMPtr<nsISimpleEnumerator> xreEnum;
   1.522 +  rv = GetFilesInternal(aProperty, getter_AddRefs(xreEnum));
   1.523 +  if (NS_FAILED(rv)) {
   1.524 +    if (appEnum) {
   1.525 +      NS_ADDREF(*aResult = appEnum);
   1.526 +      return NS_SUCCESS_AGGREGATE_RESULT;
   1.527 +    }
   1.528 +
   1.529 +    return rv;
   1.530 +  }
   1.531 +
   1.532 +  rv = NS_NewUnionEnumerator(aResult, appEnum, xreEnum);
   1.533 +  if (NS_FAILED(rv))
   1.534 +    return rv;
   1.535 +
   1.536 +  return NS_SUCCESS_AGGREGATE_RESULT;
   1.537 +}
   1.538 +
   1.539 +static void
   1.540 +LoadExtensionDirectories(nsINIParser &parser,
   1.541 +                         const char *aSection,
   1.542 +                         nsCOMArray<nsIFile> &aDirectories,
   1.543 +                         NSLocationType aType)
   1.544 +{
   1.545 +  nsresult rv;
   1.546 +  int32_t i = 0;
   1.547 +  do {
   1.548 +    nsAutoCString buf("Extension");
   1.549 +    buf.AppendInt(i++);
   1.550 +
   1.551 +    nsAutoCString path;
   1.552 +    rv = parser.GetString(aSection, buf.get(), path);
   1.553 +    if (NS_FAILED(rv))
   1.554 +      return;
   1.555 +
   1.556 +    nsCOMPtr<nsIFile> dir = do_CreateInstance("@mozilla.org/file/local;1", &rv);
   1.557 +    if (NS_FAILED(rv))
   1.558 +      continue;
   1.559 +
   1.560 +    rv = dir->SetPersistentDescriptor(path);
   1.561 +    if (NS_FAILED(rv))
   1.562 +      continue;
   1.563 +
   1.564 +    aDirectories.AppendObject(dir);
   1.565 +    if (Substring(path, path.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi"))) {
   1.566 +      XRE_AddJarManifestLocation(aType, dir);
   1.567 +    }
   1.568 +    else {
   1.569 +      nsCOMPtr<nsIFile> manifest =
   1.570 +        CloneAndAppend(dir, "chrome.manifest");
   1.571 +      XRE_AddManifestLocation(aType, manifest);
   1.572 +    }
   1.573 +  }
   1.574 +  while (true);
   1.575 +}
   1.576 +
   1.577 +void
   1.578 +nsXREDirProvider::LoadExtensionBundleDirectories()
   1.579 +{
   1.580 +  if (!mozilla::Preferences::GetBool("extensions.defaultProviders.enabled", true))
   1.581 +    return;
   1.582 +
   1.583 +  if (mProfileDir && !gSafeMode) {
   1.584 +    nsCOMPtr<nsIFile> extensionsINI;
   1.585 +    mProfileDir->Clone(getter_AddRefs(extensionsINI));
   1.586 +    if (!extensionsINI)
   1.587 +      return;
   1.588 +
   1.589 +    extensionsINI->AppendNative(NS_LITERAL_CSTRING("extensions.ini"));
   1.590 +
   1.591 +    nsCOMPtr<nsIFile> extensionsINILF =
   1.592 +      do_QueryInterface(extensionsINI);
   1.593 +    if (!extensionsINILF)
   1.594 +      return;
   1.595 +
   1.596 +    nsINIParser parser;
   1.597 +    nsresult rv = parser.Init(extensionsINILF);
   1.598 +    if (NS_FAILED(rv))
   1.599 +      return;
   1.600 +
   1.601 +    LoadExtensionDirectories(parser, "ExtensionDirs", mExtensionDirectories,
   1.602 +                             NS_COMPONENT_LOCATION);
   1.603 +    LoadExtensionDirectories(parser, "ThemeDirs", mThemeDirectories,
   1.604 +                             NS_SKIN_LOCATION);
   1.605 +  }
   1.606 +}
   1.607 +
   1.608 +void
   1.609 +nsXREDirProvider::LoadAppBundleDirs()
   1.610 +{
   1.611 +  nsCOMPtr<nsIFile> dir;
   1.612 +  bool persistent = false;
   1.613 +  nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &persistent, getter_AddRefs(dir));
   1.614 +  if (NS_FAILED(rv))
   1.615 +    return;
   1.616 +
   1.617 +  dir->SetNativeLeafName(NS_LITERAL_CSTRING("distribution"));
   1.618 +  dir->AppendNative(NS_LITERAL_CSTRING("bundles"));
   1.619 +
   1.620 +  nsCOMPtr<nsISimpleEnumerator> e;
   1.621 +  rv = dir->GetDirectoryEntries(getter_AddRefs(e));
   1.622 +  if (NS_FAILED(rv))
   1.623 +    return;
   1.624 +
   1.625 +  nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e);
   1.626 +  if (!files)
   1.627 +    return;
   1.628 +
   1.629 +  nsCOMPtr<nsIFile> subdir;
   1.630 +  while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(subdir))) && subdir) {
   1.631 +    mAppBundleDirectories.AppendObject(subdir);
   1.632 +
   1.633 +    nsCOMPtr<nsIFile> manifest =
   1.634 +      CloneAndAppend(subdir, "chrome.manifest");
   1.635 +    XRE_AddManifestLocation(NS_COMPONENT_LOCATION, manifest);
   1.636 +  }
   1.637 +}
   1.638 +
   1.639 +static const char *const kAppendPrefDir[] = { "defaults", "preferences", nullptr };
   1.640 +
   1.641 +#ifdef DEBUG_bsmedberg
   1.642 +static void
   1.643 +DumpFileArray(const char *key,
   1.644 +              nsCOMArray<nsIFile> dirs)
   1.645 +{
   1.646 +  fprintf(stderr, "nsXREDirProvider::GetFilesInternal(%s)\n", key);
   1.647 +
   1.648 +  nsAutoCString path;
   1.649 +  for (int32_t i = 0; i < dirs.Count(); ++i) {
   1.650 +    dirs[i]->GetNativePath(path);
   1.651 +    fprintf(stderr, "  %s\n", path.get());
   1.652 +  }
   1.653 +}
   1.654 +#endif // DEBUG_bsmedberg
   1.655 +
   1.656 +nsresult
   1.657 +nsXREDirProvider::GetFilesInternal(const char* aProperty,
   1.658 +                                   nsISimpleEnumerator** aResult)
   1.659 +{
   1.660 +  nsresult rv = NS_OK;
   1.661 +  *aResult = nullptr;
   1.662 +
   1.663 +  if (!strcmp(aProperty, XRE_EXTENSIONS_DIR_LIST)) {
   1.664 +    nsCOMArray<nsIFile> directories;
   1.665 +
   1.666 +    static const char *const kAppendNothing[] = { nullptr };
   1.667 +
   1.668 +    LoadDirsIntoArray(mAppBundleDirectories,
   1.669 +                      kAppendNothing, directories);
   1.670 +    LoadDirsIntoArray(mExtensionDirectories,
   1.671 +                      kAppendNothing, directories);
   1.672 +
   1.673 +    rv = NS_NewArrayEnumerator(aResult, directories);
   1.674 +  }
   1.675 +  else if (!strcmp(aProperty, NS_APP_PREFS_DEFAULTS_DIR_LIST)) {
   1.676 +    nsCOMArray<nsIFile> directories;
   1.677 +
   1.678 +    LoadDirIntoArray(mXULAppDir, kAppendPrefDir, directories);
   1.679 +    LoadDirsIntoArray(mAppBundleDirectories,
   1.680 +                      kAppendPrefDir, directories);
   1.681 +
   1.682 +    rv = NS_NewArrayEnumerator(aResult, directories);
   1.683 +  }
   1.684 +  else if (!strcmp(aProperty, NS_EXT_PREFS_DEFAULTS_DIR_LIST)) {
   1.685 +    nsCOMArray<nsIFile> directories;
   1.686 +
   1.687 +    LoadDirsIntoArray(mExtensionDirectories,
   1.688 +                      kAppendPrefDir, directories);
   1.689 +
   1.690 +    if (mProfileDir) {
   1.691 +      nsCOMPtr<nsIFile> overrideFile;
   1.692 +      mProfileDir->Clone(getter_AddRefs(overrideFile));
   1.693 +      overrideFile->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
   1.694 +
   1.695 +      bool exists;
   1.696 +      if (NS_SUCCEEDED(overrideFile->Exists(&exists)) && exists)
   1.697 +        directories.AppendObject(overrideFile);
   1.698 +    }
   1.699 +
   1.700 +    rv = NS_NewArrayEnumerator(aResult, directories);
   1.701 +  }
   1.702 +  else if (!strcmp(aProperty, NS_APP_CHROME_DIR_LIST)) {
   1.703 +    // NS_APP_CHROME_DIR_LIST is only used to get default (native) icons
   1.704 +    // for OS window decoration.
   1.705 +
   1.706 +    static const char *const kAppendChromeDir[] = { "chrome", nullptr };
   1.707 +    nsCOMArray<nsIFile> directories;
   1.708 +    LoadDirIntoArray(mXULAppDir,
   1.709 +                     kAppendChromeDir,
   1.710 +                     directories);
   1.711 +    LoadDirsIntoArray(mAppBundleDirectories,
   1.712 +                      kAppendChromeDir,
   1.713 +                      directories);
   1.714 +    LoadDirsIntoArray(mExtensionDirectories,
   1.715 +                      kAppendChromeDir,
   1.716 +                      directories);
   1.717 +
   1.718 +    rv = NS_NewArrayEnumerator(aResult, directories);
   1.719 +  }
   1.720 +  else if (!strcmp(aProperty, NS_APP_PLUGINS_DIR_LIST)) {
   1.721 +    nsCOMArray<nsIFile> directories;
   1.722 +
   1.723 +    if (mozilla::Preferences::GetBool("plugins.load_appdir_plugins", false)) {
   1.724 +      nsCOMPtr<nsIFile> appdir;
   1.725 +      rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(appdir));
   1.726 +      if (NS_SUCCEEDED(rv)) {
   1.727 +        appdir->SetNativeLeafName(NS_LITERAL_CSTRING("plugins"));
   1.728 +        directories.AppendObject(appdir);
   1.729 +      }
   1.730 +    }
   1.731 +
   1.732 +    static const char *const kAppendPlugins[] = { "plugins", nullptr };
   1.733 +
   1.734 +    // The root dirserviceprovider does quite a bit for us: we're mainly
   1.735 +    // interested in xulapp and extension-provided plugins.
   1.736 +    LoadDirsIntoArray(mAppBundleDirectories,
   1.737 +                      kAppendPlugins,
   1.738 +                      directories);
   1.739 +    LoadDirsIntoArray(mExtensionDirectories,
   1.740 +                      kAppendPlugins,
   1.741 +                      directories);
   1.742 +
   1.743 +    if (mProfileDir) {
   1.744 +      nsCOMArray<nsIFile> profileDir;
   1.745 +      profileDir.AppendObject(mProfileDir);
   1.746 +      LoadDirsIntoArray(profileDir,
   1.747 +                        kAppendPlugins,
   1.748 +                        directories);
   1.749 +    }
   1.750 +
   1.751 +    rv = NS_NewArrayEnumerator(aResult, directories);
   1.752 +    NS_ENSURE_SUCCESS(rv, rv);
   1.753 +
   1.754 +    rv = NS_SUCCESS_AGGREGATE_RESULT;
   1.755 +  }
   1.756 +  else
   1.757 +    rv = NS_ERROR_FAILURE;
   1.758 +
   1.759 +  return rv;
   1.760 +}
   1.761 +
   1.762 +NS_IMETHODIMP
   1.763 +nsXREDirProvider::GetDirectory(nsIFile* *aResult)
   1.764 +{
   1.765 +  NS_ENSURE_TRUE(mProfileDir, NS_ERROR_NOT_INITIALIZED);
   1.766 +
   1.767 +  return mProfileDir->Clone(aResult);
   1.768 +}
   1.769 +
   1.770 +NS_IMETHODIMP
   1.771 +nsXREDirProvider::DoStartup()
   1.772 +{
   1.773 +  if (!mProfileNotified) {
   1.774 +    nsCOMPtr<nsIObserverService> obsSvc =
   1.775 +      mozilla::services::GetObserverService();
   1.776 +    if (!obsSvc) return NS_ERROR_FAILURE;
   1.777 +
   1.778 +    mProfileNotified = true;
   1.779 +
   1.780 +    /*
   1.781 +       Setup prefs before profile-do-change to be able to use them to track
   1.782 +       crashes and because we want to begin crash tracking before other code run
   1.783 +       from this notification since they may cause crashes.
   1.784 +    */
   1.785 +    nsresult rv = mozilla::Preferences::ResetAndReadUserPrefs();
   1.786 +    if (NS_FAILED(rv)) NS_WARNING("Failed to setup pref service.");
   1.787 +
   1.788 +    bool safeModeNecessary = false;
   1.789 +    nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
   1.790 +    if (appStartup) {
   1.791 +      rv = appStartup->TrackStartupCrashBegin(&safeModeNecessary);
   1.792 +      if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE)
   1.793 +        NS_WARNING("Error while beginning startup crash tracking");
   1.794 +
   1.795 +      if (!gSafeMode && safeModeNecessary) {
   1.796 +        appStartup->RestartInSafeMode(nsIAppStartup::eForceQuit);
   1.797 +        return NS_OK;
   1.798 +      }
   1.799 +    }
   1.800 +
   1.801 +    static const char16_t kStartup[] = {'s','t','a','r','t','u','p','\0'};
   1.802 +    obsSvc->NotifyObservers(nullptr, "profile-do-change", kStartup);
   1.803 +    // Init the Extension Manager
   1.804 +    nsCOMPtr<nsIObserver> em = do_GetService("@mozilla.org/addons/integration;1");
   1.805 +    if (em) {
   1.806 +      em->Observe(nullptr, "addons-startup", nullptr);
   1.807 +    } else {
   1.808 +      NS_WARNING("Failed to create Addons Manager.");
   1.809 +    }
   1.810 +
   1.811 +    LoadExtensionBundleDirectories();
   1.812 +
   1.813 +    obsSvc->NotifyObservers(nullptr, "load-extension-defaults", nullptr);
   1.814 +    obsSvc->NotifyObservers(nullptr, "profile-after-change", kStartup);
   1.815 +
   1.816 +    // Any component that has registered for the profile-after-change category
   1.817 +    // should also be created at this time.
   1.818 +    (void)NS_CreateServicesFromCategory("profile-after-change", nullptr,
   1.819 +                                        "profile-after-change");
   1.820 +
   1.821 +    if (gSafeMode && safeModeNecessary) {
   1.822 +      static const char16_t kCrashed[] = {'c','r','a','s','h','e','d','\0'};
   1.823 +      obsSvc->NotifyObservers(nullptr, "safemode-forced", kCrashed);
   1.824 +    }
   1.825 +
   1.826 +    // 1 = Regular mode, 2 = Safe mode, 3 = Safe mode forced
   1.827 +    int mode = 1;
   1.828 +    if (gSafeMode) {
   1.829 +      if (safeModeNecessary)
   1.830 +        mode = 3;
   1.831 +      else
   1.832 +        mode = 2;
   1.833 +    }
   1.834 +    mozilla::Telemetry::Accumulate(mozilla::Telemetry::SAFE_MODE_USAGE, mode);
   1.835 +
   1.836 +    obsSvc->NotifyObservers(nullptr, "profile-initial-state", nullptr);
   1.837 +  }
   1.838 +  return NS_OK;
   1.839 +}
   1.840 +
   1.841 +void
   1.842 +nsXREDirProvider::DoShutdown()
   1.843 +{
   1.844 +  if (mProfileNotified) {
   1.845 +    nsCOMPtr<nsIObserverService> obsSvc =
   1.846 +      mozilla::services::GetObserverService();
   1.847 +    NS_ASSERTION(obsSvc, "No observer service?");
   1.848 +    if (obsSvc) {
   1.849 +      static const char16_t kShutdownPersist[] =
   1.850 +        {'s','h','u','t','d','o','w','n','-','p','e','r','s','i','s','t','\0'};
   1.851 +      obsSvc->NotifyObservers(nullptr, "profile-change-net-teardown", kShutdownPersist);
   1.852 +      obsSvc->NotifyObservers(nullptr, "profile-change-teardown", kShutdownPersist);
   1.853 +
   1.854 +      // Phase 2c: Now that things are torn down, force JS GC so that things which depend on
   1.855 +      // resources which are about to go away in "profile-before-change" are destroyed first.
   1.856 +
   1.857 +      nsCOMPtr<nsIJSRuntimeService> rtsvc
   1.858 +        (do_GetService("@mozilla.org/js/xpc/RuntimeService;1"));
   1.859 +      if (rtsvc)
   1.860 +      {
   1.861 +        JSRuntime *rt = nullptr;
   1.862 +        rtsvc->GetRuntime(&rt);
   1.863 +        if (rt)
   1.864 +          ::JS_GC(rt);
   1.865 +      }
   1.866 +
   1.867 +      // Phase 3: Notify observers of a profile change
   1.868 +      obsSvc->NotifyObservers(nullptr, "profile-before-change", kShutdownPersist);
   1.869 +      obsSvc->NotifyObservers(nullptr, "profile-before-change2", kShutdownPersist);
   1.870 +    }
   1.871 +    mProfileNotified = false;
   1.872 +  }
   1.873 +}
   1.874 +
   1.875 +#ifdef XP_WIN
   1.876 +static nsresult
   1.877 +GetShellFolderPath(int folder, nsAString& _retval)
   1.878 +{
   1.879 +  wchar_t* buf;
   1.880 +  uint32_t bufLength = _retval.GetMutableData(&buf, MAXPATHLEN + 3);
   1.881 +  NS_ENSURE_TRUE(bufLength >= (MAXPATHLEN + 3), NS_ERROR_OUT_OF_MEMORY);
   1.882 +
   1.883 +  nsresult rv = NS_OK;
   1.884 +
   1.885 +  LPITEMIDLIST pItemIDList = nullptr;
   1.886 +
   1.887 +  if (SUCCEEDED(SHGetSpecialFolderLocation(nullptr, folder, &pItemIDList)) &&
   1.888 +      SHGetPathFromIDListW(pItemIDList, buf)) {
   1.889 +    // We're going to use wcslen (wcsnlen not available in msvc7.1) so make
   1.890 +    // sure to null terminate.
   1.891 +    buf[bufLength - 1] = L'\0';
   1.892 +    _retval.SetLength(wcslen(buf));
   1.893 +  } else {
   1.894 +    _retval.SetLength(0);
   1.895 +    rv = NS_ERROR_NOT_AVAILABLE;
   1.896 +  }
   1.897 +
   1.898 +  CoTaskMemFree(pItemIDList);
   1.899 +
   1.900 +  return rv;
   1.901 +}
   1.902 +
   1.903 +/**
   1.904 + * Provides a fallback for getting the path to APPDATA or LOCALAPPDATA by
   1.905 + * querying the registry when the call to SHGetSpecialFolderLocation or
   1.906 + * SHGetPathFromIDListW is unable to provide these paths (Bug 513958).
   1.907 + */
   1.908 +static nsresult
   1.909 +GetRegWindowsAppDataFolder(bool aLocal, nsAString& _retval)
   1.910 +{
   1.911 +  HKEY key;
   1.912 +  NS_NAMED_LITERAL_STRING(keyName,
   1.913 +  "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
   1.914 +  DWORD res = ::RegOpenKeyExW(HKEY_CURRENT_USER, keyName.get(), 0, KEY_READ,
   1.915 +                              &key);
   1.916 +  if (res != ERROR_SUCCESS) {
   1.917 +    _retval.SetLength(0);
   1.918 +    return NS_ERROR_NOT_AVAILABLE;
   1.919 +  }
   1.920 +
   1.921 +  DWORD type, size;
   1.922 +  res = RegQueryValueExW(key, (aLocal ? L"Local AppData" : L"AppData"),
   1.923 +                         nullptr, &type, nullptr, &size);
   1.924 +  // The call to RegQueryValueExW must succeed, the type must be REG_SZ, the
   1.925 +  // buffer size must not equal 0, and the buffer size be a multiple of 2.
   1.926 +  if (res != ERROR_SUCCESS || type != REG_SZ || size == 0 || size % 2 != 0) {
   1.927 +    ::RegCloseKey(key);
   1.928 +    _retval.SetLength(0);
   1.929 +    return NS_ERROR_NOT_AVAILABLE;
   1.930 +  }
   1.931 +
   1.932 +  // |size| may or may not include room for the terminating null character
   1.933 +  DWORD resultLen = size / 2;
   1.934 +
   1.935 +  _retval.SetLength(resultLen);
   1.936 +  nsAString::iterator begin;
   1.937 +  _retval.BeginWriting(begin);
   1.938 +  if (begin.size_forward() != resultLen) {
   1.939 +    ::RegCloseKey(key);
   1.940 +    _retval.SetLength(0);
   1.941 +    return NS_ERROR_NOT_AVAILABLE;
   1.942 +  }
   1.943 +
   1.944 +  res = RegQueryValueExW(key, (aLocal ? L"Local AppData" : L"AppData"),
   1.945 +                         nullptr, nullptr, (LPBYTE) begin.get(), &size);
   1.946 +  ::RegCloseKey(key);
   1.947 +  if (res != ERROR_SUCCESS) {
   1.948 +    _retval.SetLength(0);
   1.949 +    return NS_ERROR_NOT_AVAILABLE;
   1.950 +  }
   1.951 +
   1.952 +  if (!_retval.CharAt(resultLen - 1)) {
   1.953 +    // It was already null terminated.
   1.954 +    _retval.Truncate(resultLen - 1);
   1.955 +  }
   1.956 +
   1.957 +  return NS_OK;
   1.958 +}
   1.959 +
   1.960 +static bool
   1.961 +GetCachedHash(HKEY rootKey, const nsAString &regPath, const nsAString &path,
   1.962 +              nsAString &cachedHash)
   1.963 +{
   1.964 +  HKEY baseKey;
   1.965 +  if (RegOpenKeyExW(rootKey, reinterpret_cast<const wchar_t*>(regPath.BeginReading()), 0, KEY_READ, &baseKey) !=
   1.966 +      ERROR_SUCCESS) {
   1.967 +    return false;
   1.968 +  }
   1.969 +
   1.970 +  wchar_t cachedHashRaw[512];
   1.971 +  DWORD bufferSize = sizeof(cachedHashRaw);
   1.972 +  LONG result = RegQueryValueExW(baseKey, reinterpret_cast<const wchar_t*>(path.BeginReading()), 0, nullptr,
   1.973 +                                 (LPBYTE)cachedHashRaw, &bufferSize);
   1.974 +  RegCloseKey(baseKey);
   1.975 +  if (result == ERROR_SUCCESS) {
   1.976 +    cachedHash.Assign(cachedHashRaw);
   1.977 +  }
   1.978 +  return ERROR_SUCCESS == result;
   1.979 +}
   1.980 +
   1.981 +#endif
   1.982 +
   1.983 +nsresult
   1.984 +nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
   1.985 +{
   1.986 +  nsCOMPtr<nsIFile> updRoot;
   1.987 +#if defined(MOZ_WIDGET_GONK)
   1.988 +
   1.989 +  nsresult rv = NS_NewNativeLocalFile(nsDependentCString("/data/local"),
   1.990 +                                      true,
   1.991 +                                      getter_AddRefs(updRoot));
   1.992 +  NS_ENSURE_SUCCESS(rv, rv);
   1.993 +
   1.994 +#else
   1.995 +  nsCOMPtr<nsIFile> appFile;
   1.996 +  bool per = false;
   1.997 +  nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(appFile));
   1.998 +  NS_ENSURE_SUCCESS(rv, rv);
   1.999 +  rv = appFile->GetParent(getter_AddRefs(updRoot));
  1.1000 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1001 +
  1.1002 +#ifdef XP_WIN
  1.1003 +
  1.1004 +  nsAutoString pathHash;
  1.1005 +  bool pathHashResult = false;
  1.1006 +  bool hasVendor = gAppData->vendor && strlen(gAppData->vendor) != 0;
  1.1007 +
  1.1008 +  nsAutoString appDirPath;
  1.1009 +  if (SUCCEEDED(updRoot->GetPath(appDirPath))) {
  1.1010 +
  1.1011 +    // Figure out where we should check for a cached hash value. If the
  1.1012 +    // application doesn't have the nsXREAppData vendor value defined check
  1.1013 +    // under SOFTWARE\Mozilla.
  1.1014 +    wchar_t regPath[1024] = { L'\0' };
  1.1015 +    swprintf_s(regPath, mozilla::ArrayLength(regPath), L"SOFTWARE\\%S\\%S\\TaskBarIDs",
  1.1016 +               (hasVendor ? gAppData->vendor : "Mozilla"), MOZ_APP_BASENAME);
  1.1017 +
  1.1018 +    // If we pre-computed the hash, grab it from the registry.
  1.1019 +    pathHashResult = GetCachedHash(HKEY_LOCAL_MACHINE,
  1.1020 +                                   nsDependentString(regPath), appDirPath,
  1.1021 +                                   pathHash);
  1.1022 +    if (!pathHashResult) {
  1.1023 +      pathHashResult = GetCachedHash(HKEY_CURRENT_USER,
  1.1024 +                                     nsDependentString(regPath), appDirPath,
  1.1025 +                                     pathHash);
  1.1026 +    }
  1.1027 +  }
  1.1028 +
  1.1029 +  // Get the local app data directory and if a vendor name exists append it.
  1.1030 +  // If only a product name exists, append it.  If neither exist fallback to
  1.1031 +  // old handling.  We don't use the product name on purpose because we want a
  1.1032 +  // shared update directory for different apps run from the same path (like
  1.1033 +  // Metro & Desktop).
  1.1034 +  nsCOMPtr<nsIFile> localDir;
  1.1035 +  if (pathHashResult && (hasVendor || gAppData->name) &&
  1.1036 +      NS_SUCCEEDED(GetUserDataDirectoryHome(getter_AddRefs(localDir), true)) &&
  1.1037 +      NS_SUCCEEDED(localDir->AppendNative(nsDependentCString(hasVendor ?
  1.1038 +                                          gAppData->vendor : gAppData->name))) &&
  1.1039 +      NS_SUCCEEDED(localDir->Append(NS_LITERAL_STRING("updates"))) &&
  1.1040 +      NS_SUCCEEDED(localDir->Append(pathHash))) {
  1.1041 +    NS_ADDREF(*aResult = localDir);
  1.1042 +    return NS_OK;
  1.1043 +  }
  1.1044 +
  1.1045 +  nsAutoString appPath;
  1.1046 +  rv = updRoot->GetPath(appPath);
  1.1047 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1048 +
  1.1049 +  // AppDir may be a short path. Convert to long path to make sure
  1.1050 +  // the consistency of the update folder location
  1.1051 +  nsString longPath;
  1.1052 +  wchar_t* buf;
  1.1053 +
  1.1054 +  uint32_t bufLength = longPath.GetMutableData(&buf, MAXPATHLEN);
  1.1055 +  NS_ENSURE_TRUE(bufLength >= MAXPATHLEN, NS_ERROR_OUT_OF_MEMORY);
  1.1056 +
  1.1057 +  DWORD len = GetLongPathNameW(appPath.get(), buf, bufLength);
  1.1058 +
  1.1059 +  // Failing GetLongPathName() is not fatal.
  1.1060 +  if (len <= 0 || len >= bufLength)
  1.1061 +    longPath.Assign(appPath);
  1.1062 +  else
  1.1063 +    longPath.SetLength(len);
  1.1064 +
  1.1065 +  // Use <UserLocalDataDir>\updates\<relative path to app dir from
  1.1066 +  // Program Files> if app dir is under Program Files to avoid the
  1.1067 +  // folder virtualization mess on Windows Vista
  1.1068 +  nsAutoString programFiles;
  1.1069 +  rv = GetShellFolderPath(CSIDL_PROGRAM_FILES, programFiles);
  1.1070 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1071 +
  1.1072 +  programFiles.AppendLiteral("\\");
  1.1073 +  uint32_t programFilesLen = programFiles.Length();
  1.1074 +
  1.1075 +  nsAutoString programName;
  1.1076 +  if (_wcsnicmp(programFiles.get(), longPath.get(), programFilesLen) == 0) {
  1.1077 +    programName = Substring(longPath, programFilesLen);
  1.1078 +  } else {
  1.1079 +    // We need the update root directory to live outside of the installation
  1.1080 +    // directory, because otherwise the updater writing the log file can cause
  1.1081 +    // the directory to be locked, which prevents it from being replaced after
  1.1082 +    // background updates.
  1.1083 +    programName.AssignASCII(MOZ_APP_NAME);
  1.1084 +  }
  1.1085 +
  1.1086 +  rv = GetUserLocalDataDirectory(getter_AddRefs(updRoot));
  1.1087 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1088 +
  1.1089 +  rv = updRoot->AppendRelativePath(programName);
  1.1090 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1091 +
  1.1092 +#endif
  1.1093 +#endif
  1.1094 +  NS_ADDREF(*aResult = updRoot);
  1.1095 +  return NS_OK;
  1.1096 +}
  1.1097 +
  1.1098 +nsresult
  1.1099 +nsXREDirProvider::GetProfileStartupDir(nsIFile* *aResult)
  1.1100 +{
  1.1101 +  if (mProfileDir)
  1.1102 +    return mProfileDir->Clone(aResult);
  1.1103 +
  1.1104 +  if (mAppProvider) {
  1.1105 +    nsCOMPtr<nsIFile> needsclone;
  1.1106 +    bool dummy;
  1.1107 +    nsresult rv = mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP,
  1.1108 +                                        &dummy,
  1.1109 +                                        getter_AddRefs(needsclone));
  1.1110 +    if (NS_SUCCEEDED(rv))
  1.1111 +      return needsclone->Clone(aResult);
  1.1112 +  }
  1.1113 +
  1.1114 +  return NS_ERROR_FAILURE;
  1.1115 +}
  1.1116 +
  1.1117 +nsresult
  1.1118 +nsXREDirProvider::GetProfileDir(nsIFile* *aResult)
  1.1119 +{
  1.1120 +  if (mProfileDir) {
  1.1121 +    if (!mProfileNotified)
  1.1122 +      return NS_ERROR_FAILURE;
  1.1123 +
  1.1124 +    return mProfileDir->Clone(aResult);
  1.1125 +  }
  1.1126 +
  1.1127 +  if (mAppProvider) {
  1.1128 +    nsCOMPtr<nsIFile> needsclone;
  1.1129 +    bool dummy;
  1.1130 +    nsresult rv = mAppProvider->GetFile(NS_APP_USER_PROFILE_50_DIR,
  1.1131 +                                        &dummy,
  1.1132 +                                        getter_AddRefs(needsclone));
  1.1133 +    if (NS_SUCCEEDED(rv))
  1.1134 +      return needsclone->Clone(aResult);
  1.1135 +  }
  1.1136 +
  1.1137 +  return NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aResult);
  1.1138 +}
  1.1139 +
  1.1140 +nsresult
  1.1141 +nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal)
  1.1142 +{
  1.1143 +  // Copied from nsAppFileLocationProvider (more or less)
  1.1144 +  NS_ENSURE_ARG_POINTER(aFile);
  1.1145 +  nsCOMPtr<nsIFile> localDir;
  1.1146 +
  1.1147 +  nsresult rv = GetAppDir()->Clone(getter_AddRefs(localDir));
  1.1148 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1149 +
  1.1150 +  int levelsToRemove = 1; // In FF21+, appDir points to browser subdirectory.
  1.1151 +#if defined(XP_MACOSX)
  1.1152 +  levelsToRemove += 2;
  1.1153 +#endif
  1.1154 +  while (localDir && (levelsToRemove > 0)) {
  1.1155 +    // When crawling up the hierarchy, components named "." do not count.
  1.1156 +    nsAutoCString removedName;
  1.1157 +    rv = localDir->GetNativeLeafName(removedName);
  1.1158 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1159 +    bool didRemove = !removedName.Equals(".");
  1.1160 +
  1.1161 +    // Remove a directory component.
  1.1162 +    nsCOMPtr<nsIFile> parentDir;
  1.1163 +    rv = localDir->GetParent(getter_AddRefs(parentDir));
  1.1164 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1165 +    localDir = parentDir;
  1.1166 +
  1.1167 +    if (didRemove)
  1.1168 +      --levelsToRemove;
  1.1169 +  }
  1.1170 +
  1.1171 +  if (!localDir)
  1.1172 +    return NS_ERROR_FAILURE;
  1.1173 +
  1.1174 +  rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("TorBrowser"
  1.1175 +                                     XPCOM_FILE_PATH_SEPARATOR "Data"
  1.1176 +                                     XPCOM_FILE_PATH_SEPARATOR "Browser"));
  1.1177 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1178 +
  1.1179 +  if (aLocal) {
  1.1180 +    rv = localDir->AppendNative(NS_LITERAL_CSTRING("Caches"));
  1.1181 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1182 +  }
  1.1183 +
  1.1184 +  NS_IF_ADDREF(*aFile = localDir);
  1.1185 +  return rv;
  1.1186 +}
  1.1187 +
  1.1188 +nsresult
  1.1189 +nsXREDirProvider::GetSysUserExtensionsDirectory(nsIFile** aFile)
  1.1190 +{
  1.1191 +  nsCOMPtr<nsIFile> localDir;
  1.1192 +  nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), false);
  1.1193 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1194 +
  1.1195 +  rv = AppendSysUserExtensionPath(localDir);
  1.1196 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1197 +
  1.1198 +  rv = EnsureDirectoryExists(localDir);
  1.1199 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1200 +
  1.1201 +  NS_ADDREF(*aFile = localDir);
  1.1202 +  return NS_OK;
  1.1203 +}
  1.1204 +
  1.1205 +#if defined(XP_UNIX) || defined(XP_MACOSX)
  1.1206 +nsresult
  1.1207 +nsXREDirProvider::GetSystemExtensionsDirectory(nsIFile** aFile)
  1.1208 +{
  1.1209 +  nsresult rv;
  1.1210 +  nsCOMPtr<nsIFile> localDir;
  1.1211 +#if defined(XP_MACOSX)
  1.1212 +  FSRef fsRef;
  1.1213 +  OSErr err = ::FSFindFolder(kOnSystemDisk, kApplicationSupportFolderType, kCreateFolder, &fsRef);
  1.1214 +  NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
  1.1215 +
  1.1216 +  rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localDir));
  1.1217 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1218 +
  1.1219 +  nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir);
  1.1220 +  NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED);
  1.1221 +
  1.1222 +  rv = dirFileMac->InitWithFSRef(&fsRef);
  1.1223 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1224 +
  1.1225 +  localDir = do_QueryInterface(dirFileMac, &rv);
  1.1226 +
  1.1227 +  static const char* const sXR = "Mozilla";
  1.1228 +  rv = localDir->AppendNative(nsDependentCString(sXR));
  1.1229 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1230 +
  1.1231 +  static const char* const sExtensions = "Extensions";
  1.1232 +  rv = localDir->AppendNative(nsDependentCString(sExtensions));
  1.1233 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1234 +#elif defined(XP_UNIX)
  1.1235 +  static const char *const sysSExtDir = 
  1.1236 +#ifdef HAVE_USR_LIB64_DIR
  1.1237 +    "/usr/lib64/mozilla/extensions";
  1.1238 +#elif defined(__OpenBSD__) || defined(__FreeBSD__)
  1.1239 +    "/usr/local/lib/mozilla/extensions";
  1.1240 +#else
  1.1241 +    "/usr/lib/mozilla/extensions";
  1.1242 +#endif
  1.1243 +
  1.1244 +  rv = NS_NewNativeLocalFile(nsDependentCString(sysSExtDir), false,
  1.1245 +                             getter_AddRefs(localDir));
  1.1246 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1247 +#endif
  1.1248 +
  1.1249 +  NS_ADDREF(*aFile = localDir);
  1.1250 +  return NS_OK;
  1.1251 +}
  1.1252 +#endif
  1.1253 +
  1.1254 +nsresult
  1.1255 +nsXREDirProvider::GetUserDataDirectory(nsIFile** aFile, bool aLocal,
  1.1256 +                                       const nsACString* aProfileName,
  1.1257 +                                       const nsACString* aAppName,
  1.1258 +                                       const nsACString* aVendorName)
  1.1259 +{
  1.1260 +  nsCOMPtr<nsIFile> localDir;
  1.1261 +  nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), aLocal);
  1.1262 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1263 +
  1.1264 +  rv = AppendProfilePath(localDir, aProfileName, aAppName, aVendorName, aLocal);
  1.1265 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1266 +
  1.1267 +#ifdef DEBUG_jungshik
  1.1268 +  nsAutoCString cwd;
  1.1269 +  localDir->GetNativePath(cwd);
  1.1270 +  printf("nsXREDirProvider::GetUserDataDirectory: %s\n", cwd.get());
  1.1271 +#endif
  1.1272 +  rv = EnsureDirectoryExists(localDir);
  1.1273 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1274 +
  1.1275 +  NS_ADDREF(*aFile = localDir);
  1.1276 +  return NS_OK;
  1.1277 +}
  1.1278 +
  1.1279 +nsresult
  1.1280 +nsXREDirProvider::EnsureDirectoryExists(nsIFile* aDirectory)
  1.1281 +{
  1.1282 +  bool exists;
  1.1283 +  nsresult rv = aDirectory->Exists(&exists);
  1.1284 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1285 +#ifdef DEBUG_jungshik
  1.1286 +  if (!exists) {
  1.1287 +    nsAutoCString cwd;
  1.1288 +    aDirectory->GetNativePath(cwd);
  1.1289 +    printf("nsXREDirProvider::EnsureDirectoryExists: %s does not\n", cwd.get());
  1.1290 +  }
  1.1291 +#endif
  1.1292 +  if (!exists)
  1.1293 +    rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0700);
  1.1294 +#ifdef DEBUG_jungshik
  1.1295 +  if (NS_FAILED(rv))
  1.1296 +    NS_WARNING("nsXREDirProvider::EnsureDirectoryExists: create failed");
  1.1297 +#endif
  1.1298 +
  1.1299 +  return rv;
  1.1300 +}
  1.1301 +
  1.1302 +void
  1.1303 +nsXREDirProvider::EnsureProfileFileExists(nsIFile *aFile)
  1.1304 +{
  1.1305 +  nsresult rv;
  1.1306 +  bool exists;
  1.1307 +
  1.1308 +  rv = aFile->Exists(&exists);
  1.1309 +  if (NS_FAILED(rv) || exists) return;
  1.1310 +
  1.1311 +  nsAutoCString leafName;
  1.1312 +  rv = aFile->GetNativeLeafName(leafName);
  1.1313 +  if (NS_FAILED(rv)) return;
  1.1314 +
  1.1315 +  nsCOMPtr<nsIFile> defaultsFile;
  1.1316 +  rv = GetProfileDefaultsDir(getter_AddRefs(defaultsFile));
  1.1317 +  if (NS_FAILED(rv)) return;
  1.1318 +
  1.1319 +  rv = defaultsFile->AppendNative(leafName);
  1.1320 +  if (NS_FAILED(rv)) return;
  1.1321 +
  1.1322 +  defaultsFile->CopyToNative(mProfileDir, EmptyCString());
  1.1323 +}
  1.1324 +
  1.1325 +nsresult
  1.1326 +nsXREDirProvider::GetProfileDefaultsDir(nsIFile* *aResult)
  1.1327 +{
  1.1328 +  NS_ASSERTION(mGREDir, "nsXREDirProvider not initialized.");
  1.1329 +  NS_PRECONDITION(aResult, "Null out-param");
  1.1330 +
  1.1331 +  nsresult rv;
  1.1332 +  nsCOMPtr<nsIFile> defaultsDir;
  1.1333 +
  1.1334 +  rv = GetAppDir()->Clone(getter_AddRefs(defaultsDir));
  1.1335 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1336 +
  1.1337 +  rv = defaultsDir->AppendNative(NS_LITERAL_CSTRING("defaults"));
  1.1338 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1339 +
  1.1340 +  rv = defaultsDir->AppendNative(NS_LITERAL_CSTRING("profile"));
  1.1341 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1342 +
  1.1343 +  NS_ADDREF(*aResult = defaultsDir);
  1.1344 +  return NS_OK;
  1.1345 +}
  1.1346 +
  1.1347 +nsresult
  1.1348 +nsXREDirProvider::AppendSysUserExtensionPath(nsIFile* aFile)
  1.1349 +{
  1.1350 +  NS_ASSERTION(aFile, "Null pointer!");
  1.1351 +
  1.1352 +  nsresult rv;
  1.1353 +
  1.1354 +#if defined (XP_MACOSX) || defined(XP_WIN)
  1.1355 +
  1.1356 +  static const char* const sXR = "Mozilla";
  1.1357 +  rv = aFile->AppendNative(nsDependentCString(sXR));
  1.1358 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1359 +
  1.1360 +  static const char* const sExtensions = "Extensions";
  1.1361 +  rv = aFile->AppendNative(nsDependentCString(sExtensions));
  1.1362 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1363 +
  1.1364 +#elif defined(XP_UNIX)
  1.1365 +
  1.1366 +  static const char* const sXR = ".mozilla";
  1.1367 +  rv = aFile->AppendNative(nsDependentCString(sXR));
  1.1368 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1369 +
  1.1370 +  static const char* const sExtensions = "extensions";
  1.1371 +  rv = aFile->AppendNative(nsDependentCString(sExtensions));
  1.1372 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1373 +
  1.1374 +#else
  1.1375 +#error "Don't know how to get XRE user extension path on your platform"
  1.1376 +#endif
  1.1377 +  return NS_OK;
  1.1378 +}
  1.1379 +
  1.1380 +
  1.1381 +nsresult
  1.1382 +nsXREDirProvider::AppendProfilePath(nsIFile* aFile,
  1.1383 +                                    const nsACString* aProfileName,
  1.1384 +                                    const nsACString* aAppName,
  1.1385 +                                    const nsACString* aVendorName,
  1.1386 +                                    bool aLocal)
  1.1387 +{
  1.1388 +  NS_ASSERTION(aFile, "Null pointer!");
  1.1389 +  
  1.1390 +  if (!gAppData) {
  1.1391 +    return NS_ERROR_FAILURE;
  1.1392 +  }
  1.1393 +
  1.1394 +  nsAutoCString profile;
  1.1395 +  if (aProfileName && !aProfileName->IsEmpty()) {
  1.1396 +    profile = *aProfileName;
  1.1397 +  } else if (gAppData->profile) {
  1.1398 +    profile = gAppData->profile;
  1.1399 +  }
  1.1400 +
  1.1401 +  nsresult rv = NS_ERROR_FAILURE;
  1.1402 +
  1.1403 +#if defined (XP_MACOSX)
  1.1404 +  if (!profile.IsEmpty()) {
  1.1405 +    rv = AppendProfileString(aFile, profile.get());
  1.1406 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1407 +  }
  1.1408 +
  1.1409 +#elif defined(XP_WIN)
  1.1410 +  if (!profile.IsEmpty()) {
  1.1411 +    rv = AppendProfileString(aFile, profile.get());
  1.1412 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1413 +  }
  1.1414 +
  1.1415 +#elif defined(ANDROID)
  1.1416 +  // The directory used for storing profiles
  1.1417 +  // The parent of this directory is set in GetUserDataDirectoryHome
  1.1418 +  // XXX: handle gAppData->profile properly
  1.1419 +  // XXXsmaug ...and the rest of the profile creation!
  1.1420 +  MOZ_ASSERT(!aAppName,
  1.1421 +             "Profile creation for external applications is not implemented!");
  1.1422 +  rv = aFile->AppendNative(nsDependentCString("mozilla"));
  1.1423 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1424 +#elif defined(XP_UNIX)
  1.1425 +  if (!profile.IsEmpty()) {
  1.1426 +    // Skip any leading path characters
  1.1427 +    const char* profileStart = profile.get();
  1.1428 +    while (*profileStart == '/' || *profileStart == '\\')
  1.1429 +      profileStart++;
  1.1430 +
  1.1431 +    // On the off chance that someone wanted their folder to be hidden don't
  1.1432 +    // let it become ".."
  1.1433 +    if (*profileStart == '.')
  1.1434 +      profileStart++;
  1.1435 +
  1.1436 +    // Make it hidden (by starting with ".").
  1.1437 +    nsAutoCString folder(".");
  1.1438 +    folder.Append(profileStart);
  1.1439 +    ToLowerCase(folder);
  1.1440 +
  1.1441 +    rv = AppendProfileString(aFile, folder.BeginReading());
  1.1442 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1443 +  }
  1.1444 +
  1.1445 +#else
  1.1446 +#error "Don't know how to get profile path on your platform"
  1.1447 +#endif
  1.1448 +  return NS_OK;
  1.1449 +}
  1.1450 +
  1.1451 +nsresult
  1.1452 +nsXREDirProvider::AppendProfileString(nsIFile* aFile, const char* aPath)
  1.1453 +{
  1.1454 +  NS_ASSERTION(aFile, "Null file!");
  1.1455 +  NS_ASSERTION(aPath, "Null path!");
  1.1456 +
  1.1457 +  nsAutoCString pathDup(aPath);
  1.1458 +
  1.1459 +  char* path = pathDup.BeginWriting();
  1.1460 +
  1.1461 +  nsresult rv;
  1.1462 +  char* subdir;
  1.1463 +  while ((subdir = NS_strtok("/\\", &path))) {
  1.1464 +    rv = aFile->AppendNative(nsDependentCString(subdir));
  1.1465 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1466 +  }
  1.1467 +
  1.1468 +  return NS_OK;
  1.1469 +}

mercurial