toolkit/profile/nsToolkitProfileService.cpp

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/ArrayUtils.h"
     8 #include <stdio.h>
     9 #include <stdlib.h>
    10 #include <prprf.h>
    11 #include <prtime.h>
    12 #include "nsProfileLock.h"
    14 #ifdef XP_WIN
    15 #include <windows.h>
    16 #include <shlobj.h>
    17 #endif
    18 #ifdef XP_UNIX
    19 #include <unistd.h>
    20 #endif
    22 #include "nsIToolkitProfileService.h"
    23 #include "nsIToolkitProfile.h"
    24 #include "nsIFactory.h"
    25 #include "nsIFile.h"
    26 #include "nsISimpleEnumerator.h"
    28 #ifdef XP_MACOSX
    29 #include <CoreFoundation/CoreFoundation.h>
    30 #include "nsILocalFileMac.h"
    31 #endif
    33 #include "nsAppDirectoryServiceDefs.h"
    34 #include "nsXULAppAPI.h"
    36 #include "nsINIParser.h"
    37 #include "nsXREDirProvider.h"
    38 #include "nsAppRunner.h"
    39 #include "nsString.h"
    40 #include "nsReadableUtils.h"
    41 #include "nsNativeCharsetUtils.h"
    42 #include "mozilla/Attributes.h"
    44 using namespace mozilla;
    46 class nsToolkitProfile MOZ_FINAL : public nsIToolkitProfile
    47 {
    48 public:
    49     NS_DECL_ISUPPORTS
    50     NS_DECL_NSITOOLKITPROFILE
    52     friend class nsToolkitProfileService;
    53     nsRefPtr<nsToolkitProfile> mNext;
    54     nsToolkitProfile          *mPrev;
    56     ~nsToolkitProfile() { }
    58 private:
    59     nsToolkitProfile(const nsACString& aName,
    60                      nsIFile* aRootDir,
    61                      nsIFile* aLocalDir,
    62                      nsToolkitProfile* aPrev,
    63                      bool aForExternalApp);
    65     friend class nsToolkitProfileLock;
    67     nsCString                  mName;
    68     nsCOMPtr<nsIFile>          mRootDir;
    69     nsCOMPtr<nsIFile>          mLocalDir;
    70     nsIProfileLock*            mLock;
    71     bool                       mForExternalApp;
    72 };
    74 class nsToolkitProfileLock MOZ_FINAL : public nsIProfileLock
    75 {
    76 public:
    77     NS_DECL_ISUPPORTS
    78     NS_DECL_NSIPROFILELOCK
    80     nsresult Init(nsToolkitProfile* aProfile, nsIProfileUnlocker* *aUnlocker);
    81     nsresult Init(nsIFile* aDirectory, nsIFile* aLocalDirectory,
    82                   nsIProfileUnlocker* *aUnlocker);
    84     nsToolkitProfileLock() { }
    85     ~nsToolkitProfileLock();
    87 private:
    88     nsRefPtr<nsToolkitProfile> mProfile;
    89     nsCOMPtr<nsIFile> mDirectory;
    90     nsCOMPtr<nsIFile> mLocalDirectory;
    92     nsProfileLock mLock;
    93 };
    95 class nsToolkitProfileFactory MOZ_FINAL : public nsIFactory
    96 {
    97 public:
    98     NS_DECL_ISUPPORTS
    99     NS_DECL_NSIFACTORY
   100 };
   102 class nsToolkitProfileService MOZ_FINAL : public nsIToolkitProfileService
   103 {
   104 public:
   105     NS_DECL_ISUPPORTS
   106     NS_DECL_NSITOOLKITPROFILESERVICE
   108 private:
   109     friend class nsToolkitProfile;
   110     friend class nsToolkitProfileFactory;
   111     friend nsresult NS_NewToolkitProfileService(nsIToolkitProfileService**);
   113     nsToolkitProfileService() :
   114         mDirty(false),
   115         mStartWithLast(true),
   116         mStartOffline(false)
   117     {
   118         gService = this;
   119     }
   120     ~nsToolkitProfileService()
   121     {
   122         gService = nullptr;
   123     }
   125     NS_HIDDEN_(nsresult) Init();
   127     nsresult CreateTimesInternal(nsIFile *profileDir);
   129     nsresult CreateProfileInternal(nsIFile* aRootDir,
   130                                    const nsACString& aName,
   131                                    const nsACString* aProfileName,
   132                                    const nsACString* aAppName,
   133                                    const nsACString* aVendorName,
   134                                    /*in*/ nsIFile** aProfileDefaultsDir,
   135                                    bool aForExternalApp,
   136                                    nsIToolkitProfile** aResult);
   138     nsRefPtr<nsToolkitProfile>  mFirst;
   139     nsCOMPtr<nsIToolkitProfile> mChosen;
   140     nsCOMPtr<nsIFile>           mAppData;
   141     nsCOMPtr<nsIFile>           mTempData;
   142     nsCOMPtr<nsIFile>           mListFile;
   143     bool mDirty;
   144     bool mStartWithLast;
   145     bool mStartOffline;
   147     static nsToolkitProfileService *gService;
   149     class ProfileEnumerator MOZ_FINAL : public nsISimpleEnumerator
   150     {
   151     public:
   152         NS_DECL_ISUPPORTS
   153         NS_DECL_NSISIMPLEENUMERATOR
   155         ProfileEnumerator(nsToolkitProfile *first)
   156           { mCurrent = first; }
   157     private:
   158         ~ProfileEnumerator() { }
   159         nsRefPtr<nsToolkitProfile> mCurrent;
   160     };
   161 };
   163 nsToolkitProfile::nsToolkitProfile(const nsACString& aName,
   164                                    nsIFile* aRootDir,
   165                                    nsIFile* aLocalDir,
   166                                    nsToolkitProfile* aPrev,
   167                                    bool aForExternalApp) :
   168     mPrev(aPrev),
   169     mName(aName),
   170     mRootDir(aRootDir),
   171     mLocalDir(aLocalDir),
   172     mLock(nullptr),
   173     mForExternalApp(aForExternalApp)
   174 {
   175     NS_ASSERTION(aRootDir, "No file!");
   177     if (!aForExternalApp) {
   178         if (aPrev) {
   179             aPrev->mNext = this;
   180         } else {
   181             nsToolkitProfileService::gService->mFirst = this;
   182         }
   183     }
   184 }
   186 NS_IMPL_ISUPPORTS(nsToolkitProfile, nsIToolkitProfile)
   188 NS_IMETHODIMP
   189 nsToolkitProfile::GetRootDir(nsIFile* *aResult)
   190 {
   191     NS_ADDREF(*aResult = mRootDir);
   192     return NS_OK;
   193 }
   195 NS_IMETHODIMP
   196 nsToolkitProfile::GetLocalDir(nsIFile* *aResult)
   197 {
   198     NS_ADDREF(*aResult = mLocalDir);
   199     return NS_OK;
   200 }
   202 NS_IMETHODIMP
   203 nsToolkitProfile::GetName(nsACString& aResult)
   204 {
   205     aResult = mName;
   206     return NS_OK;
   207 }
   209 NS_IMETHODIMP
   210 nsToolkitProfile::SetName(const nsACString& aName)
   211 {
   212     NS_ASSERTION(nsToolkitProfileService::gService,
   213                  "Where did my service go?");
   214     NS_ENSURE_TRUE(!mForExternalApp, NS_ERROR_NOT_IMPLEMENTED);
   216     mName = aName;
   217     nsToolkitProfileService::gService->mDirty = true;
   219     return NS_OK;
   220 }
   222 NS_IMETHODIMP
   223 nsToolkitProfile::Remove(bool removeFiles)
   224 {
   225     NS_ASSERTION(nsToolkitProfileService::gService,
   226                  "Whoa, my service is gone.");
   228     NS_ENSURE_TRUE(!mForExternalApp, NS_ERROR_NOT_IMPLEMENTED);
   230     if (mLock)
   231         return NS_ERROR_FILE_IS_LOCKED;
   233     if (!mPrev && !mNext && nsToolkitProfileService::gService->mFirst != this)
   234         return NS_ERROR_NOT_INITIALIZED;
   236     if (removeFiles) {
   237         bool equals;
   238         nsresult rv = mRootDir->Equals(mLocalDir, &equals);
   239         if (NS_FAILED(rv))
   240             return rv;
   242         // The root dir might contain the temp dir, so remove
   243         // the temp dir first.
   244         if (!equals)
   245             mLocalDir->Remove(true);
   247         mRootDir->Remove(true);
   248     }
   250     if (mPrev)
   251         mPrev->mNext = mNext;
   252     else
   253         nsToolkitProfileService::gService->mFirst = mNext;
   255     if (mNext)
   256         mNext->mPrev = mPrev;
   258     mPrev = nullptr;
   259     mNext = nullptr;
   261     if (nsToolkitProfileService::gService->mChosen == this)
   262         nsToolkitProfileService::gService->mChosen = nullptr;
   264     nsToolkitProfileService::gService->mDirty = true;
   266     return NS_OK;
   267 }
   269 NS_IMETHODIMP
   270 nsToolkitProfile::Lock(nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult)
   271 {
   272     if (mLock) {
   273         NS_ADDREF(*aResult = mLock);
   274         return NS_OK;
   275     }
   277     nsRefPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock();
   278     if (!lock) return NS_ERROR_OUT_OF_MEMORY;
   280     nsresult rv = lock->Init(this, aUnlocker);
   281     if (NS_FAILED(rv)) return rv;
   283     NS_ADDREF(*aResult = lock);
   284     return NS_OK;
   285 }
   287 NS_IMPL_ISUPPORTS(nsToolkitProfileLock, nsIProfileLock)
   289 nsresult
   290 nsToolkitProfileLock::Init(nsToolkitProfile* aProfile, nsIProfileUnlocker* *aUnlocker)
   291 {
   292     nsresult rv;
   293     rv = Init(aProfile->mRootDir, aProfile->mLocalDir, aUnlocker);
   294     if (NS_SUCCEEDED(rv))
   295         mProfile = aProfile;
   297     return rv;
   298 }
   300 nsresult
   301 nsToolkitProfileLock::Init(nsIFile* aDirectory, nsIFile* aLocalDirectory,
   302                            nsIProfileUnlocker* *aUnlocker)
   303 {
   304     nsresult rv;
   306     rv = mLock.Lock(aDirectory, aUnlocker);
   308     if (NS_SUCCEEDED(rv)) {
   309         mDirectory = aDirectory;
   310         mLocalDirectory = aLocalDirectory;
   311     }
   313     return rv;
   314 }
   316 NS_IMETHODIMP
   317 nsToolkitProfileLock::GetDirectory(nsIFile* *aResult)
   318 {
   319     if (!mDirectory) {
   320         NS_ERROR("Not initialized, or unlocked!");
   321         return NS_ERROR_NOT_INITIALIZED;
   322     }
   324     NS_ADDREF(*aResult = mDirectory);
   325     return NS_OK;
   326 }
   328 NS_IMETHODIMP
   329 nsToolkitProfileLock::GetLocalDirectory(nsIFile* *aResult)
   330 {
   331     if (!mLocalDirectory) {
   332         NS_ERROR("Not initialized, or unlocked!");
   333         return NS_ERROR_NOT_INITIALIZED;
   334     }
   336     NS_ADDREF(*aResult = mLocalDirectory);
   337     return NS_OK;
   338 }
   340 NS_IMETHODIMP
   341 nsToolkitProfileLock::Unlock()
   342 {
   343     if (!mDirectory) {
   344         NS_ERROR("Unlocking a never-locked nsToolkitProfileLock!");
   345         return NS_ERROR_UNEXPECTED;
   346     }
   348     mLock.Unlock();
   350     if (mProfile) {
   351         mProfile->mLock = nullptr;
   352         mProfile = nullptr;
   353     }
   354     mDirectory = nullptr;
   355     mLocalDirectory = nullptr;
   357     return NS_OK;
   358 }
   360 NS_IMETHODIMP
   361 nsToolkitProfileLock::GetReplacedLockTime(PRTime *aResult)
   362 {
   363     mLock.GetReplacedLockTime(aResult);
   364     return NS_OK;
   365 }
   367 nsToolkitProfileLock::~nsToolkitProfileLock()
   368 {
   369     if (mDirectory) {
   370         Unlock();
   371     }
   372 }
   374 nsToolkitProfileService*
   375 nsToolkitProfileService::gService = nullptr;
   377 NS_IMPL_ISUPPORTS(nsToolkitProfileService,
   378                   nsIToolkitProfileService)
   380 nsresult
   381 nsToolkitProfileService::Init()
   382 {
   383     NS_ASSERTION(gDirServiceProvider, "No dirserviceprovider!");
   384     nsresult rv;
   386     rv = gDirServiceProvider->GetUserAppDataDirectory(getter_AddRefs(mAppData));
   387     NS_ENSURE_SUCCESS(rv, rv);
   389     rv = gDirServiceProvider->GetUserLocalDataDirectory(getter_AddRefs(mTempData));
   390     NS_ENSURE_SUCCESS(rv, rv);
   392     rv = mAppData->Clone(getter_AddRefs(mListFile));
   393     NS_ENSURE_SUCCESS(rv, rv);
   395     rv = mListFile->AppendNative(NS_LITERAL_CSTRING("profiles.ini"));
   396     NS_ENSURE_SUCCESS(rv, rv);
   398     bool exists;
   399     rv = mListFile->IsFile(&exists);
   400     if (NS_FAILED(rv) || !exists) {
   401         return NS_OK;
   402     }
   404     int64_t size;
   405     rv = mListFile->GetFileSize(&size);
   406     if (NS_FAILED(rv) || !size) {
   407         return NS_OK;
   408     }
   410     nsINIParser parser;
   411     rv = parser.Init(mListFile);
   412     // Init does not fail on parsing errors, only on OOM/really unexpected
   413     // conditions.
   414     if (NS_FAILED(rv))
   415         return rv;
   417     nsAutoCString buffer;
   418     rv = parser.GetString("General", "StartWithLastProfile", buffer);
   419     if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("0"))
   420         mStartWithLast = false;
   422     nsToolkitProfile* currentProfile = nullptr;
   424     unsigned int c = 0;
   425     for (c = 0; true; ++c) {
   426         nsAutoCString profileID("Profile");
   427         profileID.AppendInt(c);
   429         rv = parser.GetString(profileID.get(), "IsRelative", buffer);
   430         if (NS_FAILED(rv)) break;
   432         bool isRelative = buffer.EqualsLiteral("1");
   434         nsAutoCString filePath;
   436         rv = parser.GetString(profileID.get(), "Path", filePath);
   437         if (NS_FAILED(rv)) {
   438             NS_ERROR("Malformed profiles.ini: Path= not found");
   439             continue;
   440         }
   442         rv = parser.GetString(profileID.get(), "Name", buffer);
   443         if (NS_FAILED(rv)) {
   444             NS_ERROR("Malformed profiles.ini: Name= not found");
   445             continue;
   446         }
   448         nsCOMPtr<nsIFile> rootDir;
   449         rv = NS_NewNativeLocalFile(EmptyCString(), true,
   450                                    getter_AddRefs(rootDir));
   451         NS_ENSURE_SUCCESS(rv, rv);
   453         if (isRelative) {
   454             rv = rootDir->SetRelativeDescriptor(mAppData, filePath);
   455         } else {
   456             rv = rootDir->SetPersistentDescriptor(filePath);
   457         }
   458         if (NS_FAILED(rv)) continue;
   460         nsCOMPtr<nsIFile> localDir;
   461         if (isRelative) {
   462             rv = NS_NewNativeLocalFile(EmptyCString(), true,
   463                                        getter_AddRefs(localDir));
   464             NS_ENSURE_SUCCESS(rv, rv);
   466             rv = localDir->SetRelativeDescriptor(mTempData, filePath);
   467         } else {
   468             localDir = rootDir;
   469         }
   471         currentProfile = new nsToolkitProfile(buffer,
   472                                               rootDir, localDir,
   473                                               currentProfile, false);
   474         NS_ENSURE_TRUE(currentProfile, NS_ERROR_OUT_OF_MEMORY);
   476         rv = parser.GetString(profileID.get(), "Default", buffer);
   477         if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("1"))
   478             mChosen = currentProfile;
   479     }
   480     if (!mChosen && mFirst && !mFirst->mNext) // only one profile
   481         mChosen = mFirst;
   482     return NS_OK;
   483 }
   485 NS_IMETHODIMP
   486 nsToolkitProfileService::SetStartWithLastProfile(bool aValue)
   487 {
   488     if (mStartWithLast != aValue) {
   489         mStartWithLast = aValue;
   490         mDirty = true;
   491     }
   492     return NS_OK;
   493 }
   495 NS_IMETHODIMP
   496 nsToolkitProfileService::GetStartWithLastProfile(bool *aResult)
   497 {
   498     *aResult = mStartWithLast;
   499     return NS_OK;
   500 }
   502 NS_IMETHODIMP
   503 nsToolkitProfileService::GetStartOffline(bool *aResult)
   504 {
   505     *aResult = mStartOffline;
   506     return NS_OK;
   507 }
   509 NS_IMETHODIMP
   510 nsToolkitProfileService::SetStartOffline(bool aValue)
   511 {
   512     mStartOffline = aValue;
   513     return NS_OK;
   514 }
   516 NS_IMETHODIMP
   517 nsToolkitProfileService::GetProfiles(nsISimpleEnumerator* *aResult)
   518 {
   519     *aResult = new ProfileEnumerator(this->mFirst);
   520     if (!*aResult)
   521         return NS_ERROR_OUT_OF_MEMORY;
   523     NS_ADDREF(*aResult);
   524     return NS_OK;
   525 }
   527 NS_IMPL_ISUPPORTS(nsToolkitProfileService::ProfileEnumerator,
   528                   nsISimpleEnumerator)
   530 NS_IMETHODIMP
   531 nsToolkitProfileService::ProfileEnumerator::HasMoreElements(bool* aResult)
   532 {
   533     *aResult = mCurrent ? true : false;
   534     return NS_OK;
   535 }
   537 NS_IMETHODIMP
   538 nsToolkitProfileService::ProfileEnumerator::GetNext(nsISupports* *aResult)
   539 {
   540     if (!mCurrent) return NS_ERROR_FAILURE;
   542     NS_ADDREF(*aResult = mCurrent);
   544     mCurrent = mCurrent->mNext;
   545     return NS_OK;
   546 }
   548 NS_IMETHODIMP
   549 nsToolkitProfileService::GetSelectedProfile(nsIToolkitProfile* *aResult)
   550 {
   551     if (!mChosen && mFirst && !mFirst->mNext) // only one profile
   552         mChosen = mFirst;
   554     if (!mChosen) return NS_ERROR_FAILURE;
   556     NS_ADDREF(*aResult = mChosen);
   557     return NS_OK;
   558 }
   560 NS_IMETHODIMP
   561 nsToolkitProfileService::SetSelectedProfile(nsIToolkitProfile* aProfile)
   562 {
   563     if (mChosen != aProfile) {
   564         mChosen = aProfile;
   565         mDirty = true;
   566     }
   567     return NS_OK;
   568 }
   570 NS_IMETHODIMP
   571 nsToolkitProfileService::GetProfileByName(const nsACString& aName,
   572                                           nsIToolkitProfile* *aResult)
   573 {
   574     nsToolkitProfile* curP = mFirst;
   575     while (curP) {
   576         if (curP->mName.Equals(aName)) {
   577             NS_ADDREF(*aResult = curP);
   578             return NS_OK;
   579         }
   580         curP = curP->mNext;
   581     }
   583     return NS_ERROR_FAILURE;
   584 }
   586 NS_IMETHODIMP
   587 nsToolkitProfileService::LockProfilePath(nsIFile* aDirectory,
   588                                          nsIFile* aLocalDirectory,
   589                                          nsIProfileLock* *aResult)
   590 {
   591     return NS_LockProfilePath(aDirectory, aLocalDirectory, nullptr, aResult);
   592 }
   594 nsresult
   595 NS_LockProfilePath(nsIFile* aPath, nsIFile* aTempPath,
   596                    nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult)
   597 {
   598     nsRefPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock();
   599     if (!lock) return NS_ERROR_OUT_OF_MEMORY;
   601     nsresult rv = lock->Init(aPath, aTempPath, aUnlocker);
   602     if (NS_FAILED(rv)) return rv;
   604     NS_ADDREF(*aResult = lock);
   605     return NS_OK;
   606 }
   608 static const char kTable[] =
   609     { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
   610       'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
   611       '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
   613 static void SaltProfileName(nsACString& aName)
   614 {
   615     double fpTime = double(PR_Now());
   617     // use 1e-6, granularity of PR_Now() on the mac is seconds
   618     srand((unsigned int)(fpTime * 1e-6 + 0.5));
   620     char salt[9];
   622     int i;
   623     for (i = 0; i < 8; ++i)
   624         salt[i] = kTable[rand() % ArrayLength(kTable)];
   626     salt[8] = '.';
   628     aName.Insert(salt, 0, 9);
   629 }
   631 NS_IMETHODIMP
   632 nsToolkitProfileService::CreateDefaultProfileForApp(const nsACString& aProfileName,
   633                                                     const nsACString& aAppName,
   634                                                     const nsACString& aVendorName,
   635                                                     nsIFile* aProfileDefaultsDir,
   636                                                     nsIToolkitProfile** aResult)
   637 {
   638     NS_ENSURE_STATE(!aProfileName.IsEmpty() || !aAppName.IsEmpty());
   639     nsCOMPtr<nsIFile> appData;
   640     nsresult rv =
   641         gDirServiceProvider->GetUserDataDirectory(getter_AddRefs(appData),
   642                                                   false,
   643                                                   &aProfileName,
   644                                                   &aAppName,
   645                                                   &aVendorName);
   646     NS_ENSURE_SUCCESS(rv, rv);
   648     nsCOMPtr<nsIFile> profilesini;
   649     appData->Clone(getter_AddRefs(profilesini));
   650     rv = profilesini->AppendNative(NS_LITERAL_CSTRING("profiles.ini"));
   651     NS_ENSURE_SUCCESS(rv, rv);
   653     bool exists = false;
   654     profilesini->Exists(&exists);
   655     NS_ENSURE_FALSE(exists, NS_ERROR_ALREADY_INITIALIZED);
   657     nsIFile* profileDefaultsDir = aProfileDefaultsDir;
   658     rv = CreateProfileInternal(nullptr,
   659                                NS_LITERAL_CSTRING("default"),
   660                                &aProfileName, &aAppName, &aVendorName,
   661                                &profileDefaultsDir, true, aResult);
   662     NS_ENSURE_SUCCESS(rv, rv);
   663     NS_ENSURE_STATE(*aResult);
   665     nsCOMPtr<nsIFile> rootDir;
   666     (*aResult)->GetRootDir(getter_AddRefs(rootDir));
   667     NS_ENSURE_SUCCESS(rv, rv);
   669     nsAutoCString profileDir;
   670     rv = rootDir->GetRelativeDescriptor(appData, profileDir);
   671     NS_ENSURE_SUCCESS(rv, rv);
   673     nsCString ini;
   674     ini.SetCapacity(512);
   675     ini.AppendLiteral("[General]\n");
   676     ini.AppendLiteral("StartWithLastProfile=1\n\n");
   678     ini.AppendLiteral("[Profile0]\n");
   679     ini.AppendLiteral("Name=default\n");
   680     ini.AppendLiteral("IsRelative=1\n");
   681     ini.AppendLiteral("Path=");
   682     ini.Append(profileDir);
   683     ini.Append('\n');
   684     ini.AppendLiteral("Default=1\n\n");
   686     FILE* writeFile;
   687     rv = profilesini->OpenANSIFileDesc("w", &writeFile);
   688     NS_ENSURE_SUCCESS(rv, rv);
   690     if (fwrite(ini.get(), sizeof(char), ini.Length(), writeFile) !=
   691         ini.Length()) {
   692         rv = NS_ERROR_UNEXPECTED;
   693     }
   694     fclose(writeFile);
   695     return rv;
   696 }
   698 NS_IMETHODIMP
   699 nsToolkitProfileService::CreateProfile(nsIFile* aRootDir,
   700                                        const nsACString& aName,
   701                                        nsIToolkitProfile** aResult)
   702 {
   703     return CreateProfileInternal(aRootDir, aName,
   704                                  nullptr, nullptr, nullptr, nullptr, false, aResult);
   705 }
   707 nsresult
   708 nsToolkitProfileService::CreateProfileInternal(nsIFile* aRootDir,
   709                                                const nsACString& aName,
   710                                                const nsACString* aProfileName,
   711                                                const nsACString* aAppName,
   712                                                const nsACString* aVendorName,
   713                                                nsIFile** aProfileDefaultsDir,
   714                                                bool aForExternalApp,
   715                                                nsIToolkitProfile** aResult)
   716 {
   717     nsresult rv = NS_ERROR_FAILURE;
   719     if (!aForExternalApp) {
   720         rv = GetProfileByName(aName, aResult);
   721         if (NS_SUCCEEDED(rv)) {
   722             return rv;
   723         }
   724     }
   726     nsCOMPtr<nsIFile> rootDir (aRootDir);
   728     nsAutoCString dirName;
   729     if (!rootDir) {
   730         rv = gDirServiceProvider->GetUserProfilesRootDir(getter_AddRefs(rootDir),
   731                                                          aProfileName, aAppName,
   732                                                          aVendorName);
   733         NS_ENSURE_SUCCESS(rv, rv);
   735         dirName = aName;
   736         SaltProfileName(dirName);
   738         if (NS_IsNativeUTF8()) {
   739             rootDir->AppendNative(dirName);
   740         } else {
   741             rootDir->Append(NS_ConvertUTF8toUTF16(dirName));
   742         }
   743     }
   745     nsCOMPtr<nsIFile> localDir;
   747     bool isRelative;
   748     rv = mAppData->Contains(rootDir, true, &isRelative);
   749     if (NS_SUCCEEDED(rv) && isRelative) {
   750         nsAutoCString path;
   751         rv = rootDir->GetRelativeDescriptor(mAppData, path);
   752         NS_ENSURE_SUCCESS(rv, rv);
   754         rv = NS_NewNativeLocalFile(EmptyCString(), true,
   755                                    getter_AddRefs(localDir));
   756         NS_ENSURE_SUCCESS(rv, rv);
   758         rv = localDir->SetRelativeDescriptor(mTempData, path);
   759     } else {
   760         localDir = rootDir;
   761     }
   763     bool exists;
   764     rv = rootDir->Exists(&exists);
   765     NS_ENSURE_SUCCESS(rv, rv);
   767     if (exists) {
   768         rv = rootDir->IsDirectory(&exists);
   769         NS_ENSURE_SUCCESS(rv, rv);
   771         if (!exists)
   772             return NS_ERROR_FILE_NOT_DIRECTORY;
   773     }
   774     else {
   775         nsCOMPtr<nsIFile> profileDefaultsDir;
   776         nsCOMPtr<nsIFile> profileDirParent;
   777         nsAutoString profileDirName;
   779         rv = rootDir->GetParent(getter_AddRefs(profileDirParent));
   780         NS_ENSURE_SUCCESS(rv, rv);
   782         rv = rootDir->GetLeafName(profileDirName);
   783         NS_ENSURE_SUCCESS(rv, rv);
   785         if (aProfileDefaultsDir) {
   786             profileDefaultsDir = *aProfileDefaultsDir;
   787         } else {
   788             bool dummy;
   789             rv = gDirServiceProvider->GetFile(NS_APP_PROFILE_DEFAULTS_50_DIR, &dummy,
   790                                               getter_AddRefs(profileDefaultsDir));
   791         }
   793         if (NS_SUCCEEDED(rv) && profileDefaultsDir)
   794             rv = profileDefaultsDir->CopyTo(profileDirParent,
   795                                             profileDirName);
   796         if (NS_FAILED(rv) || !profileDefaultsDir) {
   797             // if copying failed, lets just ensure that the profile directory exists.
   798             rv = rootDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
   799             NS_ENSURE_SUCCESS(rv, rv);
   800         }
   801         rv = rootDir->SetPermissions(0700);
   802 #ifndef ANDROID
   803         // If the profile is on the sdcard, this will fail but its non-fatal
   804         NS_ENSURE_SUCCESS(rv, rv);
   805 #endif
   806     }
   808     rv = localDir->Exists(&exists);
   809     NS_ENSURE_SUCCESS(rv, rv);
   811     if (!exists) {
   812         rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
   813         NS_ENSURE_SUCCESS(rv, rv);
   814     }
   816     // We created a new profile dir. Let's store a creation timestamp.
   817     // Note that this code path does not apply if the profile dir was
   818     // created prior to launching.
   819     rv = CreateTimesInternal(rootDir);
   820     NS_ENSURE_SUCCESS(rv, rv);
   822     nsToolkitProfile* last = aForExternalApp ? nullptr : mFirst;
   823     if (last) {
   824         while (last->mNext)
   825             last = last->mNext;
   826     }
   828     nsCOMPtr<nsIToolkitProfile> profile =
   829         new nsToolkitProfile(aName, rootDir, localDir, last, aForExternalApp);
   830     if (!profile) return NS_ERROR_OUT_OF_MEMORY;
   832     NS_ADDREF(*aResult = profile);
   833     return NS_OK;
   834 }
   836 nsresult
   837 nsToolkitProfileService::CreateTimesInternal(nsIFile* aProfileDir)
   838 {
   839     nsresult rv = NS_ERROR_FAILURE;
   840     nsCOMPtr<nsIFile> creationLog;
   841     rv = aProfileDir->Clone(getter_AddRefs(creationLog));
   842     NS_ENSURE_SUCCESS(rv, rv);
   844     rv = creationLog->AppendNative(NS_LITERAL_CSTRING("times.json"));
   845     NS_ENSURE_SUCCESS(rv, rv);
   847     bool exists = false;
   848     creationLog->Exists(&exists);
   849     if (exists) {
   850       return NS_OK;
   851     }
   853     rv = creationLog->Create(nsIFile::NORMAL_FILE_TYPE, 0700);
   854     NS_ENSURE_SUCCESS(rv, rv);
   856     // We don't care about microsecond resolution.
   857     int64_t msec = PR_Now() / PR_USEC_PER_MSEC;
   859     // Write it out.
   860     PRFileDesc *writeFile;
   861     rv = creationLog->OpenNSPRFileDesc(PR_WRONLY, 0700, &writeFile);
   862     NS_ENSURE_SUCCESS(rv, rv);
   864     PR_fprintf(writeFile, "{\n\"created\": %lld\n}\n", msec);
   865     PR_Close(writeFile);
   866     return NS_OK;
   867 }
   869 NS_IMETHODIMP
   870 nsToolkitProfileService::GetProfileCount(uint32_t *aResult)
   871 {
   872     if (!mFirst)
   873         *aResult = 0;
   874     else if (! mFirst->mNext)
   875         *aResult = 1;
   876     else
   877         *aResult = 2;
   879     return NS_OK;
   880 }
   882 NS_IMETHODIMP
   883 nsToolkitProfileService::Flush()
   884 {
   885     // Errors during writing might cause unhappy semi-written files.
   886     // To avoid this, write the entire thing to a buffer, then write
   887     // that buffer to disk.
   889     nsresult rv;
   890     uint32_t pCount = 0;
   891     nsToolkitProfile *cur;
   893     for (cur = mFirst; cur != nullptr; cur = cur->mNext)
   894         ++pCount;
   896     uint32_t length;
   897     nsAutoArrayPtr<char> buffer (new char[100+MAXPATHLEN*pCount]);
   899     NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
   901     char *end = buffer;
   903     end += sprintf(end,
   904                    "[General]\n"
   905                    "StartWithLastProfile=%s\n\n",
   906                    mStartWithLast ? "1" : "0");
   908     nsAutoCString path;
   909     cur = mFirst;
   910     pCount = 0;
   912     while (cur) {
   913         // if the profile dir is relative to appdir...
   914         bool isRelative;
   915         rv = mAppData->Contains(cur->mRootDir, true, &isRelative);
   916         if (NS_SUCCEEDED(rv) && isRelative) {
   917             // we use a relative descriptor
   918             rv = cur->mRootDir->GetRelativeDescriptor(mAppData, path);
   919         } else {
   920             // otherwise, a persistent descriptor
   921             rv = cur->mRootDir->GetPersistentDescriptor(path);
   922             NS_ENSURE_SUCCESS(rv, rv);
   923         }
   925         end += sprintf(end,
   926                        "[Profile%u]\n"
   927                        "Name=%s\n"
   928                        "IsRelative=%s\n"
   929                        "Path=%s\n",
   930                        pCount, cur->mName.get(),
   931                        isRelative ? "1" : "0", path.get());
   933         if (mChosen == cur) {
   934             end += sprintf(end, "Default=1\n");
   935         }
   937         end += sprintf(end, "\n");
   939         cur = cur->mNext;
   940         ++pCount;
   941     }
   943     FILE* writeFile;
   944     rv = mListFile->OpenANSIFileDesc("w", &writeFile);
   945     NS_ENSURE_SUCCESS(rv, rv);
   947     if (buffer) {
   948         length = end - buffer;
   950         if (fwrite(buffer, sizeof(char), length, writeFile) != length) {
   951             fclose(writeFile);
   952             return NS_ERROR_UNEXPECTED;
   953         }
   954     }
   956     fclose(writeFile);
   957     return NS_OK;
   958 }
   960 NS_IMPL_ISUPPORTS(nsToolkitProfileFactory, nsIFactory)
   962 NS_IMETHODIMP
   963 nsToolkitProfileFactory::CreateInstance(nsISupports* aOuter, const nsID& aIID,
   964                                         void** aResult)
   965 {
   966     if (aOuter)
   967         return NS_ERROR_NO_AGGREGATION;
   969     nsCOMPtr<nsIToolkitProfileService> profileService =
   970         nsToolkitProfileService::gService;
   971     if (!profileService) {
   972         nsresult rv = NS_NewToolkitProfileService(getter_AddRefs(profileService));
   973         if (NS_FAILED(rv))
   974             return rv;
   975     }
   976     return profileService->QueryInterface(aIID, aResult);
   977 }
   979 NS_IMETHODIMP
   980 nsToolkitProfileFactory::LockFactory(bool aVal)
   981 {
   982     return NS_OK;
   983 }
   985 nsresult
   986 NS_NewToolkitProfileFactory(nsIFactory* *aResult)
   987 {
   988     *aResult = new nsToolkitProfileFactory();
   989     if (!*aResult)
   990         return NS_ERROR_OUT_OF_MEMORY;
   992     NS_ADDREF(*aResult);
   993     return NS_OK;
   994 }
   996 nsresult
   997 NS_NewToolkitProfileService(nsIToolkitProfileService* *aResult)
   998 {
   999     nsToolkitProfileService* profileService = new nsToolkitProfileService();
  1000     if (!profileService)
  1001         return NS_ERROR_OUT_OF_MEMORY;
  1002     nsresult rv = profileService->Init();
  1003     if (NS_FAILED(rv)) {
  1004         NS_ERROR("nsToolkitProfileService::Init failed!");
  1005         delete profileService;
  1006         return rv;
  1009     NS_ADDREF(*aResult = profileService);
  1010     return NS_OK;
  1013 nsresult
  1014 XRE_GetFileFromPath(const char *aPath, nsIFile* *aResult)
  1016 #if defined(XP_MACOSX)
  1017     int32_t pathLen = strlen(aPath);
  1018     if (pathLen > MAXPATHLEN)
  1019         return NS_ERROR_INVALID_ARG;
  1021     CFURLRef fullPath =
  1022         CFURLCreateFromFileSystemRepresentation(nullptr, (const UInt8 *) aPath,
  1023                                                 pathLen, true);
  1024     if (!fullPath)
  1025         return NS_ERROR_FAILURE;
  1027     nsCOMPtr<nsIFile> lf;
  1028     nsresult rv = NS_NewNativeLocalFile(EmptyCString(), true,
  1029                                         getter_AddRefs(lf));
  1030     if (NS_SUCCEEDED(rv)) {
  1031         nsCOMPtr<nsILocalFileMac> lfMac = do_QueryInterface(lf, &rv);
  1032         if (NS_SUCCEEDED(rv)) {
  1033             rv = lfMac->InitWithCFURL(fullPath);
  1034             if (NS_SUCCEEDED(rv))
  1035                 NS_ADDREF(*aResult = lf);
  1038     CFRelease(fullPath);
  1039     return rv;
  1041 #elif defined(XP_UNIX)
  1042     char fullPath[MAXPATHLEN];
  1044     if (!realpath(aPath, fullPath))
  1045         return NS_ERROR_FAILURE;
  1047     return NS_NewNativeLocalFile(nsDependentCString(fullPath), true,
  1048                                  aResult);
  1049 #elif defined(XP_WIN)
  1050     WCHAR fullPath[MAXPATHLEN];
  1052     if (!_wfullpath(fullPath, NS_ConvertUTF8toUTF16(aPath).get(), MAXPATHLEN))
  1053         return NS_ERROR_FAILURE;
  1055     return NS_NewLocalFile(nsDependentString(fullPath), true,
  1056                            aResult);
  1058 #else
  1059 #error Platform-specific logic needed here.
  1060 #endif

mercurial