Bug 1838629 - Part 7: Inline nursery cell allocation method in Allocator.h r=sfink
[gecko.git] / toolkit / xre / ProfileReset.cpp
blob8ed01e6535e21aafd52bfdea96ac0d1cb05fcfbf
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsIAppStartup.h"
7 #include "nsIFile.h"
8 #include "nsIStringBundle.h"
9 #include "nsIToolkitProfile.h"
10 #include "nsIWindowWatcher.h"
12 #include "ProfileReset.h"
14 #include "nsDirectoryServiceDefs.h"
15 #include "nsDirectoryServiceUtils.h"
16 #include "nsPIDOMWindow.h"
17 #include "nsString.h"
18 #include "mozilla/Components.h"
19 #include "mozilla/XREAppData.h"
21 #include "mozilla/SpinEventLoopUntil.h"
22 #include "mozilla/Unused.h"
24 using namespace mozilla;
26 extern const XREAppData* gAppData;
28 static const char kProfileProperties[] =
29 "chrome://mozapps/locale/profile/profileSelection.properties";
31 /**
32 * Spin up a thread to backup the old profile's main directory and delete the
33 * profile's local directory. Once complete have the profile service remove the
34 * old profile and if necessary make the new profile the default.
36 nsresult ProfileResetCleanup(nsToolkitProfileService* aService,
37 nsIToolkitProfile* aOldProfile) {
38 nsresult rv;
39 nsCOMPtr<nsIFile> profileDir;
40 rv = aOldProfile->GetRootDir(getter_AddRefs(profileDir));
41 if (NS_FAILED(rv)) return rv;
43 nsCOMPtr<nsIFile> profileLocalDir;
44 rv = aOldProfile->GetLocalDir(getter_AddRefs(profileLocalDir));
45 if (NS_FAILED(rv)) return rv;
47 // Get the friendly name for the backup directory.
48 nsCOMPtr<nsIStringBundleService> sbs =
49 mozilla::components::StringBundle::Service();
50 if (!sbs) return NS_ERROR_FAILURE;
52 nsCOMPtr<nsIStringBundle> sb;
53 Unused << sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
54 if (!sb) return NS_ERROR_FAILURE;
56 NS_ConvertUTF8toUTF16 appName(gAppData->name);
57 AutoTArray<nsString, 2> params = {appName, appName};
59 nsAutoString resetBackupDirectoryName;
61 static const char* kResetBackupDirectory = "resetBackupDirectory";
62 rv = sb->FormatStringFromName(kResetBackupDirectory, params,
63 resetBackupDirectoryName);
64 if (NS_FAILED(rv)) return rv;
66 // Get info to copy the old root profile dir to the desktop as a backup.
67 nsCOMPtr<nsIFile> backupDest, containerDest, profileDest;
68 rv = NS_GetSpecialDirectory(NS_OS_DESKTOP_DIR, getter_AddRefs(backupDest));
69 if (NS_FAILED(rv)) {
70 // Fall back to the home directory if the desktop is not available.
71 rv = NS_GetSpecialDirectory(NS_OS_HOME_DIR, getter_AddRefs(backupDest));
72 if (NS_FAILED(rv)) return rv;
75 // Try to create a directory for all the backups
76 backupDest->Clone(getter_AddRefs(containerDest));
77 containerDest->Append(resetBackupDirectoryName);
78 rv = containerDest->Create(nsIFile::DIRECTORY_TYPE, 0700);
79 // It's OK if it already exists, if and only if it is a directory
80 if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
81 bool containerIsDir;
82 rv = containerDest->IsDirectory(&containerIsDir);
83 if (NS_FAILED(rv) || !containerIsDir) {
84 return rv;
86 } else if (NS_FAILED(rv)) {
87 return rv;
90 // Get the name of the profile
91 nsAutoString leafName;
92 rv = profileDir->GetLeafName(leafName);
93 if (NS_FAILED(rv)) return rv;
95 // Try to create a unique directory for the profile:
96 containerDest->Clone(getter_AddRefs(profileDest));
97 profileDest->Append(leafName);
98 rv = profileDest->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
99 if (NS_FAILED(rv)) return rv;
101 // Get the unique profile name
102 rv = profileDest->GetLeafName(leafName);
103 if (NS_FAILED(rv)) return rv;
105 // Delete the empty directory that CreateUnique just created.
106 rv = profileDest->Remove(false);
107 if (NS_FAILED(rv)) return rv;
109 // Show a progress window while the cleanup happens since the disk I/O can
110 // take time.
111 nsCOMPtr<nsIWindowWatcher> windowWatcher(
112 do_GetService(NS_WINDOWWATCHER_CONTRACTID));
113 if (!windowWatcher) return NS_ERROR_FAILURE;
115 nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
116 if (!appStartup) return NS_ERROR_FAILURE;
118 nsCOMPtr<mozIDOMWindowProxy> progressWindow;
119 rv = windowWatcher->OpenWindow(nullptr, nsDependentCString(kResetProgressURL),
120 "_blank"_ns, "centerscreen,chrome,titlebar"_ns,
121 nullptr, getter_AddRefs(progressWindow));
122 if (NS_FAILED(rv)) return rv;
124 // Create a new thread to do the bulk of profile cleanup to stay responsive.
125 nsCOMPtr<nsIThread> cleanupThread;
126 rv = NS_NewNamedThread("ResetCleanup", getter_AddRefs(cleanupThread));
127 if (NS_SUCCEEDED(rv)) {
128 nsCOMPtr<nsIRunnable> runnable = new ProfileResetCleanupAsyncTask(
129 profileDir, profileLocalDir, containerDest, leafName);
130 cleanupThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
131 // The result callback will shut down the worker thread.
133 // Wait for the cleanup thread to complete.
134 SpinEventLoopUntil("xre:ProfileResetCreateBackup"_ns,
135 [&]() { return gProfileResetCleanupCompleted; });
136 } else {
137 gProfileResetCleanupCompleted = true;
138 NS_WARNING("Cleanup thread creation failed");
139 return rv;
141 // Close the progress window now that the cleanup thread is done.
142 auto* piWindow = nsPIDOMWindowOuter::From(progressWindow);
143 piWindow->Close();
145 return aService->ApplyResetProfile(aOldProfile);