1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/profile/nsToolkitProfileService.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1061 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 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 "mozilla/ArrayUtils.h" 1.10 + 1.11 +#include <stdio.h> 1.12 +#include <stdlib.h> 1.13 +#include <prprf.h> 1.14 +#include <prtime.h> 1.15 +#include "nsProfileLock.h" 1.16 + 1.17 +#ifdef XP_WIN 1.18 +#include <windows.h> 1.19 +#include <shlobj.h> 1.20 +#endif 1.21 +#ifdef XP_UNIX 1.22 +#include <unistd.h> 1.23 +#endif 1.24 + 1.25 +#include "nsIToolkitProfileService.h" 1.26 +#include "nsIToolkitProfile.h" 1.27 +#include "nsIFactory.h" 1.28 +#include "nsIFile.h" 1.29 +#include "nsISimpleEnumerator.h" 1.30 + 1.31 +#ifdef XP_MACOSX 1.32 +#include <CoreFoundation/CoreFoundation.h> 1.33 +#include "nsILocalFileMac.h" 1.34 +#endif 1.35 + 1.36 +#include "nsAppDirectoryServiceDefs.h" 1.37 +#include "nsXULAppAPI.h" 1.38 + 1.39 +#include "nsINIParser.h" 1.40 +#include "nsXREDirProvider.h" 1.41 +#include "nsAppRunner.h" 1.42 +#include "nsString.h" 1.43 +#include "nsReadableUtils.h" 1.44 +#include "nsNativeCharsetUtils.h" 1.45 +#include "mozilla/Attributes.h" 1.46 + 1.47 +using namespace mozilla; 1.48 + 1.49 +class nsToolkitProfile MOZ_FINAL : public nsIToolkitProfile 1.50 +{ 1.51 +public: 1.52 + NS_DECL_ISUPPORTS 1.53 + NS_DECL_NSITOOLKITPROFILE 1.54 + 1.55 + friend class nsToolkitProfileService; 1.56 + nsRefPtr<nsToolkitProfile> mNext; 1.57 + nsToolkitProfile *mPrev; 1.58 + 1.59 + ~nsToolkitProfile() { } 1.60 + 1.61 +private: 1.62 + nsToolkitProfile(const nsACString& aName, 1.63 + nsIFile* aRootDir, 1.64 + nsIFile* aLocalDir, 1.65 + nsToolkitProfile* aPrev, 1.66 + bool aForExternalApp); 1.67 + 1.68 + friend class nsToolkitProfileLock; 1.69 + 1.70 + nsCString mName; 1.71 + nsCOMPtr<nsIFile> mRootDir; 1.72 + nsCOMPtr<nsIFile> mLocalDir; 1.73 + nsIProfileLock* mLock; 1.74 + bool mForExternalApp; 1.75 +}; 1.76 + 1.77 +class nsToolkitProfileLock MOZ_FINAL : public nsIProfileLock 1.78 +{ 1.79 +public: 1.80 + NS_DECL_ISUPPORTS 1.81 + NS_DECL_NSIPROFILELOCK 1.82 + 1.83 + nsresult Init(nsToolkitProfile* aProfile, nsIProfileUnlocker* *aUnlocker); 1.84 + nsresult Init(nsIFile* aDirectory, nsIFile* aLocalDirectory, 1.85 + nsIProfileUnlocker* *aUnlocker); 1.86 + 1.87 + nsToolkitProfileLock() { } 1.88 + ~nsToolkitProfileLock(); 1.89 + 1.90 +private: 1.91 + nsRefPtr<nsToolkitProfile> mProfile; 1.92 + nsCOMPtr<nsIFile> mDirectory; 1.93 + nsCOMPtr<nsIFile> mLocalDirectory; 1.94 + 1.95 + nsProfileLock mLock; 1.96 +}; 1.97 + 1.98 +class nsToolkitProfileFactory MOZ_FINAL : public nsIFactory 1.99 +{ 1.100 +public: 1.101 + NS_DECL_ISUPPORTS 1.102 + NS_DECL_NSIFACTORY 1.103 +}; 1.104 + 1.105 +class nsToolkitProfileService MOZ_FINAL : public nsIToolkitProfileService 1.106 +{ 1.107 +public: 1.108 + NS_DECL_ISUPPORTS 1.109 + NS_DECL_NSITOOLKITPROFILESERVICE 1.110 + 1.111 +private: 1.112 + friend class nsToolkitProfile; 1.113 + friend class nsToolkitProfileFactory; 1.114 + friend nsresult NS_NewToolkitProfileService(nsIToolkitProfileService**); 1.115 + 1.116 + nsToolkitProfileService() : 1.117 + mDirty(false), 1.118 + mStartWithLast(true), 1.119 + mStartOffline(false) 1.120 + { 1.121 + gService = this; 1.122 + } 1.123 + ~nsToolkitProfileService() 1.124 + { 1.125 + gService = nullptr; 1.126 + } 1.127 + 1.128 + NS_HIDDEN_(nsresult) Init(); 1.129 + 1.130 + nsresult CreateTimesInternal(nsIFile *profileDir); 1.131 + 1.132 + nsresult CreateProfileInternal(nsIFile* aRootDir, 1.133 + const nsACString& aName, 1.134 + const nsACString* aProfileName, 1.135 + const nsACString* aAppName, 1.136 + const nsACString* aVendorName, 1.137 + /*in*/ nsIFile** aProfileDefaultsDir, 1.138 + bool aForExternalApp, 1.139 + nsIToolkitProfile** aResult); 1.140 + 1.141 + nsRefPtr<nsToolkitProfile> mFirst; 1.142 + nsCOMPtr<nsIToolkitProfile> mChosen; 1.143 + nsCOMPtr<nsIFile> mAppData; 1.144 + nsCOMPtr<nsIFile> mTempData; 1.145 + nsCOMPtr<nsIFile> mListFile; 1.146 + bool mDirty; 1.147 + bool mStartWithLast; 1.148 + bool mStartOffline; 1.149 + 1.150 + static nsToolkitProfileService *gService; 1.151 + 1.152 + class ProfileEnumerator MOZ_FINAL : public nsISimpleEnumerator 1.153 + { 1.154 + public: 1.155 + NS_DECL_ISUPPORTS 1.156 + NS_DECL_NSISIMPLEENUMERATOR 1.157 + 1.158 + ProfileEnumerator(nsToolkitProfile *first) 1.159 + { mCurrent = first; } 1.160 + private: 1.161 + ~ProfileEnumerator() { } 1.162 + nsRefPtr<nsToolkitProfile> mCurrent; 1.163 + }; 1.164 +}; 1.165 + 1.166 +nsToolkitProfile::nsToolkitProfile(const nsACString& aName, 1.167 + nsIFile* aRootDir, 1.168 + nsIFile* aLocalDir, 1.169 + nsToolkitProfile* aPrev, 1.170 + bool aForExternalApp) : 1.171 + mPrev(aPrev), 1.172 + mName(aName), 1.173 + mRootDir(aRootDir), 1.174 + mLocalDir(aLocalDir), 1.175 + mLock(nullptr), 1.176 + mForExternalApp(aForExternalApp) 1.177 +{ 1.178 + NS_ASSERTION(aRootDir, "No file!"); 1.179 + 1.180 + if (!aForExternalApp) { 1.181 + if (aPrev) { 1.182 + aPrev->mNext = this; 1.183 + } else { 1.184 + nsToolkitProfileService::gService->mFirst = this; 1.185 + } 1.186 + } 1.187 +} 1.188 + 1.189 +NS_IMPL_ISUPPORTS(nsToolkitProfile, nsIToolkitProfile) 1.190 + 1.191 +NS_IMETHODIMP 1.192 +nsToolkitProfile::GetRootDir(nsIFile* *aResult) 1.193 +{ 1.194 + NS_ADDREF(*aResult = mRootDir); 1.195 + return NS_OK; 1.196 +} 1.197 + 1.198 +NS_IMETHODIMP 1.199 +nsToolkitProfile::GetLocalDir(nsIFile* *aResult) 1.200 +{ 1.201 + NS_ADDREF(*aResult = mLocalDir); 1.202 + return NS_OK; 1.203 +} 1.204 + 1.205 +NS_IMETHODIMP 1.206 +nsToolkitProfile::GetName(nsACString& aResult) 1.207 +{ 1.208 + aResult = mName; 1.209 + return NS_OK; 1.210 +} 1.211 + 1.212 +NS_IMETHODIMP 1.213 +nsToolkitProfile::SetName(const nsACString& aName) 1.214 +{ 1.215 + NS_ASSERTION(nsToolkitProfileService::gService, 1.216 + "Where did my service go?"); 1.217 + NS_ENSURE_TRUE(!mForExternalApp, NS_ERROR_NOT_IMPLEMENTED); 1.218 + 1.219 + mName = aName; 1.220 + nsToolkitProfileService::gService->mDirty = true; 1.221 + 1.222 + return NS_OK; 1.223 +} 1.224 + 1.225 +NS_IMETHODIMP 1.226 +nsToolkitProfile::Remove(bool removeFiles) 1.227 +{ 1.228 + NS_ASSERTION(nsToolkitProfileService::gService, 1.229 + "Whoa, my service is gone."); 1.230 + 1.231 + NS_ENSURE_TRUE(!mForExternalApp, NS_ERROR_NOT_IMPLEMENTED); 1.232 + 1.233 + if (mLock) 1.234 + return NS_ERROR_FILE_IS_LOCKED; 1.235 + 1.236 + if (!mPrev && !mNext && nsToolkitProfileService::gService->mFirst != this) 1.237 + return NS_ERROR_NOT_INITIALIZED; 1.238 + 1.239 + if (removeFiles) { 1.240 + bool equals; 1.241 + nsresult rv = mRootDir->Equals(mLocalDir, &equals); 1.242 + if (NS_FAILED(rv)) 1.243 + return rv; 1.244 + 1.245 + // The root dir might contain the temp dir, so remove 1.246 + // the temp dir first. 1.247 + if (!equals) 1.248 + mLocalDir->Remove(true); 1.249 + 1.250 + mRootDir->Remove(true); 1.251 + } 1.252 + 1.253 + if (mPrev) 1.254 + mPrev->mNext = mNext; 1.255 + else 1.256 + nsToolkitProfileService::gService->mFirst = mNext; 1.257 + 1.258 + if (mNext) 1.259 + mNext->mPrev = mPrev; 1.260 + 1.261 + mPrev = nullptr; 1.262 + mNext = nullptr; 1.263 + 1.264 + if (nsToolkitProfileService::gService->mChosen == this) 1.265 + nsToolkitProfileService::gService->mChosen = nullptr; 1.266 + 1.267 + nsToolkitProfileService::gService->mDirty = true; 1.268 + 1.269 + return NS_OK; 1.270 +} 1.271 + 1.272 +NS_IMETHODIMP 1.273 +nsToolkitProfile::Lock(nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult) 1.274 +{ 1.275 + if (mLock) { 1.276 + NS_ADDREF(*aResult = mLock); 1.277 + return NS_OK; 1.278 + } 1.279 + 1.280 + nsRefPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock(); 1.281 + if (!lock) return NS_ERROR_OUT_OF_MEMORY; 1.282 + 1.283 + nsresult rv = lock->Init(this, aUnlocker); 1.284 + if (NS_FAILED(rv)) return rv; 1.285 + 1.286 + NS_ADDREF(*aResult = lock); 1.287 + return NS_OK; 1.288 +} 1.289 + 1.290 +NS_IMPL_ISUPPORTS(nsToolkitProfileLock, nsIProfileLock) 1.291 + 1.292 +nsresult 1.293 +nsToolkitProfileLock::Init(nsToolkitProfile* aProfile, nsIProfileUnlocker* *aUnlocker) 1.294 +{ 1.295 + nsresult rv; 1.296 + rv = Init(aProfile->mRootDir, aProfile->mLocalDir, aUnlocker); 1.297 + if (NS_SUCCEEDED(rv)) 1.298 + mProfile = aProfile; 1.299 + 1.300 + return rv; 1.301 +} 1.302 + 1.303 +nsresult 1.304 +nsToolkitProfileLock::Init(nsIFile* aDirectory, nsIFile* aLocalDirectory, 1.305 + nsIProfileUnlocker* *aUnlocker) 1.306 +{ 1.307 + nsresult rv; 1.308 + 1.309 + rv = mLock.Lock(aDirectory, aUnlocker); 1.310 + 1.311 + if (NS_SUCCEEDED(rv)) { 1.312 + mDirectory = aDirectory; 1.313 + mLocalDirectory = aLocalDirectory; 1.314 + } 1.315 + 1.316 + return rv; 1.317 +} 1.318 + 1.319 +NS_IMETHODIMP 1.320 +nsToolkitProfileLock::GetDirectory(nsIFile* *aResult) 1.321 +{ 1.322 + if (!mDirectory) { 1.323 + NS_ERROR("Not initialized, or unlocked!"); 1.324 + return NS_ERROR_NOT_INITIALIZED; 1.325 + } 1.326 + 1.327 + NS_ADDREF(*aResult = mDirectory); 1.328 + return NS_OK; 1.329 +} 1.330 + 1.331 +NS_IMETHODIMP 1.332 +nsToolkitProfileLock::GetLocalDirectory(nsIFile* *aResult) 1.333 +{ 1.334 + if (!mLocalDirectory) { 1.335 + NS_ERROR("Not initialized, or unlocked!"); 1.336 + return NS_ERROR_NOT_INITIALIZED; 1.337 + } 1.338 + 1.339 + NS_ADDREF(*aResult = mLocalDirectory); 1.340 + return NS_OK; 1.341 +} 1.342 + 1.343 +NS_IMETHODIMP 1.344 +nsToolkitProfileLock::Unlock() 1.345 +{ 1.346 + if (!mDirectory) { 1.347 + NS_ERROR("Unlocking a never-locked nsToolkitProfileLock!"); 1.348 + return NS_ERROR_UNEXPECTED; 1.349 + } 1.350 + 1.351 + mLock.Unlock(); 1.352 + 1.353 + if (mProfile) { 1.354 + mProfile->mLock = nullptr; 1.355 + mProfile = nullptr; 1.356 + } 1.357 + mDirectory = nullptr; 1.358 + mLocalDirectory = nullptr; 1.359 + 1.360 + return NS_OK; 1.361 +} 1.362 + 1.363 +NS_IMETHODIMP 1.364 +nsToolkitProfileLock::GetReplacedLockTime(PRTime *aResult) 1.365 +{ 1.366 + mLock.GetReplacedLockTime(aResult); 1.367 + return NS_OK; 1.368 +} 1.369 + 1.370 +nsToolkitProfileLock::~nsToolkitProfileLock() 1.371 +{ 1.372 + if (mDirectory) { 1.373 + Unlock(); 1.374 + } 1.375 +} 1.376 + 1.377 +nsToolkitProfileService* 1.378 +nsToolkitProfileService::gService = nullptr; 1.379 + 1.380 +NS_IMPL_ISUPPORTS(nsToolkitProfileService, 1.381 + nsIToolkitProfileService) 1.382 + 1.383 +nsresult 1.384 +nsToolkitProfileService::Init() 1.385 +{ 1.386 + NS_ASSERTION(gDirServiceProvider, "No dirserviceprovider!"); 1.387 + nsresult rv; 1.388 + 1.389 + rv = gDirServiceProvider->GetUserAppDataDirectory(getter_AddRefs(mAppData)); 1.390 + NS_ENSURE_SUCCESS(rv, rv); 1.391 + 1.392 + rv = gDirServiceProvider->GetUserLocalDataDirectory(getter_AddRefs(mTempData)); 1.393 + NS_ENSURE_SUCCESS(rv, rv); 1.394 + 1.395 + rv = mAppData->Clone(getter_AddRefs(mListFile)); 1.396 + NS_ENSURE_SUCCESS(rv, rv); 1.397 + 1.398 + rv = mListFile->AppendNative(NS_LITERAL_CSTRING("profiles.ini")); 1.399 + NS_ENSURE_SUCCESS(rv, rv); 1.400 + 1.401 + bool exists; 1.402 + rv = mListFile->IsFile(&exists); 1.403 + if (NS_FAILED(rv) || !exists) { 1.404 + return NS_OK; 1.405 + } 1.406 + 1.407 + int64_t size; 1.408 + rv = mListFile->GetFileSize(&size); 1.409 + if (NS_FAILED(rv) || !size) { 1.410 + return NS_OK; 1.411 + } 1.412 + 1.413 + nsINIParser parser; 1.414 + rv = parser.Init(mListFile); 1.415 + // Init does not fail on parsing errors, only on OOM/really unexpected 1.416 + // conditions. 1.417 + if (NS_FAILED(rv)) 1.418 + return rv; 1.419 + 1.420 + nsAutoCString buffer; 1.421 + rv = parser.GetString("General", "StartWithLastProfile", buffer); 1.422 + if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("0")) 1.423 + mStartWithLast = false; 1.424 + 1.425 + nsToolkitProfile* currentProfile = nullptr; 1.426 + 1.427 + unsigned int c = 0; 1.428 + for (c = 0; true; ++c) { 1.429 + nsAutoCString profileID("Profile"); 1.430 + profileID.AppendInt(c); 1.431 + 1.432 + rv = parser.GetString(profileID.get(), "IsRelative", buffer); 1.433 + if (NS_FAILED(rv)) break; 1.434 + 1.435 + bool isRelative = buffer.EqualsLiteral("1"); 1.436 + 1.437 + nsAutoCString filePath; 1.438 + 1.439 + rv = parser.GetString(profileID.get(), "Path", filePath); 1.440 + if (NS_FAILED(rv)) { 1.441 + NS_ERROR("Malformed profiles.ini: Path= not found"); 1.442 + continue; 1.443 + } 1.444 + 1.445 + rv = parser.GetString(profileID.get(), "Name", buffer); 1.446 + if (NS_FAILED(rv)) { 1.447 + NS_ERROR("Malformed profiles.ini: Name= not found"); 1.448 + continue; 1.449 + } 1.450 + 1.451 + nsCOMPtr<nsIFile> rootDir; 1.452 + rv = NS_NewNativeLocalFile(EmptyCString(), true, 1.453 + getter_AddRefs(rootDir)); 1.454 + NS_ENSURE_SUCCESS(rv, rv); 1.455 + 1.456 + if (isRelative) { 1.457 + rv = rootDir->SetRelativeDescriptor(mAppData, filePath); 1.458 + } else { 1.459 + rv = rootDir->SetPersistentDescriptor(filePath); 1.460 + } 1.461 + if (NS_FAILED(rv)) continue; 1.462 + 1.463 + nsCOMPtr<nsIFile> localDir; 1.464 + if (isRelative) { 1.465 + rv = NS_NewNativeLocalFile(EmptyCString(), true, 1.466 + getter_AddRefs(localDir)); 1.467 + NS_ENSURE_SUCCESS(rv, rv); 1.468 + 1.469 + rv = localDir->SetRelativeDescriptor(mTempData, filePath); 1.470 + } else { 1.471 + localDir = rootDir; 1.472 + } 1.473 + 1.474 + currentProfile = new nsToolkitProfile(buffer, 1.475 + rootDir, localDir, 1.476 + currentProfile, false); 1.477 + NS_ENSURE_TRUE(currentProfile, NS_ERROR_OUT_OF_MEMORY); 1.478 + 1.479 + rv = parser.GetString(profileID.get(), "Default", buffer); 1.480 + if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("1")) 1.481 + mChosen = currentProfile; 1.482 + } 1.483 + if (!mChosen && mFirst && !mFirst->mNext) // only one profile 1.484 + mChosen = mFirst; 1.485 + return NS_OK; 1.486 +} 1.487 + 1.488 +NS_IMETHODIMP 1.489 +nsToolkitProfileService::SetStartWithLastProfile(bool aValue) 1.490 +{ 1.491 + if (mStartWithLast != aValue) { 1.492 + mStartWithLast = aValue; 1.493 + mDirty = true; 1.494 + } 1.495 + return NS_OK; 1.496 +} 1.497 + 1.498 +NS_IMETHODIMP 1.499 +nsToolkitProfileService::GetStartWithLastProfile(bool *aResult) 1.500 +{ 1.501 + *aResult = mStartWithLast; 1.502 + return NS_OK; 1.503 +} 1.504 + 1.505 +NS_IMETHODIMP 1.506 +nsToolkitProfileService::GetStartOffline(bool *aResult) 1.507 +{ 1.508 + *aResult = mStartOffline; 1.509 + return NS_OK; 1.510 +} 1.511 + 1.512 +NS_IMETHODIMP 1.513 +nsToolkitProfileService::SetStartOffline(bool aValue) 1.514 +{ 1.515 + mStartOffline = aValue; 1.516 + return NS_OK; 1.517 +} 1.518 + 1.519 +NS_IMETHODIMP 1.520 +nsToolkitProfileService::GetProfiles(nsISimpleEnumerator* *aResult) 1.521 +{ 1.522 + *aResult = new ProfileEnumerator(this->mFirst); 1.523 + if (!*aResult) 1.524 + return NS_ERROR_OUT_OF_MEMORY; 1.525 + 1.526 + NS_ADDREF(*aResult); 1.527 + return NS_OK; 1.528 +} 1.529 + 1.530 +NS_IMPL_ISUPPORTS(nsToolkitProfileService::ProfileEnumerator, 1.531 + nsISimpleEnumerator) 1.532 + 1.533 +NS_IMETHODIMP 1.534 +nsToolkitProfileService::ProfileEnumerator::HasMoreElements(bool* aResult) 1.535 +{ 1.536 + *aResult = mCurrent ? true : false; 1.537 + return NS_OK; 1.538 +} 1.539 + 1.540 +NS_IMETHODIMP 1.541 +nsToolkitProfileService::ProfileEnumerator::GetNext(nsISupports* *aResult) 1.542 +{ 1.543 + if (!mCurrent) return NS_ERROR_FAILURE; 1.544 + 1.545 + NS_ADDREF(*aResult = mCurrent); 1.546 + 1.547 + mCurrent = mCurrent->mNext; 1.548 + return NS_OK; 1.549 +} 1.550 + 1.551 +NS_IMETHODIMP 1.552 +nsToolkitProfileService::GetSelectedProfile(nsIToolkitProfile* *aResult) 1.553 +{ 1.554 + if (!mChosen && mFirst && !mFirst->mNext) // only one profile 1.555 + mChosen = mFirst; 1.556 + 1.557 + if (!mChosen) return NS_ERROR_FAILURE; 1.558 + 1.559 + NS_ADDREF(*aResult = mChosen); 1.560 + return NS_OK; 1.561 +} 1.562 + 1.563 +NS_IMETHODIMP 1.564 +nsToolkitProfileService::SetSelectedProfile(nsIToolkitProfile* aProfile) 1.565 +{ 1.566 + if (mChosen != aProfile) { 1.567 + mChosen = aProfile; 1.568 + mDirty = true; 1.569 + } 1.570 + return NS_OK; 1.571 +} 1.572 + 1.573 +NS_IMETHODIMP 1.574 +nsToolkitProfileService::GetProfileByName(const nsACString& aName, 1.575 + nsIToolkitProfile* *aResult) 1.576 +{ 1.577 + nsToolkitProfile* curP = mFirst; 1.578 + while (curP) { 1.579 + if (curP->mName.Equals(aName)) { 1.580 + NS_ADDREF(*aResult = curP); 1.581 + return NS_OK; 1.582 + } 1.583 + curP = curP->mNext; 1.584 + } 1.585 + 1.586 + return NS_ERROR_FAILURE; 1.587 +} 1.588 + 1.589 +NS_IMETHODIMP 1.590 +nsToolkitProfileService::LockProfilePath(nsIFile* aDirectory, 1.591 + nsIFile* aLocalDirectory, 1.592 + nsIProfileLock* *aResult) 1.593 +{ 1.594 + return NS_LockProfilePath(aDirectory, aLocalDirectory, nullptr, aResult); 1.595 +} 1.596 + 1.597 +nsresult 1.598 +NS_LockProfilePath(nsIFile* aPath, nsIFile* aTempPath, 1.599 + nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult) 1.600 +{ 1.601 + nsRefPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock(); 1.602 + if (!lock) return NS_ERROR_OUT_OF_MEMORY; 1.603 + 1.604 + nsresult rv = lock->Init(aPath, aTempPath, aUnlocker); 1.605 + if (NS_FAILED(rv)) return rv; 1.606 + 1.607 + NS_ADDREF(*aResult = lock); 1.608 + return NS_OK; 1.609 +} 1.610 + 1.611 +static const char kTable[] = 1.612 + { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 1.613 + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1.614 + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' }; 1.615 + 1.616 +static void SaltProfileName(nsACString& aName) 1.617 +{ 1.618 + double fpTime = double(PR_Now()); 1.619 + 1.620 + // use 1e-6, granularity of PR_Now() on the mac is seconds 1.621 + srand((unsigned int)(fpTime * 1e-6 + 0.5)); 1.622 + 1.623 + char salt[9]; 1.624 + 1.625 + int i; 1.626 + for (i = 0; i < 8; ++i) 1.627 + salt[i] = kTable[rand() % ArrayLength(kTable)]; 1.628 + 1.629 + salt[8] = '.'; 1.630 + 1.631 + aName.Insert(salt, 0, 9); 1.632 +} 1.633 + 1.634 +NS_IMETHODIMP 1.635 +nsToolkitProfileService::CreateDefaultProfileForApp(const nsACString& aProfileName, 1.636 + const nsACString& aAppName, 1.637 + const nsACString& aVendorName, 1.638 + nsIFile* aProfileDefaultsDir, 1.639 + nsIToolkitProfile** aResult) 1.640 +{ 1.641 + NS_ENSURE_STATE(!aProfileName.IsEmpty() || !aAppName.IsEmpty()); 1.642 + nsCOMPtr<nsIFile> appData; 1.643 + nsresult rv = 1.644 + gDirServiceProvider->GetUserDataDirectory(getter_AddRefs(appData), 1.645 + false, 1.646 + &aProfileName, 1.647 + &aAppName, 1.648 + &aVendorName); 1.649 + NS_ENSURE_SUCCESS(rv, rv); 1.650 + 1.651 + nsCOMPtr<nsIFile> profilesini; 1.652 + appData->Clone(getter_AddRefs(profilesini)); 1.653 + rv = profilesini->AppendNative(NS_LITERAL_CSTRING("profiles.ini")); 1.654 + NS_ENSURE_SUCCESS(rv, rv); 1.655 + 1.656 + bool exists = false; 1.657 + profilesini->Exists(&exists); 1.658 + NS_ENSURE_FALSE(exists, NS_ERROR_ALREADY_INITIALIZED); 1.659 + 1.660 + nsIFile* profileDefaultsDir = aProfileDefaultsDir; 1.661 + rv = CreateProfileInternal(nullptr, 1.662 + NS_LITERAL_CSTRING("default"), 1.663 + &aProfileName, &aAppName, &aVendorName, 1.664 + &profileDefaultsDir, true, aResult); 1.665 + NS_ENSURE_SUCCESS(rv, rv); 1.666 + NS_ENSURE_STATE(*aResult); 1.667 + 1.668 + nsCOMPtr<nsIFile> rootDir; 1.669 + (*aResult)->GetRootDir(getter_AddRefs(rootDir)); 1.670 + NS_ENSURE_SUCCESS(rv, rv); 1.671 + 1.672 + nsAutoCString profileDir; 1.673 + rv = rootDir->GetRelativeDescriptor(appData, profileDir); 1.674 + NS_ENSURE_SUCCESS(rv, rv); 1.675 + 1.676 + nsCString ini; 1.677 + ini.SetCapacity(512); 1.678 + ini.AppendLiteral("[General]\n"); 1.679 + ini.AppendLiteral("StartWithLastProfile=1\n\n"); 1.680 + 1.681 + ini.AppendLiteral("[Profile0]\n"); 1.682 + ini.AppendLiteral("Name=default\n"); 1.683 + ini.AppendLiteral("IsRelative=1\n"); 1.684 + ini.AppendLiteral("Path="); 1.685 + ini.Append(profileDir); 1.686 + ini.Append('\n'); 1.687 + ini.AppendLiteral("Default=1\n\n"); 1.688 + 1.689 + FILE* writeFile; 1.690 + rv = profilesini->OpenANSIFileDesc("w", &writeFile); 1.691 + NS_ENSURE_SUCCESS(rv, rv); 1.692 + 1.693 + if (fwrite(ini.get(), sizeof(char), ini.Length(), writeFile) != 1.694 + ini.Length()) { 1.695 + rv = NS_ERROR_UNEXPECTED; 1.696 + } 1.697 + fclose(writeFile); 1.698 + return rv; 1.699 +} 1.700 + 1.701 +NS_IMETHODIMP 1.702 +nsToolkitProfileService::CreateProfile(nsIFile* aRootDir, 1.703 + const nsACString& aName, 1.704 + nsIToolkitProfile** aResult) 1.705 +{ 1.706 + return CreateProfileInternal(aRootDir, aName, 1.707 + nullptr, nullptr, nullptr, nullptr, false, aResult); 1.708 +} 1.709 + 1.710 +nsresult 1.711 +nsToolkitProfileService::CreateProfileInternal(nsIFile* aRootDir, 1.712 + const nsACString& aName, 1.713 + const nsACString* aProfileName, 1.714 + const nsACString* aAppName, 1.715 + const nsACString* aVendorName, 1.716 + nsIFile** aProfileDefaultsDir, 1.717 + bool aForExternalApp, 1.718 + nsIToolkitProfile** aResult) 1.719 +{ 1.720 + nsresult rv = NS_ERROR_FAILURE; 1.721 + 1.722 + if (!aForExternalApp) { 1.723 + rv = GetProfileByName(aName, aResult); 1.724 + if (NS_SUCCEEDED(rv)) { 1.725 + return rv; 1.726 + } 1.727 + } 1.728 + 1.729 + nsCOMPtr<nsIFile> rootDir (aRootDir); 1.730 + 1.731 + nsAutoCString dirName; 1.732 + if (!rootDir) { 1.733 + rv = gDirServiceProvider->GetUserProfilesRootDir(getter_AddRefs(rootDir), 1.734 + aProfileName, aAppName, 1.735 + aVendorName); 1.736 + NS_ENSURE_SUCCESS(rv, rv); 1.737 + 1.738 + dirName = aName; 1.739 + SaltProfileName(dirName); 1.740 + 1.741 + if (NS_IsNativeUTF8()) { 1.742 + rootDir->AppendNative(dirName); 1.743 + } else { 1.744 + rootDir->Append(NS_ConvertUTF8toUTF16(dirName)); 1.745 + } 1.746 + } 1.747 + 1.748 + nsCOMPtr<nsIFile> localDir; 1.749 + 1.750 + bool isRelative; 1.751 + rv = mAppData->Contains(rootDir, true, &isRelative); 1.752 + if (NS_SUCCEEDED(rv) && isRelative) { 1.753 + nsAutoCString path; 1.754 + rv = rootDir->GetRelativeDescriptor(mAppData, path); 1.755 + NS_ENSURE_SUCCESS(rv, rv); 1.756 + 1.757 + rv = NS_NewNativeLocalFile(EmptyCString(), true, 1.758 + getter_AddRefs(localDir)); 1.759 + NS_ENSURE_SUCCESS(rv, rv); 1.760 + 1.761 + rv = localDir->SetRelativeDescriptor(mTempData, path); 1.762 + } else { 1.763 + localDir = rootDir; 1.764 + } 1.765 + 1.766 + bool exists; 1.767 + rv = rootDir->Exists(&exists); 1.768 + NS_ENSURE_SUCCESS(rv, rv); 1.769 + 1.770 + if (exists) { 1.771 + rv = rootDir->IsDirectory(&exists); 1.772 + NS_ENSURE_SUCCESS(rv, rv); 1.773 + 1.774 + if (!exists) 1.775 + return NS_ERROR_FILE_NOT_DIRECTORY; 1.776 + } 1.777 + else { 1.778 + nsCOMPtr<nsIFile> profileDefaultsDir; 1.779 + nsCOMPtr<nsIFile> profileDirParent; 1.780 + nsAutoString profileDirName; 1.781 + 1.782 + rv = rootDir->GetParent(getter_AddRefs(profileDirParent)); 1.783 + NS_ENSURE_SUCCESS(rv, rv); 1.784 + 1.785 + rv = rootDir->GetLeafName(profileDirName); 1.786 + NS_ENSURE_SUCCESS(rv, rv); 1.787 + 1.788 + if (aProfileDefaultsDir) { 1.789 + profileDefaultsDir = *aProfileDefaultsDir; 1.790 + } else { 1.791 + bool dummy; 1.792 + rv = gDirServiceProvider->GetFile(NS_APP_PROFILE_DEFAULTS_50_DIR, &dummy, 1.793 + getter_AddRefs(profileDefaultsDir)); 1.794 + } 1.795 + 1.796 + if (NS_SUCCEEDED(rv) && profileDefaultsDir) 1.797 + rv = profileDefaultsDir->CopyTo(profileDirParent, 1.798 + profileDirName); 1.799 + if (NS_FAILED(rv) || !profileDefaultsDir) { 1.800 + // if copying failed, lets just ensure that the profile directory exists. 1.801 + rv = rootDir->Create(nsIFile::DIRECTORY_TYPE, 0700); 1.802 + NS_ENSURE_SUCCESS(rv, rv); 1.803 + } 1.804 + rv = rootDir->SetPermissions(0700); 1.805 +#ifndef ANDROID 1.806 + // If the profile is on the sdcard, this will fail but its non-fatal 1.807 + NS_ENSURE_SUCCESS(rv, rv); 1.808 +#endif 1.809 + } 1.810 + 1.811 + rv = localDir->Exists(&exists); 1.812 + NS_ENSURE_SUCCESS(rv, rv); 1.813 + 1.814 + if (!exists) { 1.815 + rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700); 1.816 + NS_ENSURE_SUCCESS(rv, rv); 1.817 + } 1.818 + 1.819 + // We created a new profile dir. Let's store a creation timestamp. 1.820 + // Note that this code path does not apply if the profile dir was 1.821 + // created prior to launching. 1.822 + rv = CreateTimesInternal(rootDir); 1.823 + NS_ENSURE_SUCCESS(rv, rv); 1.824 + 1.825 + nsToolkitProfile* last = aForExternalApp ? nullptr : mFirst; 1.826 + if (last) { 1.827 + while (last->mNext) 1.828 + last = last->mNext; 1.829 + } 1.830 + 1.831 + nsCOMPtr<nsIToolkitProfile> profile = 1.832 + new nsToolkitProfile(aName, rootDir, localDir, last, aForExternalApp); 1.833 + if (!profile) return NS_ERROR_OUT_OF_MEMORY; 1.834 + 1.835 + NS_ADDREF(*aResult = profile); 1.836 + return NS_OK; 1.837 +} 1.838 + 1.839 +nsresult 1.840 +nsToolkitProfileService::CreateTimesInternal(nsIFile* aProfileDir) 1.841 +{ 1.842 + nsresult rv = NS_ERROR_FAILURE; 1.843 + nsCOMPtr<nsIFile> creationLog; 1.844 + rv = aProfileDir->Clone(getter_AddRefs(creationLog)); 1.845 + NS_ENSURE_SUCCESS(rv, rv); 1.846 + 1.847 + rv = creationLog->AppendNative(NS_LITERAL_CSTRING("times.json")); 1.848 + NS_ENSURE_SUCCESS(rv, rv); 1.849 + 1.850 + bool exists = false; 1.851 + creationLog->Exists(&exists); 1.852 + if (exists) { 1.853 + return NS_OK; 1.854 + } 1.855 + 1.856 + rv = creationLog->Create(nsIFile::NORMAL_FILE_TYPE, 0700); 1.857 + NS_ENSURE_SUCCESS(rv, rv); 1.858 + 1.859 + // We don't care about microsecond resolution. 1.860 + int64_t msec = PR_Now() / PR_USEC_PER_MSEC; 1.861 + 1.862 + // Write it out. 1.863 + PRFileDesc *writeFile; 1.864 + rv = creationLog->OpenNSPRFileDesc(PR_WRONLY, 0700, &writeFile); 1.865 + NS_ENSURE_SUCCESS(rv, rv); 1.866 + 1.867 + PR_fprintf(writeFile, "{\n\"created\": %lld\n}\n", msec); 1.868 + PR_Close(writeFile); 1.869 + return NS_OK; 1.870 +} 1.871 + 1.872 +NS_IMETHODIMP 1.873 +nsToolkitProfileService::GetProfileCount(uint32_t *aResult) 1.874 +{ 1.875 + if (!mFirst) 1.876 + *aResult = 0; 1.877 + else if (! mFirst->mNext) 1.878 + *aResult = 1; 1.879 + else 1.880 + *aResult = 2; 1.881 + 1.882 + return NS_OK; 1.883 +} 1.884 + 1.885 +NS_IMETHODIMP 1.886 +nsToolkitProfileService::Flush() 1.887 +{ 1.888 + // Errors during writing might cause unhappy semi-written files. 1.889 + // To avoid this, write the entire thing to a buffer, then write 1.890 + // that buffer to disk. 1.891 + 1.892 + nsresult rv; 1.893 + uint32_t pCount = 0; 1.894 + nsToolkitProfile *cur; 1.895 + 1.896 + for (cur = mFirst; cur != nullptr; cur = cur->mNext) 1.897 + ++pCount; 1.898 + 1.899 + uint32_t length; 1.900 + nsAutoArrayPtr<char> buffer (new char[100+MAXPATHLEN*pCount]); 1.901 + 1.902 + NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY); 1.903 + 1.904 + char *end = buffer; 1.905 + 1.906 + end += sprintf(end, 1.907 + "[General]\n" 1.908 + "StartWithLastProfile=%s\n\n", 1.909 + mStartWithLast ? "1" : "0"); 1.910 + 1.911 + nsAutoCString path; 1.912 + cur = mFirst; 1.913 + pCount = 0; 1.914 + 1.915 + while (cur) { 1.916 + // if the profile dir is relative to appdir... 1.917 + bool isRelative; 1.918 + rv = mAppData->Contains(cur->mRootDir, true, &isRelative); 1.919 + if (NS_SUCCEEDED(rv) && isRelative) { 1.920 + // we use a relative descriptor 1.921 + rv = cur->mRootDir->GetRelativeDescriptor(mAppData, path); 1.922 + } else { 1.923 + // otherwise, a persistent descriptor 1.924 + rv = cur->mRootDir->GetPersistentDescriptor(path); 1.925 + NS_ENSURE_SUCCESS(rv, rv); 1.926 + } 1.927 + 1.928 + end += sprintf(end, 1.929 + "[Profile%u]\n" 1.930 + "Name=%s\n" 1.931 + "IsRelative=%s\n" 1.932 + "Path=%s\n", 1.933 + pCount, cur->mName.get(), 1.934 + isRelative ? "1" : "0", path.get()); 1.935 + 1.936 + if (mChosen == cur) { 1.937 + end += sprintf(end, "Default=1\n"); 1.938 + } 1.939 + 1.940 + end += sprintf(end, "\n"); 1.941 + 1.942 + cur = cur->mNext; 1.943 + ++pCount; 1.944 + } 1.945 + 1.946 + FILE* writeFile; 1.947 + rv = mListFile->OpenANSIFileDesc("w", &writeFile); 1.948 + NS_ENSURE_SUCCESS(rv, rv); 1.949 + 1.950 + if (buffer) { 1.951 + length = end - buffer; 1.952 + 1.953 + if (fwrite(buffer, sizeof(char), length, writeFile) != length) { 1.954 + fclose(writeFile); 1.955 + return NS_ERROR_UNEXPECTED; 1.956 + } 1.957 + } 1.958 + 1.959 + fclose(writeFile); 1.960 + return NS_OK; 1.961 +} 1.962 + 1.963 +NS_IMPL_ISUPPORTS(nsToolkitProfileFactory, nsIFactory) 1.964 + 1.965 +NS_IMETHODIMP 1.966 +nsToolkitProfileFactory::CreateInstance(nsISupports* aOuter, const nsID& aIID, 1.967 + void** aResult) 1.968 +{ 1.969 + if (aOuter) 1.970 + return NS_ERROR_NO_AGGREGATION; 1.971 + 1.972 + nsCOMPtr<nsIToolkitProfileService> profileService = 1.973 + nsToolkitProfileService::gService; 1.974 + if (!profileService) { 1.975 + nsresult rv = NS_NewToolkitProfileService(getter_AddRefs(profileService)); 1.976 + if (NS_FAILED(rv)) 1.977 + return rv; 1.978 + } 1.979 + return profileService->QueryInterface(aIID, aResult); 1.980 +} 1.981 + 1.982 +NS_IMETHODIMP 1.983 +nsToolkitProfileFactory::LockFactory(bool aVal) 1.984 +{ 1.985 + return NS_OK; 1.986 +} 1.987 + 1.988 +nsresult 1.989 +NS_NewToolkitProfileFactory(nsIFactory* *aResult) 1.990 +{ 1.991 + *aResult = new nsToolkitProfileFactory(); 1.992 + if (!*aResult) 1.993 + return NS_ERROR_OUT_OF_MEMORY; 1.994 + 1.995 + NS_ADDREF(*aResult); 1.996 + return NS_OK; 1.997 +} 1.998 + 1.999 +nsresult 1.1000 +NS_NewToolkitProfileService(nsIToolkitProfileService* *aResult) 1.1001 +{ 1.1002 + nsToolkitProfileService* profileService = new nsToolkitProfileService(); 1.1003 + if (!profileService) 1.1004 + return NS_ERROR_OUT_OF_MEMORY; 1.1005 + nsresult rv = profileService->Init(); 1.1006 + if (NS_FAILED(rv)) { 1.1007 + NS_ERROR("nsToolkitProfileService::Init failed!"); 1.1008 + delete profileService; 1.1009 + return rv; 1.1010 + } 1.1011 + 1.1012 + NS_ADDREF(*aResult = profileService); 1.1013 + return NS_OK; 1.1014 +} 1.1015 + 1.1016 +nsresult 1.1017 +XRE_GetFileFromPath(const char *aPath, nsIFile* *aResult) 1.1018 +{ 1.1019 +#if defined(XP_MACOSX) 1.1020 + int32_t pathLen = strlen(aPath); 1.1021 + if (pathLen > MAXPATHLEN) 1.1022 + return NS_ERROR_INVALID_ARG; 1.1023 + 1.1024 + CFURLRef fullPath = 1.1025 + CFURLCreateFromFileSystemRepresentation(nullptr, (const UInt8 *) aPath, 1.1026 + pathLen, true); 1.1027 + if (!fullPath) 1.1028 + return NS_ERROR_FAILURE; 1.1029 + 1.1030 + nsCOMPtr<nsIFile> lf; 1.1031 + nsresult rv = NS_NewNativeLocalFile(EmptyCString(), true, 1.1032 + getter_AddRefs(lf)); 1.1033 + if (NS_SUCCEEDED(rv)) { 1.1034 + nsCOMPtr<nsILocalFileMac> lfMac = do_QueryInterface(lf, &rv); 1.1035 + if (NS_SUCCEEDED(rv)) { 1.1036 + rv = lfMac->InitWithCFURL(fullPath); 1.1037 + if (NS_SUCCEEDED(rv)) 1.1038 + NS_ADDREF(*aResult = lf); 1.1039 + } 1.1040 + } 1.1041 + CFRelease(fullPath); 1.1042 + return rv; 1.1043 + 1.1044 +#elif defined(XP_UNIX) 1.1045 + char fullPath[MAXPATHLEN]; 1.1046 + 1.1047 + if (!realpath(aPath, fullPath)) 1.1048 + return NS_ERROR_FAILURE; 1.1049 + 1.1050 + return NS_NewNativeLocalFile(nsDependentCString(fullPath), true, 1.1051 + aResult); 1.1052 +#elif defined(XP_WIN) 1.1053 + WCHAR fullPath[MAXPATHLEN]; 1.1054 + 1.1055 + if (!_wfullpath(fullPath, NS_ConvertUTF8toUTF16(aPath).get(), MAXPATHLEN)) 1.1056 + return NS_ERROR_FAILURE; 1.1057 + 1.1058 + return NS_NewLocalFile(nsDependentString(fullPath), true, 1.1059 + aResult); 1.1060 + 1.1061 +#else 1.1062 +#error Platform-specific logic needed here. 1.1063 +#endif 1.1064 +}