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
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsAppRunner.h"
7 #include "nsXREDirProvider.h"
9 # include "commonupdatedir.h"
13 #include "xpcpublic.h"
16 #include "nsIAppStartup.h"
18 #include "nsIObserver.h"
19 #include "nsIObserverService.h"
20 #include "nsISimpleEnumerator.h"
21 #include "nsIToolkitProfileService.h"
22 #include "nsIXULRuntime.h"
23 #include "commonupdatedir.h"
25 #include "nsAppDirectoryServiceDefs.h"
26 #include "nsDirectoryServiceDefs.h"
27 #include "nsDirectoryServiceUtils.h"
28 #include "nsXULAppAPI.h"
29 #include "nsCategoryManagerUtils.h"
31 #include "nsDependentString.h"
32 #include "nsCOMArray.h"
33 #include "nsArrayEnumerator.h"
34 #include "nsEnumeratorUtils.h"
35 #include "nsReadableUtils.h"
37 #include "SpecialSystemDirectory.h"
39 #include "mozilla/dom/ScriptSettings.h"
41 #include "mozilla/AppShutdown.h"
42 #include "mozilla/AutoRestore.h"
43 #ifdef MOZ_BACKGROUNDTASKS
44 # include "mozilla/BackgroundTasks.h"
46 #include "mozilla/Components.h"
47 #include "mozilla/Services.h"
48 #include "mozilla/Omnijar.h"
49 #include "mozilla/Preferences.h"
50 #include "mozilla/ProfilerLabels.h"
51 #include "mozilla/Telemetry.h"
52 #include "mozilla/XREAppData.h"
53 #include "nsPrintfCString.h"
55 #ifdef MOZ_THUNDERBIRD
56 # include "nsIPK11TokenDB.h"
57 # include "nsIPK11Token.h"
65 # include "WinUtils.h"
68 # include "nsILocalFileMac.h"
70 # include <sys/stat.h>
77 # include "UIKitDirProvider.h"
80 #if defined(MOZ_CONTENT_TEMP_DIR)
81 # include "mozilla/SandboxSettings.h"
83 # include "mozilla/Unused.h"
86 #if defined(XP_MACOSX)
87 # define APP_REGISTRY_NAME "Application Registry"
89 # define APP_REGISTRY_NAME "registry.dat"
91 # define APP_REGISTRY_NAME "appreg"
94 #define PREF_OVERRIDE_DIRNAME "preferences"
96 #if defined(MOZ_CONTENT_TEMP_DIR)
97 static already_AddRefed
<nsIFile
> GetProcessSandboxTempDir(
98 GeckoProcessType type
);
99 static nsresult
DeleteDirIfExists(nsIFile
* dir
);
100 static bool IsContentSandboxDisabled();
101 static const char* GetProcessTempBaseDirKey();
102 static already_AddRefed
<nsIFile
> CreateProcessSandboxTempDir(
103 GeckoProcessType procType
);
106 nsXREDirProvider
* gDirServiceProvider
= nullptr;
107 nsIFile
* gDataDirHomeLocal
= nullptr;
108 nsIFile
* gDataDirHome
= nullptr;
109 nsCOMPtr
<nsIFile
> gDataDirProfileLocal
= nullptr;
110 nsCOMPtr
<nsIFile
> gDataDirProfile
= nullptr;
112 // These are required to allow nsXREDirProvider to be usable in xpcshell tests.
113 // where gAppData is null.
114 #if defined(XP_MACOSX) || defined(XP_UNIX)
115 static const char* GetAppName() {
117 return gAppData
->name
;
124 static const char* GetAppVendor() {
126 return gAppData
->vendor
;
132 nsXREDirProvider::nsXREDirProvider() { gDirServiceProvider
= this; }
134 nsXREDirProvider::~nsXREDirProvider() {
135 gDirServiceProvider
= nullptr;
136 gDataDirHomeLocal
= nullptr;
137 gDataDirHome
= nullptr;
140 already_AddRefed
<nsXREDirProvider
> nsXREDirProvider::GetSingleton() {
141 if (!gDirServiceProvider
) {
142 new nsXREDirProvider(); // This sets gDirServiceProvider
144 return do_AddRef(gDirServiceProvider
);
147 nsresult
nsXREDirProvider::Initialize(nsIFile
* aXULAppDir
, nsIFile
* aGREDir
) {
148 NS_ENSURE_ARG(aXULAppDir
);
149 NS_ENSURE_ARG(aGREDir
);
151 mXULAppDir
= aXULAppDir
;
153 nsCOMPtr
<nsIFile
> binaryPath
;
154 nsresult rv
= XRE_GetBinaryPath(getter_AddRefs(binaryPath
));
155 NS_ENSURE_SUCCESS(rv
, rv
);
156 return binaryPath
->GetParent(getter_AddRefs(mGREBinDir
));
159 nsresult
nsXREDirProvider::SetProfile(nsIFile
* aDir
, nsIFile
* aLocalDir
) {
160 MOZ_ASSERT(aDir
&& aLocalDir
, "We don't support no-profile apps!");
161 MOZ_ASSERT(!mProfileDir
&& !mProfileLocalDir
,
162 "You may only set the profile directories once");
164 nsresult rv
= EnsureDirectoryExists(aDir
);
165 NS_ENSURE_SUCCESS(rv
, rv
);
167 rv
= EnsureDirectoryExists(aLocalDir
);
168 NS_ENSURE_SUCCESS(rv
, rv
);
171 nsAutoCString profilePath
;
172 rv
= aDir
->GetNativePath(profilePath
);
173 NS_ENSURE_SUCCESS(rv
, rv
);
175 nsAutoCString localProfilePath
;
176 rv
= aLocalDir
->GetNativePath(localProfilePath
);
177 NS_ENSURE_SUCCESS(rv
, rv
);
179 if (!mozilla::IsUtf8(profilePath
) || !mozilla::IsUtf8(localProfilePath
)) {
182 "Error: The profile path is not valid UTF-8. Unable to continue.\n");
183 return NS_ERROR_FAILURE
;
189 if (NS_SUCCEEDED(aDir
->Equals(aLocalDir
, &same
)) && !same
) {
190 // Ensure that the cache directory is not indexed by Spotlight
191 // (bug 718910). At least on OS X, the cache directory (under
192 // ~/Library/Caches/) is always the "local" user profile
193 // directory. This is confusing, since *both* user profile
194 // directories are "local" (they both exist under the user's
195 // home directory). But this usage dates back at least as far
196 // as the patch for bug 291033, where "local" seems to mean
197 // "suitable for temporary storage". Don't hide the cache
198 // directory if by some chance it and the "non-local" profile
199 // directory are the same -- there are bad side effects from
200 // hiding a profile directory under /Library/Application Support/
202 nsAutoCString cacheDir
;
203 if (NS_SUCCEEDED(aLocalDir
->GetNativePath(cacheDir
))) {
204 if (chflags(cacheDir
.get(), UF_HIDDEN
)) {
205 NS_WARNING("Failed to set Cache directory to HIDDEN.");
212 mProfileLocalDir
= aLocalDir
;
216 NS_IMPL_QUERY_INTERFACE(nsXREDirProvider
, nsIDirectoryServiceProvider
,
217 nsIDirectoryServiceProvider2
, nsIXREDirProvider
,
220 NS_IMETHODIMP_(MozExternalRefCountType
)
221 nsXREDirProvider::AddRef() { return 1; }
223 NS_IMETHODIMP_(MozExternalRefCountType
)
224 nsXREDirProvider::Release() { return 0; }
226 nsresult
nsXREDirProvider::GetUserProfilesRootDir(nsIFile
** aResult
) {
227 nsCOMPtr
<nsIFile
> file
;
228 nsresult rv
= GetUserDataDirectory(getter_AddRefs(file
), false);
230 if (NS_SUCCEEDED(rv
)) {
231 #if !defined(XP_UNIX) || defined(XP_MACOSX)
232 rv
= file
->AppendNative("Profiles"_ns
);
234 // We must create the profile directory here if it does not exist.
235 nsresult tmp
= EnsureDirectoryExists(file
);
236 if (NS_FAILED(tmp
)) {
244 nsresult
nsXREDirProvider::GetUserProfilesLocalDir(nsIFile
** aResult
) {
245 nsCOMPtr
<nsIFile
> file
;
246 nsresult rv
= GetUserDataDirectory(getter_AddRefs(file
), true);
248 if (NS_SUCCEEDED(rv
)) {
249 #if !defined(XP_UNIX) || defined(XP_MACOSX)
250 rv
= file
->AppendNative("Profiles"_ns
);
252 // We must create the profile directory here if it does not exist.
253 nsresult tmp
= EnsureDirectoryExists(file
);
254 if (NS_FAILED(tmp
)) {
262 #ifdef MOZ_BACKGROUNDTASKS
263 nsresult
nsXREDirProvider::GetBackgroundTasksProfilesRootDir(
265 nsCOMPtr
<nsIFile
> file
;
266 nsresult rv
= GetUserDataDirectory(getter_AddRefs(file
), false);
268 if (NS_SUCCEEDED(rv
)) {
269 # if !defined(XP_UNIX) || defined(XP_MACOSX)
270 // Sibling to regular user "Profiles" directory.
271 rv
= file
->AppendNative("Background Tasks Profiles"_ns
);
273 // We must create the directory here if it does not exist.
274 nsresult tmp
= EnsureDirectoryExists(file
);
275 if (NS_FAILED(tmp
)) {
284 #if defined(XP_UNIX) || defined(XP_MACOSX)
286 * Get the directory that is the parent of the system-wide directories
287 * for extensions and native manifests.
289 * On OSX this is /Library/Application Support/Mozilla
290 * On Linux this is /usr/{lib,lib64}/mozilla
291 * (for 32- and 64-bit systems respsectively)
293 static nsresult
GetSystemParentDirectory(nsIFile
** aFile
) {
295 nsCOMPtr
<nsIFile
> localDir
;
296 # if defined(XP_MACOSX)
297 rv
= GetOSXFolderType(kOnSystemDisk
, kApplicationSupportFolderType
,
298 getter_AddRefs(localDir
));
299 if (NS_SUCCEEDED(rv
)) {
300 rv
= localDir
->AppendNative("Mozilla"_ns
);
303 constexpr auto dirname
=
304 # ifdef HAVE_USR_LIB64_DIR
305 "/usr/lib64/mozilla"_ns
306 # elif defined(__OpenBSD__) || defined(__FreeBSD__)
307 "/usr/local/lib/mozilla"_ns
309 "/usr/lib/mozilla"_ns
312 rv
= NS_NewNativeLocalFile(dirname
, false, getter_AddRefs(localDir
));
315 if (NS_SUCCEEDED(rv
)) {
316 localDir
.forget(aFile
);
323 nsXREDirProvider::GetFile(const char* aProperty
, bool* aPersistent
,
326 nsresult rv
= NS_ERROR_FAILURE
;
328 nsCOMPtr
<nsIFile
> file
;
330 if (!strcmp(aProperty
, NS_APP_USER_PROFILE_LOCAL_50_DIR
) ||
331 !strcmp(aProperty
, NS_APP_PROFILE_LOCAL_DIR_STARTUP
)) {
332 if (mProfileLocalDir
) {
333 rv
= mProfileLocalDir
->Clone(getter_AddRefs(file
));
335 // Profile directories are only set up in the parent process.
336 // We don't expect every caller to check if they are in the right process,
337 // so fail immediately to avoid warning spam.
338 NS_WARNING_ASSERTION(!XRE_IsParentProcess(),
339 "tried to get profile in parent too early");
340 return NS_ERROR_FAILURE
;
342 } else if (!strcmp(aProperty
, NS_APP_USER_PROFILE_50_DIR
) ||
343 !strcmp(aProperty
, NS_APP_PROFILE_DIR_STARTUP
)) {
344 rv
= GetProfileStartupDir(getter_AddRefs(file
));
348 } else if (!strcmp(aProperty
, NS_GRE_DIR
)) {
349 // On Android, internal files are inside the APK, a zip file, so this
350 // folder doesn't really make sense.
351 #if !defined(MOZ_WIDGET_ANDROID)
352 rv
= mGREDir
->Clone(getter_AddRefs(file
));
353 #endif // !defined(MOZ_WIDGET_ANDROID)
354 } else if (!strcmp(aProperty
, NS_GRE_BIN_DIR
)) {
355 rv
= mGREBinDir
->Clone(getter_AddRefs(file
));
356 } else if (!strcmp(aProperty
, NS_OS_CURRENT_PROCESS_DIR
) ||
357 !strcmp(aProperty
, NS_APP_INSTALL_CLEANUP_DIR
)) {
358 rv
= GetAppDir()->Clone(getter_AddRefs(file
));
359 } else if (!strcmp(aProperty
, NS_APP_PREF_DEFAULTS_50_DIR
)) {
360 // Same as NS_GRE_DIR
361 #if !defined(MOZ_WIDGET_ANDROID)
362 // return the GRE default prefs directory here, and the app default prefs
363 // directory (if applicable) in NS_APP_PREFS_DEFAULTS_DIR_LIST.
364 rv
= mGREDir
->Clone(getter_AddRefs(file
));
365 NS_ENSURE_SUCCESS(rv
, rv
);
366 rv
= file
->AppendNative("defaults"_ns
);
367 NS_ENSURE_SUCCESS(rv
, rv
);
368 rv
= file
->AppendNative("pref"_ns
);
369 #endif // !defined(MOZ_WIDGET_ANDROID)
370 } else if (!strcmp(aProperty
, NS_APP_APPLICATION_REGISTRY_DIR
) ||
371 !strcmp(aProperty
, XRE_USER_APP_DATA_DIR
)) {
372 rv
= GetUserAppDataDirectory(getter_AddRefs(file
));
374 #if defined(XP_UNIX) || defined(XP_MACOSX)
375 else if (!strcmp(aProperty
, XRE_SYS_NATIVE_MANIFESTS
)) {
376 rv
= ::GetSystemParentDirectory(getter_AddRefs(file
));
377 } else if (!strcmp(aProperty
, XRE_USER_NATIVE_MANIFESTS
)) {
378 rv
= GetUserDataDirectoryHome(getter_AddRefs(file
), false);
379 NS_ENSURE_SUCCESS(rv
, rv
);
380 # if defined(XP_MACOSX)
381 rv
= file
->AppendNative("Mozilla"_ns
);
382 # else // defined(XP_MACOSX)
383 rv
= file
->AppendNative(".mozilla"_ns
);
384 # endif // defined(XP_MACOSX)
386 #endif // defined(XP_UNIX) || defined(XP_MACOSX)
387 else if (!strcmp(aProperty
, XRE_UPDATE_ROOT_DIR
)) {
388 rv
= GetUpdateRootDir(getter_AddRefs(file
));
389 } else if (!strcmp(aProperty
, XRE_OLD_UPDATE_ROOT_DIR
)) {
390 rv
= GetUpdateRootDir(getter_AddRefs(file
), true);
391 } else if (!strcmp(aProperty
, NS_APP_APPLICATION_REGISTRY_FILE
)) {
392 rv
= GetUserAppDataDirectory(getter_AddRefs(file
));
393 NS_ENSURE_SUCCESS(rv
, rv
);
394 rv
= file
->AppendNative(nsLiteralCString(APP_REGISTRY_NAME
));
395 } else if (!strcmp(aProperty
, NS_APP_USER_PROFILES_ROOT_DIR
)) {
396 rv
= GetUserProfilesRootDir(getter_AddRefs(file
));
397 } else if (!strcmp(aProperty
, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR
)) {
398 rv
= GetUserProfilesLocalDir(getter_AddRefs(file
));
399 } else if (!strcmp(aProperty
, XRE_EXECUTABLE_FILE
)) {
400 rv
= XRE_GetBinaryPath(getter_AddRefs(file
));
402 #if defined(XP_UNIX) || defined(XP_MACOSX)
403 else if (!strcmp(aProperty
, XRE_SYS_LOCAL_EXTENSION_PARENT_DIR
)) {
404 # ifdef ENABLE_SYSTEM_EXTENSION_DIRS
405 rv
= GetSystemExtensionsDirectory(getter_AddRefs(file
));
408 #endif // defined(XP_UNIX) || defined(XP_MACOSX)
409 #if defined(XP_UNIX) && !defined(XP_MACOSX)
410 else if (!strcmp(aProperty
, XRE_SYS_SHARE_EXTENSION_PARENT_DIR
)) {
411 # ifdef ENABLE_SYSTEM_EXTENSION_DIRS
412 # if defined(__OpenBSD__) || defined(__FreeBSD__)
413 static const char* const sysLExtDir
= "/usr/local/share/mozilla/extensions";
415 static const char* const sysLExtDir
= "/usr/share/mozilla/extensions";
417 rv
= NS_NewNativeLocalFile(nsDependentCString(sysLExtDir
), false,
418 getter_AddRefs(file
));
421 #endif // defined(XP_UNIX) && !defined(XP_MACOSX)
422 else if (!strcmp(aProperty
, XRE_USER_SYS_EXTENSION_DIR
)) {
423 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
424 rv
= GetSysUserExtensionsDirectory(getter_AddRefs(file
));
426 } else if (!strcmp(aProperty
, XRE_USER_RUNTIME_DIR
)) {
428 nsPrintfCString
path("/run/user/%d/%s/", getuid(), GetAppName());
430 rv
= NS_NewNativeLocalFile(path
, false, getter_AddRefs(file
));
432 } else if (!strcmp(aProperty
, XRE_APP_DISTRIBUTION_DIR
)) {
433 bool persistent
= false;
434 rv
= GetFile(NS_GRE_DIR
, &persistent
, getter_AddRefs(file
));
435 NS_ENSURE_SUCCESS(rv
, rv
);
436 rv
= file
->AppendNative("distribution"_ns
);
437 } else if (!strcmp(aProperty
, XRE_APP_FEATURES_DIR
)) {
438 rv
= GetAppDir()->Clone(getter_AddRefs(file
));
439 NS_ENSURE_SUCCESS(rv
, rv
);
440 rv
= file
->AppendNative("features"_ns
);
441 } else if (!strcmp(aProperty
, XRE_ADDON_APP_DIR
)) {
442 nsCOMPtr
<nsIDirectoryServiceProvider
> dirsvc(
443 do_GetService("@mozilla.org/file/directory_service;1", &rv
));
444 NS_ENSURE_SUCCESS(rv
, rv
);
446 rv
= dirsvc
->GetFile("XCurProcD", &unused
, getter_AddRefs(file
));
448 #if defined(MOZ_CONTENT_TEMP_DIR)
449 else if (!strcmp(aProperty
, NS_APP_CONTENT_PROCESS_TEMP_DIR
)) {
450 if (!mContentTempDir
) {
451 rv
= LoadContentProcessTempDir();
452 NS_ENSURE_SUCCESS(rv
, rv
);
454 rv
= mContentTempDir
->Clone(getter_AddRefs(file
));
456 #endif // defined(MOZ_CONTENT_TEMP_DIR)
457 else if (!strcmp(aProperty
, NS_APP_USER_CHROME_DIR
)) {
458 // It isn't clear why this uses GetProfileStartupDir instead of
459 // GetProfileDir. It could theoretically matter in a non-main
460 // process where some other directory provider has defined
461 // NS_APP_USER_PROFILE_50_DIR. In that scenario, using
462 // GetProfileStartupDir means this will fail instead of succeed.
463 rv
= GetProfileStartupDir(getter_AddRefs(file
));
467 rv
= file
->AppendNative("chrome"_ns
);
468 } else if (!strcmp(aProperty
, NS_APP_PREFS_50_DIR
)) {
469 rv
= GetProfileDir(getter_AddRefs(file
));
473 } else if (!strcmp(aProperty
, NS_APP_PREFS_50_FILE
)) {
474 rv
= GetProfileDir(getter_AddRefs(file
));
478 rv
= file
->AppendNative("prefs.js"_ns
);
479 } else if (!strcmp(aProperty
, NS_APP_PREFS_OVERRIDE_DIR
)) {
480 rv
= GetProfileDir(getter_AddRefs(file
));
484 rv
= file
->AppendNative(nsLiteralCString(PREF_OVERRIDE_DIRNAME
));
485 NS_ENSURE_SUCCESS(rv
, rv
);
486 rv
= EnsureDirectoryExists(file
);
488 // We don't know anything about this property. Fail without warning, because
489 // otherwise we'll get too much warning spam due to
490 // nsDirectoryService::Get() trying everything it gets with every provider.
491 return NS_ERROR_FAILURE
;
494 NS_ENSURE_SUCCESS(rv
, rv
);
495 NS_ENSURE_TRUE(file
, NS_ERROR_FAILURE
);
501 static void LoadDirIntoArray(nsIFile
* dir
, const char* const* aAppendList
,
502 nsCOMArray
<nsIFile
>& aDirectories
) {
505 nsCOMPtr
<nsIFile
> subdir
;
506 dir
->Clone(getter_AddRefs(subdir
));
509 for (const char* const* a
= aAppendList
; *a
; ++a
) {
510 subdir
->AppendNative(nsDependentCString(*a
));
514 if (NS_SUCCEEDED(subdir
->Exists(&exists
)) && exists
) {
515 aDirectories
.AppendObject(subdir
);
519 #if defined(MOZ_CONTENT_TEMP_DIR)
521 static const char* GetProcessTempBaseDirKey() { return NS_OS_TEMP_DIR
; }
524 // Sets mContentTempDir so that it refers to the appropriate temp dir.
525 // If the sandbox is enabled, NS_APP_CONTENT_PROCESS_TEMP_DIR, otherwise
526 // NS_OS_TEMP_DIR is used.
528 nsresult
nsXREDirProvider::LoadContentProcessTempDir() {
529 // The parent is responsible for creating the sandbox temp dir.
530 if (XRE_IsParentProcess()) {
531 mContentProcessSandboxTempDir
=
532 CreateProcessSandboxTempDir(GeckoProcessType_Content
);
533 mContentTempDir
= mContentProcessSandboxTempDir
;
535 mContentTempDir
= !IsContentSandboxDisabled()
536 ? GetProcessSandboxTempDir(GeckoProcessType_Content
)
540 if (!mContentTempDir
) {
542 NS_GetSpecialDirectory(NS_OS_TEMP_DIR
, getter_AddRefs(mContentTempDir
));
543 if (NS_WARN_IF(NS_FAILED(rv
))) {
551 static bool IsContentSandboxDisabled() {
552 return !mozilla::BrowserTabsRemoteAutostart() ||
553 (!mozilla::IsContentSandboxEnabled());
557 // If a process sandbox temp dir is to be used, returns an nsIFile
558 // for the directory. Returns null if an error occurs.
560 static already_AddRefed
<nsIFile
> GetProcessSandboxTempDir(
561 GeckoProcessType type
) {
562 nsCOMPtr
<nsIFile
> localFile
;
564 nsresult rv
= NS_GetSpecialDirectory(GetProcessTempBaseDirKey(),
565 getter_AddRefs(localFile
));
566 if (NS_WARN_IF(NS_FAILED(rv
))) {
570 MOZ_ASSERT(type
== GeckoProcessType_Content
);
572 const char* prefKey
= "security.sandbox.content.tempDirSuffix";
573 nsAutoString tempDirSuffix
;
574 rv
= mozilla::Preferences::GetString(prefKey
, tempDirSuffix
);
575 if (NS_WARN_IF(NS_FAILED(rv
)) || tempDirSuffix
.IsEmpty()) {
579 rv
= localFile
->Append(u
"Temp-"_ns
+ tempDirSuffix
);
580 if (NS_WARN_IF(NS_FAILED(rv
))) {
584 return localFile
.forget();
588 // Create a temporary directory for use from sandboxed processes.
589 // Only called in the parent. The path is derived from a UUID stored in a
590 // pref which is available to content processes. Returns null
591 // if the content sandbox is disabled or if an error occurs.
593 static already_AddRefed
<nsIFile
> CreateProcessSandboxTempDir(
594 GeckoProcessType procType
) {
595 if ((procType
== GeckoProcessType_Content
) && IsContentSandboxDisabled()) {
599 MOZ_ASSERT(procType
== GeckoProcessType_Content
);
601 // Get (and create if blank) temp directory suffix pref.
602 const char* pref
= "security.sandbox.content.tempDirSuffix";
605 nsAutoString tempDirSuffix
;
606 mozilla::Preferences::GetString(pref
, tempDirSuffix
);
608 if (tempDirSuffix
.IsEmpty()) {
610 rv
= nsID::GenerateUUIDInPlace(uuid
);
611 if (NS_WARN_IF(NS_FAILED(rv
))) {
615 char uuidChars
[NSID_LENGTH
];
616 uuid
.ToProvidedString(uuidChars
);
617 tempDirSuffix
.AssignASCII(uuidChars
, NSID_LENGTH
);
619 // Braces in a path are somewhat annoying to deal with
620 // and pretty alien on Unix
621 tempDirSuffix
.StripChars(u
"{}");
625 rv
= mozilla::Preferences::SetString(pref
, tempDirSuffix
);
626 if (NS_WARN_IF(NS_FAILED(rv
))) {
627 // If we fail to save the pref we don't want to create the temp dir,
628 // because we won't be able to clean it up later.
632 nsCOMPtr
<nsIPrefService
> prefsvc
= mozilla::Preferences::GetService();
633 if (!prefsvc
|| NS_FAILED((rv
= prefsvc
->SavePrefFile(nullptr)))) {
634 // Again, if we fail to save the pref file we might not be able to clean
635 // up the temp directory, so don't create one. Note that in the case
636 // the preference values allows an off main thread save, the successful
637 // return from the call doesn't mean we actually saved the file. See
638 // bug 1364496 for details.
639 NS_WARNING("Failed to save pref file, cannot create temp dir.");
644 nsCOMPtr
<nsIFile
> sandboxTempDir
= GetProcessSandboxTempDir(procType
);
645 if (!sandboxTempDir
) {
646 NS_WARNING("Failed to determine sandbox temp dir path.");
650 // Remove the directory. It may exist due to a previous crash.
651 if (NS_FAILED(DeleteDirIfExists(sandboxTempDir
))) {
652 NS_WARNING("Failed to reset sandbox temp dir.");
656 // Create the directory
657 rv
= sandboxTempDir
->Create(nsIFile::DIRECTORY_TYPE
, 0700);
659 NS_WARNING("Failed to create sandbox temp dir.");
663 return sandboxTempDir
.forget();
666 static nsresult
DeleteDirIfExists(nsIFile
* dir
) {
668 // Don't return an error if the directory doesn't exist.
669 nsresult rv
= dir
->Remove(/* aRecursive */ true);
670 if (NS_FAILED(rv
) && rv
!= NS_ERROR_FILE_NOT_FOUND
) {
677 #endif // defined(MOZ_CONTENT_TEMP_DIR)
679 static const char* const kAppendPrefDir
[] = {"defaults", "preferences",
681 #ifdef MOZ_BACKGROUNDTASKS
682 static const char* const kAppendBackgroundTasksPrefDir
[] = {
683 "defaults", "backgroundtasks", nullptr};
687 nsXREDirProvider::GetFiles(const char* aProperty
,
688 nsISimpleEnumerator
** aResult
) {
689 nsresult rv
= NS_ERROR_FAILURE
;
692 if (!strcmp(aProperty
, NS_APP_PREFS_DEFAULTS_DIR_LIST
)) {
693 nsCOMArray
<nsIFile
> directories
;
695 LoadDirIntoArray(mXULAppDir
, kAppendPrefDir
, directories
);
696 #ifdef MOZ_BACKGROUNDTASKS
697 if (mozilla::BackgroundTasks::IsBackgroundTaskMode()) {
698 LoadDirIntoArray(mGREDir
, kAppendBackgroundTasksPrefDir
, directories
);
699 LoadDirIntoArray(mXULAppDir
, kAppendBackgroundTasksPrefDir
, directories
);
703 rv
= NS_NewArrayEnumerator(aResult
, directories
, NS_GET_IID(nsIFile
));
704 } else if (!strcmp(aProperty
, NS_APP_CHROME_DIR_LIST
)) {
705 // NS_APP_CHROME_DIR_LIST is only used to get default (native) icons
706 // for OS window decoration.
708 static const char* const kAppendChromeDir
[] = {"chrome", nullptr};
709 nsCOMArray
<nsIFile
> directories
;
710 LoadDirIntoArray(mXULAppDir
, kAppendChromeDir
, directories
);
712 rv
= NS_NewArrayEnumerator(aResult
, directories
, NS_GET_IID(nsIFile
));
714 NS_ENSURE_SUCCESS(rv
, rv
);
716 return NS_SUCCESS_AGGREGATE_RESULT
;
720 nsXREDirProvider::GetDirectory(nsIFile
** aResult
) {
721 NS_ENSURE_TRUE(mProfileDir
, NS_ERROR_NOT_INITIALIZED
);
722 return mProfileDir
->Clone(aResult
);
725 void nsXREDirProvider::InitializeUserPrefs() {
726 if (!mPrefsInitialized
) {
727 mozilla::Preferences::InitializeUserPrefs();
731 void nsXREDirProvider::FinishInitializingUserPrefs() {
732 if (!mPrefsInitialized
) {
733 mozilla::Preferences::FinishInitializingUserPrefs();
734 mPrefsInitialized
= true;
739 nsXREDirProvider::DoStartup() {
743 nsCOMPtr
<nsIObserverService
> obsSvc
=
744 mozilla::services::GetObserverService();
745 if (!obsSvc
) return NS_ERROR_FAILURE
;
750 Make sure we've setup prefs before profile-do-change to be able to use
751 them to track crashes and because we want to begin crash tracking before
752 other code run from this notification since they may cause crashes.
754 MOZ_ASSERT(mPrefsInitialized
);
756 bool safeModeNecessary
= false;
757 nsCOMPtr
<nsIAppStartup
> appStartup(
758 mozilla::components::AppStartup::Service());
760 rv
= appStartup
->TrackStartupCrashBegin(&safeModeNecessary
);
761 if (NS_FAILED(rv
) && rv
!= NS_ERROR_NOT_AVAILABLE
)
762 NS_WARNING("Error while beginning startup crash tracking");
764 if (!gSafeMode
&& safeModeNecessary
) {
765 appStartup
->RestartInSafeMode(nsIAppStartup::eForceQuit
);
770 static const char16_t kStartup
[] = {'s', 't', 'a', 'r',
771 't', 'u', 'p', '\0'};
772 obsSvc
->NotifyObservers(nullptr, "profile-do-change", kStartup
);
774 // Initialize the Enterprise Policies service in the parent process
775 // In the content process it's loaded on demand when needed
776 if (XRE_IsParentProcess()) {
777 nsCOMPtr
<nsIObserver
> policies(
778 do_GetService("@mozilla.org/enterprisepolicies;1"));
780 policies
->Observe(nullptr, "policies-startup", nullptr);
784 #ifdef MOZ_THUNDERBIRD
785 bool bgtaskMode
= false;
786 # ifdef MOZ_BACKGROUNDTASKS
787 bgtaskMode
= mozilla::BackgroundTasks::IsBackgroundTaskMode();
790 mozilla::Preferences::GetBool(
791 "security.prompt_for_master_password_on_startup", false)) {
792 // Prompt for the master password prior to opening application windows,
793 // to avoid the race that triggers multiple prompts (see bug 177175).
794 // We use this code until we have a better solution, possibly as
795 // described in bug 177175 comment 384.
796 nsCOMPtr
<nsIPK11TokenDB
> db
=
797 do_GetService("@mozilla.org/security/pk11tokendb;1");
799 nsCOMPtr
<nsIPK11Token
> token
;
800 if (NS_SUCCEEDED(db
->GetInternalKeyToken(getter_AddRefs(token
)))) {
801 mozilla::Unused
<< token
->Login(false);
804 NS_WARNING("Failed to get nsIPK11TokenDB service.");
809 bool initExtensionManager
=
810 #ifdef MOZ_BACKGROUNDTASKS
811 !mozilla::BackgroundTasks::IsBackgroundTaskMode();
815 if (initExtensionManager
) {
816 // Init the Extension Manager
817 nsCOMPtr
<nsIObserver
> em
=
818 do_GetService("@mozilla.org/addons/integration;1");
820 em
->Observe(nullptr, "addons-startup", nullptr);
822 NS_WARNING("Failed to create Addons Manager.");
826 obsSvc
->NotifyObservers(nullptr, "profile-after-change", kStartup
);
828 // Any component that has registered for the profile-after-change category
829 // should also be created at this time.
830 (void)NS_CreateServicesFromCategory("profile-after-change", nullptr,
831 "profile-after-change");
833 if (gSafeMode
&& safeModeNecessary
) {
834 static const char16_t kCrashed
[] = {'c', 'r', 'a', 's',
835 'h', 'e', 'd', '\0'};
836 obsSvc
->NotifyObservers(nullptr, "safemode-forced", kCrashed
);
839 // 1 = Regular mode, 2 = Safe mode, 3 = Safe mode forced
842 if (safeModeNecessary
)
847 mozilla::Telemetry::Accumulate(mozilla::Telemetry::SAFE_MODE_USAGE
, mode
);
849 obsSvc
->NotifyObservers(nullptr, "profile-initial-state", nullptr);
851 #if defined(MOZ_CONTENT_TEMP_DIR)
852 // Makes sure the content temp dir has been loaded if it hasn't been
853 // already. In the parent this ensures it has been created before we attempt
854 // to start any content processes.
855 if (!mContentTempDir
) {
856 mozilla::Unused
<< NS_WARN_IF(NS_FAILED(LoadContentProcessTempDir()));
863 void nsXREDirProvider::DoShutdown() {
864 AUTO_PROFILER_LABEL("nsXREDirProvider::DoShutdown", OTHER
);
867 mozilla::AppShutdown::AdvanceShutdownPhase(
868 mozilla::ShutdownPhase::AppShutdownNetTeardown
, nullptr);
869 mozilla::AppShutdown::AdvanceShutdownPhase(
870 mozilla::ShutdownPhase::AppShutdownTeardown
, nullptr);
873 // Not having this causes large intermittent leaks. See bug 1340425.
874 if (JSContext
* cx
= mozilla::dom::danger::GetJSContext()) {
879 mozilla::AppShutdown::AdvanceShutdownPhase(
880 mozilla::ShutdownPhase::AppShutdown
, nullptr);
881 mozilla::AppShutdown::AdvanceShutdownPhase(
882 mozilla::ShutdownPhase::AppShutdownQM
, nullptr);
883 mozilla::AppShutdown::AdvanceShutdownPhase(
884 mozilla::ShutdownPhase::AppShutdownTelemetry
, nullptr);
888 gDataDirProfileLocal
= nullptr;
889 gDataDirProfile
= nullptr;
891 #if defined(MOZ_CONTENT_TEMP_DIR)
892 if (XRE_IsParentProcess()) {
893 mozilla::Unused
<< DeleteDirIfExists(mContentProcessSandboxTempDir
);
899 static nsresult
GetShellFolderPath(KNOWNFOLDERID folder
, nsAString
& _retval
) {
900 DWORD flags
= KF_FLAG_SIMPLE_IDLIST
| KF_FLAG_DONT_VERIFY
| KF_FLAG_NO_ALIAS
;
901 PWSTR path
= nullptr;
903 if (!SUCCEEDED(SHGetKnownFolderPath(folder
, flags
, NULL
, &path
))) {
904 return NS_ERROR_NOT_AVAILABLE
;
907 _retval
= nsDependentString(path
);
913 * Provides a fallback for getting the path to APPDATA or LOCALAPPDATA by
914 * querying the registry when the call to SHGetSpecialFolderLocation or
915 * SHGetPathFromIDListW is unable to provide these paths (Bug 513958).
917 static nsresult
GetRegWindowsAppDataFolder(bool aLocal
, nsAString
& _retval
) {
920 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
921 DWORD res
= ::RegOpenKeyExW(HKEY_CURRENT_USER
, keyName
, 0, KEY_READ
, &key
);
922 if (res
!= ERROR_SUCCESS
) {
923 _retval
.SetLength(0);
924 return NS_ERROR_NOT_AVAILABLE
;
928 res
= RegQueryValueExW(key
, (aLocal
? L
"Local AppData" : L
"AppData"), nullptr,
929 &type
, nullptr, &size
);
930 // The call to RegQueryValueExW must succeed, the type must be REG_SZ, the
931 // buffer size must not equal 0, and the buffer size be a multiple of 2.
932 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
|| size
== 0 || size
% 2 != 0) {
934 _retval
.SetLength(0);
935 return NS_ERROR_NOT_AVAILABLE
;
938 // |size| may or may not include room for the terminating null character
939 DWORD resultLen
= size
/ 2;
941 if (!_retval
.SetLength(resultLen
, mozilla::fallible
)) {
943 _retval
.SetLength(0);
944 return NS_ERROR_NOT_AVAILABLE
;
947 auto begin
= _retval
.BeginWriting();
949 res
= RegQueryValueExW(key
, (aLocal
? L
"Local AppData" : L
"AppData"), nullptr,
950 nullptr, (LPBYTE
)begin
, &size
);
952 if (res
!= ERROR_SUCCESS
) {
953 _retval
.SetLength(0);
954 return NS_ERROR_NOT_AVAILABLE
;
957 if (!_retval
.CharAt(resultLen
- 1)) {
958 // It was already null terminated.
959 _retval
.Truncate(resultLen
- 1);
966 static nsresult
HashInstallPath(nsAString
& aInstallPath
, nsAString
& aPathHash
) {
967 mozilla::UniquePtr
<NS_tchar
[]> hash
;
968 bool success
= ::GetInstallHash(PromiseFlatString(aInstallPath
).get(), hash
);
970 return NS_ERROR_FAILURE
;
973 // The hash string is a NS_tchar*, which is wchar* in Windows and char*
976 aPathHash
.Assign(hash
.get());
978 aPathHash
.AssignASCII(hash
.get());
984 * Gets a hash of the installation directory.
986 nsresult
nsXREDirProvider::GetInstallHash(nsAString
& aPathHash
) {
987 nsAutoString stringToHash
;
990 if (mozilla::widget::WinUtils::HasPackageIdentity()) {
991 // For packages, the install path includes the version number, so it isn't
992 // a stable or consistent identifier for the installation. The package
993 // family name is though, so use that instead of the path.
994 stringToHash
= mozilla::widget::WinUtils::GetPackageFamilyName();
998 nsCOMPtr
<nsIFile
> installDir
;
999 nsCOMPtr
<nsIFile
> appFile
;
1001 nsresult rv
= GetFile(XRE_EXECUTABLE_FILE
, &per
, getter_AddRefs(appFile
));
1002 NS_ENSURE_SUCCESS(rv
, rv
);
1003 rv
= appFile
->GetParent(getter_AddRefs(installDir
));
1004 NS_ENSURE_SUCCESS(rv
, rv
);
1006 // It is possible that the path we have is on a case insensitive
1007 // filesystem in which case the path may vary depending on how the
1008 // application is called. We want to normalize the case somehow.
1010 // Windows provides a way to get the correct case.
1011 if (!mozilla::widget::WinUtils::ResolveJunctionPointsAndSymLinks(
1013 NS_WARNING("Failed to resolve install directory.");
1015 #elif defined(MOZ_WIDGET_COCOA)
1016 // On OSX roundtripping through an FSRef fixes the case.
1018 nsCOMPtr
<nsILocalFileMac
> macFile
= do_QueryInterface(installDir
);
1019 rv
= macFile
->GetFSRef(&ref
);
1020 NS_ENSURE_SUCCESS(rv
, rv
);
1021 rv
= NS_NewLocalFileWithFSRef(&ref
, true, getter_AddRefs(macFile
));
1022 NS_ENSURE_SUCCESS(rv
, rv
);
1023 installDir
= static_cast<nsIFile
*>(macFile
);
1025 // On linux XRE_EXECUTABLE_FILE already seems to be set to the correct path.
1027 rv
= installDir
->GetPath(stringToHash
);
1028 NS_ENSURE_SUCCESS(rv
, rv
);
1031 // If we somehow failed to get an actual value, hashing an empty string could
1032 // potentially cause some serious problems given all the things this hash is
1033 // used for. So we don't allow that.
1034 if (stringToHash
.IsEmpty()) {
1035 return NS_ERROR_FAILURE
;
1038 return HashInstallPath(stringToHash
, aPathHash
);
1042 * Before bug 1555319 the directory hashed can have had an incorrect case.
1043 * Access to that hash is still available through this function. It is needed so
1044 * we can migrate users who may have an incorrect hash in profiles.ini. This
1045 * support can probably be removed in a few releases time.
1047 nsresult
nsXREDirProvider::GetLegacyInstallHash(nsAString
& aPathHash
) {
1048 nsCOMPtr
<nsIFile
> installDir
;
1049 nsCOMPtr
<nsIFile
> appFile
;
1051 nsresult rv
= GetFile(XRE_EXECUTABLE_FILE
, &per
, getter_AddRefs(appFile
));
1052 NS_ENSURE_SUCCESS(rv
, rv
);
1053 rv
= appFile
->GetParent(getter_AddRefs(installDir
));
1054 NS_ENSURE_SUCCESS(rv
, rv
);
1056 nsAutoString installPath
;
1057 rv
= installDir
->GetPath(installPath
);
1058 NS_ENSURE_SUCCESS(rv
, rv
);
1061 # if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
1062 // Convert a 64-bit install path to what would have been the 32-bit install
1063 // path to allow users to migrate their profiles from one to the other.
1064 PWSTR pathX86
= nullptr;
1066 SHGetKnownFolderPath(FOLDERID_ProgramFilesX86
, 0, nullptr, &pathX86
);
1067 if (SUCCEEDED(hres
)) {
1068 nsDependentString
strPathX86(pathX86
);
1069 if (!StringBeginsWith(installPath
, strPathX86
,
1070 nsCaseInsensitiveStringComparator
)) {
1071 PWSTR path
= nullptr;
1072 hres
= SHGetKnownFolderPath(FOLDERID_ProgramFiles
, 0, nullptr, &path
);
1073 if (SUCCEEDED(hres
)) {
1074 if (StringBeginsWith(installPath
, nsDependentString(path
),
1075 nsCaseInsensitiveStringComparator
)) {
1076 installPath
.Replace(0, wcslen(path
), strPathX86
);
1079 CoTaskMemFree(path
);
1082 CoTaskMemFree(pathX86
);
1085 return HashInstallPath(installPath
, aPathHash
);
1088 nsresult
nsXREDirProvider::GetUpdateRootDir(nsIFile
** aResult
,
1089 bool aGetOldLocation
) {
1091 // There is no old update location on platforms other than Windows. Windows is
1092 // the only platform for which we migrated the update directory.
1093 if (aGetOldLocation
) {
1094 return NS_ERROR_NOT_IMPLEMENTED
;
1097 nsCOMPtr
<nsIFile
> updRoot
;
1098 nsCOMPtr
<nsIFile
> appFile
;
1100 nsresult rv
= GetFile(XRE_EXECUTABLE_FILE
, &per
, getter_AddRefs(appFile
));
1101 NS_ENSURE_SUCCESS(rv
, rv
);
1102 rv
= appFile
->GetParent(getter_AddRefs(updRoot
));
1103 NS_ENSURE_SUCCESS(rv
, rv
);
1106 nsCOMPtr
<nsIFile
> appRootDirFile
;
1107 nsCOMPtr
<nsIFile
> localDir
;
1108 nsAutoString appDirPath
;
1109 if (NS_FAILED(appFile
->GetParent(getter_AddRefs(appRootDirFile
))) ||
1110 NS_FAILED(appRootDirFile
->GetPath(appDirPath
)) ||
1111 NS_FAILED(GetUserDataDirectoryHome(getter_AddRefs(localDir
), true))) {
1112 return NS_ERROR_FAILURE
;
1115 int32_t dotIndex
= appDirPath
.RFind(u
".app");
1116 if (dotIndex
== kNotFound
) {
1117 dotIndex
= appDirPath
.Length();
1119 appDirPath
= Substring(appDirPath
, 1, dotIndex
- 1);
1121 bool hasVendor
= GetAppVendor() && strlen(GetAppVendor()) != 0;
1122 if (hasVendor
|| GetAppName()) {
1123 if (NS_FAILED(localDir
->AppendNative(
1124 nsDependentCString(hasVendor
? GetAppVendor() : GetAppName())))) {
1125 return NS_ERROR_FAILURE
;
1127 } else if (NS_FAILED(localDir
->AppendNative("Mozilla"_ns
))) {
1128 return NS_ERROR_FAILURE
;
1131 if (NS_FAILED(localDir
->Append(u
"updates"_ns
)) ||
1132 NS_FAILED(localDir
->AppendRelativePath(appDirPath
))) {
1133 return NS_ERROR_FAILURE
;
1136 localDir
.forget(aResult
);
1140 nsAutoString installPath
;
1141 rv
= updRoot
->GetPath(installPath
);
1142 NS_ENSURE_SUCCESS(rv
, rv
);
1144 mozilla::UniquePtr
<wchar_t[]> updatePath
;
1146 if (aGetOldLocation
) {
1148 GetOldUpdateDirectory(PromiseFlatString(installPath
).get(), updatePath
);
1150 hrv
= GetCommonUpdateDirectory(PromiseFlatString(installPath
).get(),
1154 return NS_ERROR_FAILURE
;
1156 nsAutoString updatePathStr
;
1157 updatePathStr
.Assign(updatePath
.get());
1158 updRoot
->InitWithPath(updatePathStr
);
1159 updRoot
.forget(aResult
);
1162 updRoot
.forget(aResult
);
1167 nsresult
nsXREDirProvider::GetProfileStartupDir(nsIFile
** aResult
) {
1169 return mProfileDir
->Clone(aResult
);
1172 // Profile directories are only set up in the parent process.
1173 // We don't expect every caller to check if they are in the right process,
1174 // so fail immediately to avoid warning spam.
1175 NS_WARNING_ASSERTION(!XRE_IsParentProcess(),
1176 "tried to get profile in parent too early");
1177 return NS_ERROR_FAILURE
;
1180 nsresult
nsXREDirProvider::GetProfileDir(nsIFile
** aResult
) {
1182 nsresult rv
= NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
,
1183 getter_AddRefs(mProfileDir
));
1184 // Guard against potential buggy directory providers that fail while also
1185 // returning something.
1186 if (NS_FAILED(rv
)) {
1187 MOZ_ASSERT(!mProfileDir
,
1188 "Directory provider failed but returned a value");
1189 mProfileDir
= nullptr;
1192 // If we failed to get mProfileDir, this will warn for us if appropriate.
1193 return GetProfileStartupDir(aResult
);
1197 nsXREDirProvider::SetUserDataDirectory(nsIFile
* aFile
, bool aLocal
) {
1199 NS_IF_RELEASE(gDataDirHomeLocal
);
1200 NS_IF_ADDREF(gDataDirHomeLocal
= aFile
);
1202 NS_IF_RELEASE(gDataDirHome
);
1203 NS_IF_ADDREF(gDataDirHome
= aFile
);
1210 nsresult
nsXREDirProvider::SetUserDataProfileDirectory(nsCOMPtr
<nsIFile
>& aFile
,
1213 gDataDirProfileLocal
= aFile
;
1215 gDataDirProfile
= aFile
;
1221 nsresult
nsXREDirProvider::GetUserDataDirectoryHome(nsIFile
** aFile
,
1223 // Copied from nsAppFileLocationProvider (more or less)
1225 nsCOMPtr
<nsIFile
> localDir
;
1227 if (aLocal
&& gDataDirHomeLocal
) {
1228 return gDataDirHomeLocal
->Clone(aFile
);
1230 if (!aLocal
&& gDataDirHome
) {
1231 return gDataDirHome
->Clone(aFile
);
1234 #if defined(XP_MACOSX)
1238 folderType
= kCachedDataFolderType
;
1240 # ifdef MOZ_THUNDERBIRD
1241 folderType
= kDomainLibraryFolderType
;
1243 folderType
= kApplicationSupportFolderType
;
1246 OSErr err
= ::FSFindFolder(kUserDomain
, folderType
, kCreateFolder
, &fsRef
);
1247 NS_ENSURE_FALSE(err
, NS_ERROR_FAILURE
);
1249 rv
= NS_NewNativeLocalFile(""_ns
, true, getter_AddRefs(localDir
));
1250 NS_ENSURE_SUCCESS(rv
, rv
);
1252 nsCOMPtr
<nsILocalFileMac
> dirFileMac
= do_QueryInterface(localDir
);
1253 NS_ENSURE_TRUE(dirFileMac
, NS_ERROR_UNEXPECTED
);
1255 rv
= dirFileMac
->InitWithFSRef(&fsRef
);
1256 NS_ENSURE_SUCCESS(rv
, rv
);
1258 localDir
= dirFileMac
;
1259 #elif defined(XP_IOS)
1260 nsAutoCString userDir
;
1261 if (GetUIKitDirectory(aLocal
, userDir
)) {
1262 rv
= NS_NewNativeLocalFile(userDir
, true, getter_AddRefs(localDir
));
1264 rv
= NS_ERROR_FAILURE
;
1266 NS_ENSURE_SUCCESS(rv
, rv
);
1267 #elif defined(XP_WIN)
1270 rv
= GetShellFolderPath(FOLDERID_LocalAppData
, path
);
1271 if (NS_FAILED(rv
)) rv
= GetRegWindowsAppDataFolder(aLocal
, path
);
1273 if (!aLocal
|| NS_FAILED(rv
)) {
1274 rv
= GetShellFolderPath(FOLDERID_RoamingAppData
, path
);
1275 if (NS_FAILED(rv
)) {
1276 if (!aLocal
) rv
= GetRegWindowsAppDataFolder(aLocal
, path
);
1279 NS_ENSURE_SUCCESS(rv
, rv
);
1281 rv
= NS_NewLocalFile(path
, true, getter_AddRefs(localDir
));
1282 #elif defined(XP_UNIX)
1283 const char* homeDir
= getenv("HOME");
1284 if (!homeDir
|| !*homeDir
) return NS_ERROR_FAILURE
;
1286 # ifdef ANDROID /* We want (ProfD == ProfLD) on Android. */
1291 // If $XDG_CACHE_HOME is defined use it, otherwise use $HOME/.cache.
1292 const char* cacheHome
= getenv("XDG_CACHE_HOME");
1293 if (cacheHome
&& *cacheHome
) {
1294 rv
= NS_NewNativeLocalFile(nsDependentCString(cacheHome
), true,
1295 getter_AddRefs(localDir
));
1297 rv
= NS_NewNativeLocalFile(nsDependentCString(homeDir
), true,
1298 getter_AddRefs(localDir
));
1299 if (NS_SUCCEEDED(rv
)) rv
= localDir
->AppendNative(".cache"_ns
);
1302 rv
= NS_NewNativeLocalFile(nsDependentCString(homeDir
), true,
1303 getter_AddRefs(localDir
));
1306 # error "Don't know how to get product dir on your platform"
1309 NS_IF_ADDREF(*aFile
= localDir
);
1313 nsresult
nsXREDirProvider::GetSysUserExtensionsDirectory(nsIFile
** aFile
) {
1314 nsCOMPtr
<nsIFile
> localDir
;
1315 nsresult rv
= GetUserDataDirectoryHome(getter_AddRefs(localDir
), false);
1316 NS_ENSURE_SUCCESS(rv
, rv
);
1318 rv
= AppendSysUserExtensionPath(localDir
);
1319 NS_ENSURE_SUCCESS(rv
, rv
);
1321 rv
= EnsureDirectoryExists(localDir
);
1322 NS_ENSURE_SUCCESS(rv
, rv
);
1324 localDir
.forget(aFile
);
1328 #if defined(XP_UNIX) || defined(XP_MACOSX)
1329 nsresult
nsXREDirProvider::GetSystemExtensionsDirectory(nsIFile
** aFile
) {
1331 nsCOMPtr
<nsIFile
> localDir
;
1333 rv
= GetSystemParentDirectory(getter_AddRefs(localDir
));
1334 if (NS_SUCCEEDED(rv
)) {
1335 constexpr auto sExtensions
=
1336 # if defined(XP_MACOSX)
1343 rv
= localDir
->AppendNative(sExtensions
);
1344 if (NS_SUCCEEDED(rv
)) {
1345 localDir
.forget(aFile
);
1352 nsresult
nsXREDirProvider::GetUserDataDirectory(nsIFile
** aFile
, bool aLocal
) {
1353 nsCOMPtr
<nsIFile
> localDir
;
1355 if (aLocal
&& gDataDirProfileLocal
) {
1356 return gDataDirProfileLocal
->Clone(aFile
);
1358 if (!aLocal
&& gDataDirProfile
) {
1359 return gDataDirProfile
->Clone(aFile
);
1362 nsresult rv
= GetUserDataDirectoryHome(getter_AddRefs(localDir
), aLocal
);
1363 NS_ENSURE_SUCCESS(rv
, rv
);
1365 rv
= AppendProfilePath(localDir
, aLocal
);
1366 NS_ENSURE_SUCCESS(rv
, rv
);
1368 rv
= EnsureDirectoryExists(localDir
);
1369 NS_ENSURE_SUCCESS(rv
, rv
);
1371 nsXREDirProvider::SetUserDataProfileDirectory(localDir
, aLocal
);
1373 localDir
.forget(aFile
);
1377 nsresult
nsXREDirProvider::EnsureDirectoryExists(nsIFile
* aDirectory
) {
1378 nsresult rv
= aDirectory
->Create(nsIFile::DIRECTORY_TYPE
, 0700);
1380 if (rv
== NS_ERROR_FILE_ALREADY_EXISTS
) {
1386 nsresult
nsXREDirProvider::AppendSysUserExtensionPath(nsIFile
* aFile
) {
1387 NS_ASSERTION(aFile
, "Null pointer!");
1391 #if defined(XP_MACOSX) || defined(XP_WIN)
1393 static const char* const sXR
= "Mozilla";
1394 rv
= aFile
->AppendNative(nsDependentCString(sXR
));
1395 NS_ENSURE_SUCCESS(rv
, rv
);
1397 static const char* const sExtensions
= "Extensions";
1398 rv
= aFile
->AppendNative(nsDependentCString(sExtensions
));
1399 NS_ENSURE_SUCCESS(rv
, rv
);
1401 #elif defined(XP_UNIX)
1403 static const char* const sXR
= ".mozilla";
1404 rv
= aFile
->AppendNative(nsDependentCString(sXR
));
1405 NS_ENSURE_SUCCESS(rv
, rv
);
1407 static const char* const sExtensions
= "extensions";
1408 rv
= aFile
->AppendNative(nsDependentCString(sExtensions
));
1409 NS_ENSURE_SUCCESS(rv
, rv
);
1412 # error "Don't know how to get XRE user extension path on your platform"
1417 nsresult
nsXREDirProvider::AppendProfilePath(nsIFile
* aFile
, bool aLocal
) {
1418 NS_ASSERTION(aFile
, "Null pointer!");
1420 // If there is no XREAppData then there is no information to use to build
1421 // the profile path so just do nothing. This should only happen in xpcshell
1427 nsAutoCString profile
;
1428 nsAutoCString appName
;
1429 nsAutoCString vendor
;
1430 if (gAppData
->profile
) {
1431 profile
= gAppData
->profile
;
1433 appName
= gAppData
->name
;
1434 vendor
= gAppData
->vendor
;
1437 nsresult rv
= NS_OK
;
1439 #if defined(XP_MACOSX)
1440 if (!profile
.IsEmpty()) {
1441 rv
= AppendProfileString(aFile
, profile
.get());
1443 // Note that MacOS ignores the vendor when creating the profile hierarchy -
1444 // all application preferences directories live alongside one another in
1445 // ~/Library/Application Support/
1446 rv
= aFile
->AppendNative(appName
);
1448 NS_ENSURE_SUCCESS(rv
, rv
);
1450 #elif defined(XP_WIN)
1451 if (!profile
.IsEmpty()) {
1452 rv
= AppendProfileString(aFile
, profile
.get());
1454 if (!vendor
.IsEmpty()) {
1455 rv
= aFile
->AppendNative(vendor
);
1456 NS_ENSURE_SUCCESS(rv
, rv
);
1458 rv
= aFile
->AppendNative(appName
);
1460 NS_ENSURE_SUCCESS(rv
, rv
);
1462 #elif defined(ANDROID)
1463 // The directory used for storing profiles
1464 // The parent of this directory is set in GetUserDataDirectoryHome
1465 // XXX: handle gAppData->profile properly
1466 // XXXsmaug ...and the rest of the profile creation!
1467 rv
= aFile
->AppendNative(nsDependentCString("mozilla"));
1468 NS_ENSURE_SUCCESS(rv
, rv
);
1469 #elif defined(XP_UNIX)
1470 nsAutoCString folder
;
1471 // Make it hidden (by starting with "."), except when local (the
1472 // profile is already under ~/.cache or XDG_CACHE_HOME).
1473 if (!aLocal
) folder
.Assign('.');
1475 if (!profile
.IsEmpty()) {
1476 // Skip any leading path characters
1477 const char* profileStart
= profile
.get();
1478 while (*profileStart
== '/' || *profileStart
== '\\') profileStart
++;
1480 // On the off chance that someone wanted their folder to be hidden don't
1481 // let it become ".."
1482 if (*profileStart
== '.' && !aLocal
) profileStart
++;
1484 folder
.Append(profileStart
);
1485 ToLowerCase(folder
);
1487 rv
= AppendProfileString(aFile
, folder
.BeginReading());
1489 if (!vendor
.IsEmpty()) {
1490 folder
.Append(vendor
);
1491 ToLowerCase(folder
);
1493 rv
= aFile
->AppendNative(folder
);
1494 NS_ENSURE_SUCCESS(rv
, rv
);
1499 // This can be the case in tests.
1500 if (!appName
.IsEmpty()) {
1501 folder
.Append(appName
);
1502 ToLowerCase(folder
);
1504 rv
= aFile
->AppendNative(folder
);
1507 NS_ENSURE_SUCCESS(rv
, rv
);
1510 # error "Don't know how to get profile path on your platform"
1515 nsresult
nsXREDirProvider::AppendProfileString(nsIFile
* aFile
,
1516 const char* aPath
) {
1517 NS_ASSERTION(aFile
, "Null file!");
1518 NS_ASSERTION(aPath
, "Null path!");
1520 nsAutoCString
pathDup(aPath
);
1522 char* path
= pathDup
.BeginWriting();
1526 while ((subdir
= NS_strtok("/\\", &path
))) {
1527 rv
= aFile
->AppendNative(nsDependentCString(subdir
));
1528 NS_ENSURE_SUCCESS(rv
, rv
);