profile/dirserviceprovider/src/nsProfileDirServiceProvider.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsProfileDirServiceProvider.h"
michael@0 7 #include "nsProfileStringTypes.h"
michael@0 8 #include "nsProfileLock.h"
michael@0 9 #include "nsIFile.h"
michael@0 10 #include "nsDirectoryServiceDefs.h"
michael@0 11 #include "nsAppDirectoryServiceDefs.h"
michael@0 12 #include "nsISupportsUtils.h"
michael@0 13 #include "nsISimpleEnumerator.h"
michael@0 14 #include "nsIObserverService.h"
michael@0 15
michael@0 16 // File Name Defines
michael@0 17
michael@0 18 #define PREFS_FILE_50_NAME NS_LITERAL_CSTRING("prefs.js")
michael@0 19 #define PREFS_FILE_METRO_50_NAME NS_LITERAL_CSTRING("metro-prefs.js")
michael@0 20 #define USER_CHROME_DIR_50_NAME NS_LITERAL_CSTRING("chrome")
michael@0 21 #define LOCAL_STORE_FILE_50_NAME NS_LITERAL_CSTRING("localstore.rdf")
michael@0 22 #define PANELS_FILE_50_NAME NS_LITERAL_CSTRING("panels.rdf")
michael@0 23 #define MIME_TYPES_FILE_50_NAME NS_LITERAL_CSTRING("mimeTypes.rdf")
michael@0 24 #define BOOKMARKS_FILE_50_NAME NS_LITERAL_CSTRING("bookmarks.html")
michael@0 25 #define DOWNLOADS_FILE_50_NAME NS_LITERAL_CSTRING("downloads.rdf")
michael@0 26 #define SEARCH_FILE_50_NAME NS_LITERAL_CSTRING("search.rdf" )
michael@0 27
michael@0 28 //*****************************************************************************
michael@0 29 // nsProfileDirServiceProvider::nsProfileDirServiceProvider
michael@0 30 //*****************************************************************************
michael@0 31
michael@0 32 nsProfileDirServiceProvider::nsProfileDirServiceProvider(bool aNotifyObservers) :
michael@0 33 #ifdef MOZ_PROFILELOCKING
michael@0 34 mProfileDirLock(nullptr),
michael@0 35 #endif
michael@0 36 mNotifyObservers(aNotifyObservers),
michael@0 37 mSharingEnabled(false)
michael@0 38 {
michael@0 39 }
michael@0 40
michael@0 41
michael@0 42 nsProfileDirServiceProvider::~nsProfileDirServiceProvider()
michael@0 43 {
michael@0 44 #ifdef MOZ_PROFILELOCKING
michael@0 45 delete mProfileDirLock;
michael@0 46 #endif
michael@0 47 }
michael@0 48
michael@0 49 nsresult
michael@0 50 nsProfileDirServiceProvider::SetProfileDir(nsIFile* aProfileDir,
michael@0 51 nsIFile* aLocalProfileDir)
michael@0 52 {
michael@0 53 if (!aLocalProfileDir)
michael@0 54 aLocalProfileDir = aProfileDir;
michael@0 55 if (mProfileDir) {
michael@0 56 bool isEqual;
michael@0 57 if (aProfileDir &&
michael@0 58 NS_SUCCEEDED(aProfileDir->Equals(mProfileDir, &isEqual)) && isEqual) {
michael@0 59 NS_WARNING("Setting profile dir to same as current");
michael@0 60 return NS_OK;
michael@0 61 }
michael@0 62 #ifdef MOZ_PROFILELOCKING
michael@0 63 mProfileDirLock->Unlock();
michael@0 64 #endif
michael@0 65 UndefineFileLocations();
michael@0 66 }
michael@0 67 mProfileDir = aProfileDir;
michael@0 68 mLocalProfileDir = aLocalProfileDir;
michael@0 69 if (!mProfileDir)
michael@0 70 return NS_OK;
michael@0 71
michael@0 72 nsresult rv = InitProfileDir(mProfileDir);
michael@0 73 if (NS_FAILED(rv))
michael@0 74 return rv;
michael@0 75
michael@0 76 // Make sure that the local profile dir exists
michael@0 77 // we just try to create it - if it exists already, that'll fail; ignore
michael@0 78 // errors
michael@0 79 mLocalProfileDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
michael@0 80
michael@0 81 #ifdef MOZ_PROFILELOCKING
michael@0 82 // Lock the non-shared sub-dir if we are sharing,
michael@0 83 // the whole profile dir if we are not.
michael@0 84 nsCOMPtr<nsIFile> dirToLock;
michael@0 85 if (mSharingEnabled)
michael@0 86 dirToLock = mNonSharedProfileDir;
michael@0 87 else
michael@0 88 dirToLock = mProfileDir;
michael@0 89 rv = mProfileDirLock->Lock(dirToLock, nullptr);
michael@0 90 if (NS_FAILED(rv))
michael@0 91 return rv;
michael@0 92 #endif
michael@0 93
michael@0 94 if (mNotifyObservers) {
michael@0 95 nsCOMPtr<nsIObserverService> observerService =
michael@0 96 do_GetService("@mozilla.org/observer-service;1");
michael@0 97 if (!observerService)
michael@0 98 return NS_ERROR_FAILURE;
michael@0 99
michael@0 100 NS_NAMED_LITERAL_STRING(context, "startup");
michael@0 101 // Notify observers that the profile has changed - Here they respond to new profile
michael@0 102 observerService->NotifyObservers(nullptr, "profile-do-change", context.get());
michael@0 103 // Now observers can respond to something another observer did on "profile-do-change"
michael@0 104 observerService->NotifyObservers(nullptr, "profile-after-change", context.get());
michael@0 105 }
michael@0 106
michael@0 107 return NS_OK;
michael@0 108 }
michael@0 109
michael@0 110 nsresult
michael@0 111 nsProfileDirServiceProvider::Register()
michael@0 112 {
michael@0 113 nsCOMPtr<nsIDirectoryService> directoryService =
michael@0 114 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
michael@0 115 if (!directoryService)
michael@0 116 return NS_ERROR_FAILURE;
michael@0 117 return directoryService->RegisterProvider(this);
michael@0 118 }
michael@0 119
michael@0 120 nsresult
michael@0 121 nsProfileDirServiceProvider::Shutdown()
michael@0 122 {
michael@0 123 if (!mNotifyObservers)
michael@0 124 return NS_OK;
michael@0 125
michael@0 126 nsCOMPtr<nsIObserverService> observerService =
michael@0 127 do_GetService("@mozilla.org/observer-service;1");
michael@0 128 if (!observerService)
michael@0 129 return NS_ERROR_FAILURE;
michael@0 130
michael@0 131 NS_NAMED_LITERAL_STRING(context, "shutdown-persist");
michael@0 132 observerService->NotifyObservers(nullptr, "profile-before-change", context.get());
michael@0 133 observerService->NotifyObservers(nullptr, "profile-before-change2", context.get());
michael@0 134 return NS_OK;
michael@0 135 }
michael@0 136
michael@0 137 //*****************************************************************************
michael@0 138 // nsProfileDirServiceProvider::nsISupports
michael@0 139 //*****************************************************************************
michael@0 140
michael@0 141 NS_IMPL_ISUPPORTS(nsProfileDirServiceProvider,
michael@0 142 nsIDirectoryServiceProvider)
michael@0 143
michael@0 144 //*****************************************************************************
michael@0 145 // nsProfileDirServiceProvider::nsIDirectoryServiceProvider
michael@0 146 //*****************************************************************************
michael@0 147
michael@0 148 NS_IMETHODIMP
michael@0 149 nsProfileDirServiceProvider::GetFile(const char *prop, bool *persistant, nsIFile **_retval)
michael@0 150 {
michael@0 151 NS_ENSURE_ARG(prop);
michael@0 152 NS_ENSURE_ARG_POINTER(persistant);
michael@0 153 NS_ENSURE_ARG_POINTER(_retval);
michael@0 154
michael@0 155 // Don't assert - we can be called many times before SetProfileDir() has been called.
michael@0 156 if (!mProfileDir)
michael@0 157 return NS_ERROR_FAILURE;
michael@0 158
michael@0 159 *persistant = true;
michael@0 160 nsIFile* domainDir = mProfileDir;
michael@0 161
michael@0 162 nsCOMPtr<nsIFile> localFile;
michael@0 163 nsresult rv = NS_ERROR_FAILURE;
michael@0 164
michael@0 165 if (strcmp(prop, NS_APP_PREFS_50_DIR) == 0) {
michael@0 166 rv = domainDir->Clone(getter_AddRefs(localFile));
michael@0 167 }
michael@0 168 else if (strcmp(prop, NS_APP_PREFS_50_FILE) == 0) {
michael@0 169 rv = domainDir->Clone(getter_AddRefs(localFile));
michael@0 170 if (NS_SUCCEEDED(rv))
michael@0 171 rv = localFile->AppendNative(PREFS_FILE_50_NAME);
michael@0 172 }
michael@0 173 else if (strcmp(prop, NS_METRO_APP_PREFS_50_FILE) == 0) {
michael@0 174 rv = domainDir->Clone(getter_AddRefs(localFile));
michael@0 175 if (NS_SUCCEEDED(rv))
michael@0 176 rv = localFile->AppendNative(PREFS_FILE_METRO_50_NAME);
michael@0 177 }
michael@0 178 else if (strcmp(prop, NS_APP_USER_PROFILE_50_DIR) == 0) {
michael@0 179 rv = domainDir->Clone(getter_AddRefs(localFile));
michael@0 180 }
michael@0 181 else if (strcmp(prop, NS_APP_USER_PROFILE_LOCAL_50_DIR) == 0) {
michael@0 182 rv = mLocalProfileDir->Clone(getter_AddRefs(localFile));
michael@0 183 }
michael@0 184 else if (strcmp(prop, NS_APP_USER_CHROME_DIR) == 0) {
michael@0 185 rv = domainDir->Clone(getter_AddRefs(localFile));
michael@0 186 if (NS_SUCCEEDED(rv))
michael@0 187 rv = localFile->AppendNative(USER_CHROME_DIR_50_NAME);
michael@0 188 }
michael@0 189 else if (strcmp(prop, NS_APP_LOCALSTORE_50_FILE) == 0) {
michael@0 190 rv = domainDir->Clone(getter_AddRefs(localFile));
michael@0 191 if (NS_SUCCEEDED(rv)) {
michael@0 192 rv = localFile->AppendNative(LOCAL_STORE_FILE_50_NAME);
michael@0 193 if (NS_SUCCEEDED(rv)) {
michael@0 194 // it's OK if we can't copy the file... it will be created
michael@0 195 // by client code.
michael@0 196 (void) EnsureProfileFileExists(localFile, domainDir);
michael@0 197 }
michael@0 198 }
michael@0 199 }
michael@0 200 else if (strcmp(prop, NS_APP_USER_PANELS_50_FILE) == 0) {
michael@0 201 rv = domainDir->Clone(getter_AddRefs(localFile));
michael@0 202 if (NS_SUCCEEDED(rv)) {
michael@0 203 rv = localFile->AppendNative(PANELS_FILE_50_NAME);
michael@0 204 if (NS_SUCCEEDED(rv))
michael@0 205 rv = EnsureProfileFileExists(localFile, domainDir);
michael@0 206 }
michael@0 207 }
michael@0 208 else if (strcmp(prop, NS_APP_USER_MIMETYPES_50_FILE) == 0) {
michael@0 209 rv = domainDir->Clone(getter_AddRefs(localFile));
michael@0 210 if (NS_SUCCEEDED(rv)) {
michael@0 211 rv = localFile->AppendNative(MIME_TYPES_FILE_50_NAME);
michael@0 212 if (NS_SUCCEEDED(rv))
michael@0 213 rv = EnsureProfileFileExists(localFile, domainDir);
michael@0 214 }
michael@0 215 }
michael@0 216 else if (strcmp(prop, NS_APP_BOOKMARKS_50_FILE) == 0) {
michael@0 217 rv = domainDir->Clone(getter_AddRefs(localFile));
michael@0 218 if (NS_SUCCEEDED(rv))
michael@0 219 rv = localFile->AppendNative(BOOKMARKS_FILE_50_NAME);
michael@0 220 }
michael@0 221 else if (strcmp(prop, NS_APP_DOWNLOADS_50_FILE) == 0) {
michael@0 222 rv = domainDir->Clone(getter_AddRefs(localFile));
michael@0 223 if (NS_SUCCEEDED(rv))
michael@0 224 rv = localFile->AppendNative(DOWNLOADS_FILE_50_NAME);
michael@0 225 }
michael@0 226 else if (strcmp(prop, NS_APP_SEARCH_50_FILE) == 0) {
michael@0 227 rv = domainDir->Clone(getter_AddRefs(localFile));
michael@0 228 if (NS_SUCCEEDED(rv)) {
michael@0 229 rv = localFile->AppendNative(SEARCH_FILE_50_NAME);
michael@0 230 if (NS_SUCCEEDED(rv))
michael@0 231 rv = EnsureProfileFileExists(localFile, domainDir);
michael@0 232 }
michael@0 233 }
michael@0 234
michael@0 235 if (NS_FAILED(rv)) {
michael@0 236 return rv;
michael@0 237 }
michael@0 238
michael@0 239 localFile.forget(_retval);
michael@0 240 return NS_OK;
michael@0 241 }
michael@0 242
michael@0 243 //*****************************************************************************
michael@0 244 // Protected methods
michael@0 245 //*****************************************************************************
michael@0 246
michael@0 247 nsresult
michael@0 248 nsProfileDirServiceProvider::Initialize()
michael@0 249 {
michael@0 250 #ifdef MOZ_PROFILELOCKING
michael@0 251 mProfileDirLock = new nsProfileLock;
michael@0 252 if (!mProfileDirLock)
michael@0 253 return NS_ERROR_OUT_OF_MEMORY;
michael@0 254 #endif
michael@0 255
michael@0 256 return NS_OK;
michael@0 257 }
michael@0 258
michael@0 259 nsresult
michael@0 260 nsProfileDirServiceProvider::InitProfileDir(nsIFile *profileDir)
michael@0 261 {
michael@0 262 // Make sure our "Profile" folder exists.
michael@0 263 // If it does not, copy the profile defaults to its location.
michael@0 264
michael@0 265 nsresult rv;
michael@0 266 bool exists;
michael@0 267 rv = profileDir->Exists(&exists);
michael@0 268 if (NS_FAILED(rv))
michael@0 269 return rv;
michael@0 270
michael@0 271 if (!exists) {
michael@0 272 nsCOMPtr<nsIFile> profileDefaultsDir;
michael@0 273 nsCOMPtr<nsIFile> profileDirParent;
michael@0 274 nsAutoCString profileDirName;
michael@0 275
michael@0 276 (void)profileDir->GetParent(getter_AddRefs(profileDirParent));
michael@0 277 if (!profileDirParent)
michael@0 278 return NS_ERROR_FAILURE;
michael@0 279 rv = profileDir->GetNativeLeafName(profileDirName);
michael@0 280 if (NS_FAILED(rv))
michael@0 281 return rv;
michael@0 282
michael@0 283 rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_50_DIR, getter_AddRefs(profileDefaultsDir));
michael@0 284 if (NS_FAILED(rv)) {
michael@0 285 rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR, getter_AddRefs(profileDefaultsDir));
michael@0 286 if (NS_FAILED(rv))
michael@0 287 return rv;
michael@0 288 }
michael@0 289 rv = profileDefaultsDir->CopyToNative(profileDirParent, profileDirName);
michael@0 290 if (NS_FAILED(rv)) {
michael@0 291 // if copying failed, lets just ensure that the profile directory exists.
michael@0 292 profileDirParent->AppendNative(profileDirName);
michael@0 293 rv = profileDirParent->Create(nsIFile::DIRECTORY_TYPE, 0700);
michael@0 294 if (NS_FAILED(rv))
michael@0 295 return rv;
michael@0 296 }
michael@0 297
michael@0 298 rv = profileDir->SetPermissions(0700);
michael@0 299 if (NS_FAILED(rv))
michael@0 300 return rv;
michael@0 301 }
michael@0 302 else {
michael@0 303 bool isDir;
michael@0 304 rv = profileDir->IsDirectory(&isDir);
michael@0 305
michael@0 306 if (NS_FAILED(rv))
michael@0 307 return rv;
michael@0 308 if (!isDir)
michael@0 309 return NS_ERROR_FILE_NOT_DIRECTORY;
michael@0 310 }
michael@0 311
michael@0 312 if (mNonSharedDirName.Length())
michael@0 313 rv = InitNonSharedProfileDir();
michael@0 314
michael@0 315 return rv;
michael@0 316 }
michael@0 317
michael@0 318 nsresult
michael@0 319 nsProfileDirServiceProvider::InitNonSharedProfileDir()
michael@0 320 {
michael@0 321 nsresult rv;
michael@0 322
michael@0 323 NS_ENSURE_STATE(mProfileDir);
michael@0 324 NS_ENSURE_STATE(mNonSharedDirName.Length());
michael@0 325
michael@0 326 nsCOMPtr<nsIFile> localDir;
michael@0 327 rv = mProfileDir->Clone(getter_AddRefs(localDir));
michael@0 328 if (NS_SUCCEEDED(rv)) {
michael@0 329 rv = localDir->Append(mNonSharedDirName);
michael@0 330 if (NS_SUCCEEDED(rv)) {
michael@0 331 bool exists;
michael@0 332 rv = localDir->Exists(&exists);
michael@0 333 if (NS_SUCCEEDED(rv)) {
michael@0 334 if (!exists) {
michael@0 335 rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
michael@0 336 }
michael@0 337 else {
michael@0 338 bool isDir;
michael@0 339 rv = localDir->IsDirectory(&isDir);
michael@0 340 if (NS_SUCCEEDED(rv)) {
michael@0 341 if (!isDir)
michael@0 342 rv = NS_ERROR_FILE_NOT_DIRECTORY;
michael@0 343 }
michael@0 344 }
michael@0 345 if (NS_SUCCEEDED(rv))
michael@0 346 mNonSharedProfileDir = localDir;
michael@0 347 }
michael@0 348 }
michael@0 349 }
michael@0 350 return rv;
michael@0 351 }
michael@0 352
michael@0 353 nsresult
michael@0 354 nsProfileDirServiceProvider::EnsureProfileFileExists(nsIFile *aFile, nsIFile *destDir)
michael@0 355 {
michael@0 356 nsresult rv;
michael@0 357 bool exists;
michael@0 358
michael@0 359 rv = aFile->Exists(&exists);
michael@0 360 if (NS_FAILED(rv))
michael@0 361 return rv;
michael@0 362 if (exists)
michael@0 363 return NS_OK;
michael@0 364
michael@0 365 nsCOMPtr<nsIFile> defaultsFile;
michael@0 366
michael@0 367 // Attempt first to get the localized subdir of the defaults
michael@0 368 rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_50_DIR, getter_AddRefs(defaultsFile));
michael@0 369 if (NS_FAILED(rv)) {
michael@0 370 // If that has not been defined, use the top level of the defaults
michael@0 371 rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR, getter_AddRefs(defaultsFile));
michael@0 372 if (NS_FAILED(rv))
michael@0 373 return rv;
michael@0 374 }
michael@0 375
michael@0 376 nsAutoCString leafName;
michael@0 377 rv = aFile->GetNativeLeafName(leafName);
michael@0 378 if (NS_FAILED(rv))
michael@0 379 return rv;
michael@0 380 rv = defaultsFile->AppendNative(leafName);
michael@0 381 if (NS_FAILED(rv))
michael@0 382 return rv;
michael@0 383
michael@0 384 return defaultsFile->CopyTo(destDir, EmptyString());
michael@0 385 }
michael@0 386
michael@0 387 nsresult
michael@0 388 nsProfileDirServiceProvider::UndefineFileLocations()
michael@0 389 {
michael@0 390 nsresult rv;
michael@0 391
michael@0 392 nsCOMPtr<nsIProperties> directoryService =
michael@0 393 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
michael@0 394 NS_ENSURE_TRUE(directoryService, NS_ERROR_FAILURE);
michael@0 395
michael@0 396 (void) directoryService->Undefine(NS_APP_PREFS_50_DIR);
michael@0 397 (void) directoryService->Undefine(NS_APP_PREFS_50_FILE);
michael@0 398 (void) directoryService->Undefine(NS_APP_USER_PROFILE_50_DIR);
michael@0 399 (void) directoryService->Undefine(NS_APP_USER_CHROME_DIR);
michael@0 400 (void) directoryService->Undefine(NS_APP_LOCALSTORE_50_FILE);
michael@0 401 (void) directoryService->Undefine(NS_APP_USER_PANELS_50_FILE);
michael@0 402 (void) directoryService->Undefine(NS_APP_USER_MIMETYPES_50_FILE);
michael@0 403 (void) directoryService->Undefine(NS_APP_BOOKMARKS_50_FILE);
michael@0 404 (void) directoryService->Undefine(NS_APP_DOWNLOADS_50_FILE);
michael@0 405 (void) directoryService->Undefine(NS_APP_SEARCH_50_FILE);
michael@0 406
michael@0 407 return NS_OK;
michael@0 408 }
michael@0 409
michael@0 410 //*****************************************************************************
michael@0 411 // Global creation function
michael@0 412 //*****************************************************************************
michael@0 413
michael@0 414 nsresult NS_NewProfileDirServiceProvider(bool aNotifyObservers,
michael@0 415 nsProfileDirServiceProvider** aProvider)
michael@0 416 {
michael@0 417 NS_ENSURE_ARG_POINTER(aProvider);
michael@0 418 *aProvider = nullptr;
michael@0 419
michael@0 420 nsProfileDirServiceProvider *prov = new nsProfileDirServiceProvider(aNotifyObservers);
michael@0 421 if (!prov)
michael@0 422 return NS_ERROR_OUT_OF_MEMORY;
michael@0 423 nsresult rv = prov->Initialize();
michael@0 424 if (NS_FAILED(rv)) {
michael@0 425 delete prov;
michael@0 426 return rv;
michael@0 427 }
michael@0 428 NS_ADDREF(*aProvider = prov);
michael@0 429 return NS_OK;
michael@0 430 }

mercurial