Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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 "nsToolkitCompsCID.h"
8 #include "nsXREDirProvider.h"
10 #include "jsapi.h"
12 #include "nsIJSRuntimeService.h"
13 #include "nsIAppStartup.h"
14 #include "nsIDirectoryEnumerator.h"
15 #include "nsIFile.h"
16 #include "nsIObserver.h"
17 #include "nsIObserverService.h"
18 #include "nsISimpleEnumerator.h"
19 #include "nsIToolkitChromeRegistry.h"
21 #include "nsAppDirectoryServiceDefs.h"
22 #include "nsDirectoryServiceDefs.h"
23 #include "nsDirectoryServiceUtils.h"
24 #include "nsXULAppAPI.h"
25 #include "nsCategoryManagerUtils.h"
27 #include "nsINIParser.h"
28 #include "nsDependentString.h"
29 #include "nsCOMArray.h"
30 #include "nsArrayEnumerator.h"
31 #include "nsEnumeratorUtils.h"
32 #include "nsReadableUtils.h"
33 #include "nsXPCOMPrivate.h" // for XPCOM_FILE_PATH_SEPARATOR
34 #include "mozilla/Services.h"
35 #include "mozilla/Omnijar.h"
36 #include "mozilla/Preferences.h"
37 #include "mozilla/Telemetry.h"
39 #include <stdlib.h>
41 #ifdef XP_WIN
42 #include <windows.h>
43 #include <shlobj.h>
44 #endif
45 #ifdef XP_MACOSX
46 #include "nsILocalFileMac.h"
47 // for chflags()
48 #include <sys/stat.h>
49 #include <unistd.h>
50 #endif
51 #ifdef XP_UNIX
52 #include <ctype.h>
53 #endif
55 #if defined(XP_MACOSX)
56 #define APP_REGISTRY_NAME "Application Registry"
57 #elif defined(XP_WIN)
58 #define APP_REGISTRY_NAME "registry.dat"
59 #else
60 #define APP_REGISTRY_NAME "appreg"
61 #endif
63 #define PREF_OVERRIDE_DIRNAME "preferences"
65 static already_AddRefed<nsIFile>
66 CloneAndAppend(nsIFile* aFile, const char* name)
67 {
68 nsCOMPtr<nsIFile> file;
69 aFile->Clone(getter_AddRefs(file));
70 file->AppendNative(nsDependentCString(name));
71 return file.forget();
72 }
74 nsXREDirProvider* gDirServiceProvider = nullptr;
76 nsXREDirProvider::nsXREDirProvider() :
77 mProfileNotified(false)
78 {
79 gDirServiceProvider = this;
80 }
82 nsXREDirProvider::~nsXREDirProvider()
83 {
84 gDirServiceProvider = nullptr;
85 }
87 nsXREDirProvider*
88 nsXREDirProvider::GetSingleton()
89 {
90 return gDirServiceProvider;
91 }
93 nsresult
94 nsXREDirProvider::Initialize(nsIFile *aXULAppDir,
95 nsIFile *aGREDir,
96 nsIDirectoryServiceProvider* aAppProvider)
97 {
98 NS_ENSURE_ARG(aXULAppDir);
99 NS_ENSURE_ARG(aGREDir);
101 mAppProvider = aAppProvider;
102 mXULAppDir = aXULAppDir;
103 mGREDir = aGREDir;
105 if (!mProfileDir) {
106 nsCOMPtr<nsIDirectoryServiceProvider> app(do_QueryInterface(mAppProvider));
107 if (app) {
108 bool per = false;
109 app->GetFile(NS_APP_USER_PROFILE_50_DIR, &per, getter_AddRefs(mProfileDir));
110 NS_ASSERTION(per, "NS_APP_USER_PROFILE_50_DIR must be persistent!");
111 NS_ASSERTION(mProfileDir, "NS_APP_USER_PROFILE_50_DIR not defined! This shouldn't happen!");
112 }
113 }
115 LoadAppBundleDirs();
116 return NS_OK;
117 }
119 nsresult
120 nsXREDirProvider::SetProfile(nsIFile* aDir, nsIFile* aLocalDir)
121 {
122 NS_ASSERTION(aDir && aLocalDir, "We don't support no-profile apps yet!");
124 nsresult rv;
126 rv = EnsureDirectoryExists(aDir);
127 if (NS_FAILED(rv))
128 return rv;
130 rv = EnsureDirectoryExists(aLocalDir);
131 if (NS_FAILED(rv))
132 return rv;
134 #ifdef XP_MACOSX
135 bool same;
136 if (NS_SUCCEEDED(aDir->Equals(aLocalDir, &same)) && !same) {
137 // Ensure that the cache directory is not indexed by Spotlight
138 // (bug 718910). At least on OS X, the cache directory (under
139 // ~/Library/Caches/) is always the "local" user profile
140 // directory. This is confusing, since *both* user profile
141 // directories are "local" (they both exist under the user's
142 // home directory). But this usage dates back at least as far
143 // as the patch for bug 291033, where "local" seems to mean
144 // "suitable for temporary storage". Don't hide the cache
145 // directory if by some chance it and the "non-local" profile
146 // directory are the same -- there are bad side effects from
147 // hiding a profile directory under /Library/Application Support/
148 // (see bug 801883).
149 nsAutoCString cacheDir;
150 if (NS_SUCCEEDED(aLocalDir->GetNativePath(cacheDir))) {
151 if (chflags(cacheDir.get(), UF_HIDDEN)) {
152 NS_WARNING("Failed to set Cache directory to HIDDEN.");
153 }
154 }
155 }
156 #endif
158 mProfileDir = aDir;
159 mProfileLocalDir = aLocalDir;
160 return NS_OK;
161 }
163 NS_IMPL_QUERY_INTERFACE(nsXREDirProvider,
164 nsIDirectoryServiceProvider,
165 nsIDirectoryServiceProvider2,
166 nsIProfileStartup)
168 NS_IMETHODIMP_(MozExternalRefCountType)
169 nsXREDirProvider::AddRef()
170 {
171 return 1;
172 }
174 NS_IMETHODIMP_(MozExternalRefCountType)
175 nsXREDirProvider::Release()
176 {
177 return 0;
178 }
180 nsresult
181 nsXREDirProvider::GetUserProfilesRootDir(nsIFile** aResult,
182 const nsACString* aProfileName,
183 const nsACString* aAppName,
184 const nsACString* aVendorName)
185 {
186 nsCOMPtr<nsIFile> file;
187 nsresult rv = GetUserDataDirectory(getter_AddRefs(file),
188 false,
189 aProfileName, aAppName, aVendorName);
191 if (NS_SUCCEEDED(rv)) {
192 // We must create the profile directory here if it does not exist.
193 nsresult tmp = EnsureDirectoryExists(file);
194 if (NS_FAILED(tmp)) {
195 rv = tmp;
196 }
197 }
198 file.swap(*aResult);
199 return rv;
200 }
202 nsresult
203 nsXREDirProvider::GetUserProfilesLocalDir(nsIFile** aResult,
204 const nsACString* aProfileName,
205 const nsACString* aAppName,
206 const nsACString* aVendorName)
207 {
208 nsCOMPtr<nsIFile> file;
209 nsresult rv = GetUserDataDirectory(getter_AddRefs(file),
210 true,
211 aProfileName, aAppName, aVendorName);
213 if (NS_SUCCEEDED(rv)) {
214 // We must create the profile directory here if it does not exist.
215 nsresult tmp = EnsureDirectoryExists(file);
216 if (NS_FAILED(tmp)) {
217 rv = tmp;
218 }
219 }
220 file.swap(*aResult);
221 return NS_OK;
222 }
224 NS_IMETHODIMP
225 nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
226 nsIFile** aFile)
227 {
228 nsresult rv;
230 bool gettingProfile = false;
232 if (!strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR)) {
233 // If XRE_NotifyProfile hasn't been called, don't fall through to
234 // mAppProvider on the profile keys.
235 if (!mProfileNotified)
236 return NS_ERROR_FAILURE;
238 if (mProfileLocalDir)
239 return mProfileLocalDir->Clone(aFile);
241 if (mAppProvider)
242 return mAppProvider->GetFile(aProperty, aPersistent, aFile);
244 // This falls through to the case below
245 gettingProfile = true;
246 }
247 if (!strcmp(aProperty, NS_APP_USER_PROFILE_50_DIR) || gettingProfile) {
248 if (!mProfileNotified)
249 return NS_ERROR_FAILURE;
251 if (mProfileDir)
252 return mProfileDir->Clone(aFile);
254 if (mAppProvider)
255 return mAppProvider->GetFile(aProperty, aPersistent, aFile);
257 // If we don't succeed here, bail early so that we aren't reentrant
258 // through the "GetProfileDir" call below.
259 return NS_ERROR_FAILURE;
260 }
262 if (mAppProvider) {
263 rv = mAppProvider->GetFile(aProperty, aPersistent, aFile);
264 if (NS_SUCCEEDED(rv) && *aFile)
265 return rv;
266 }
268 *aPersistent = true;
270 if (!strcmp(aProperty, NS_GRE_DIR)) {
271 return mGREDir->Clone(aFile);
272 }
273 else if (!strcmp(aProperty, NS_OS_CURRENT_PROCESS_DIR) ||
274 !strcmp(aProperty, NS_APP_INSTALL_CLEANUP_DIR)) {
275 return GetAppDir()->Clone(aFile);
276 }
278 rv = NS_ERROR_FAILURE;
279 nsCOMPtr<nsIFile> file;
281 if (!strcmp(aProperty, NS_APP_PROFILE_DEFAULTS_50_DIR) ||
282 !strcmp(aProperty, NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR)) {
283 return GetProfileDefaultsDir(aFile);
284 }
285 else if (!strcmp(aProperty, NS_APP_PREF_DEFAULTS_50_DIR))
286 {
287 // return the GRE default prefs directory here, and the app default prefs
288 // directory (if applicable) in NS_APP_PREFS_DEFAULTS_DIR_LIST.
289 rv = mGREDir->Clone(getter_AddRefs(file));
290 if (NS_SUCCEEDED(rv)) {
291 rv = file->AppendNative(NS_LITERAL_CSTRING("defaults"));
292 if (NS_SUCCEEDED(rv))
293 rv = file->AppendNative(NS_LITERAL_CSTRING("pref"));
294 }
295 }
296 else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_DIR) ||
297 !strcmp(aProperty, XRE_USER_APP_DATA_DIR)) {
298 rv = GetUserAppDataDirectory(getter_AddRefs(file));
299 }
300 else if (!strcmp(aProperty, XRE_UPDATE_ROOT_DIR)) {
301 rv = GetUpdateRootDir(getter_AddRefs(file));
302 }
303 else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_FILE)) {
304 rv = GetUserAppDataDirectory(getter_AddRefs(file));
305 if (NS_SUCCEEDED(rv))
306 rv = file->AppendNative(NS_LITERAL_CSTRING(APP_REGISTRY_NAME));
307 }
308 else if (!strcmp(aProperty, NS_APP_USER_PROFILES_ROOT_DIR)) {
309 rv = GetUserProfilesRootDir(getter_AddRefs(file), nullptr, nullptr, nullptr);
310 }
311 else if (!strcmp(aProperty, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR)) {
312 rv = GetUserProfilesLocalDir(getter_AddRefs(file), nullptr, nullptr, nullptr);
313 }
314 else if (!strcmp(aProperty, XRE_EXECUTABLE_FILE) && gArgv[0]) {
315 nsCOMPtr<nsIFile> lf;
316 rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
317 if (NS_SUCCEEDED(rv))
318 file = lf;
319 }
321 else if (!strcmp(aProperty, NS_APP_PROFILE_DIR_STARTUP) && mProfileDir) {
322 return mProfileDir->Clone(aFile);
323 }
324 else if (!strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP)) {
325 if (mProfileLocalDir)
326 return mProfileLocalDir->Clone(aFile);
328 if (mProfileDir)
329 return mProfileDir->Clone(aFile);
331 if (mAppProvider)
332 return mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP, aPersistent,
333 aFile);
334 }
335 #if defined(XP_UNIX) || defined(XP_MACOSX)
336 else if (!strcmp(aProperty, XRE_SYS_LOCAL_EXTENSION_PARENT_DIR)) {
337 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
338 return GetSystemExtensionsDirectory(aFile);
339 #else
340 return NS_ERROR_FAILURE;
341 #endif
342 }
343 #endif
344 #if defined(XP_UNIX) && !defined(XP_MACOSX)
345 else if (!strcmp(aProperty, XRE_SYS_SHARE_EXTENSION_PARENT_DIR)) {
346 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
347 #if defined(__OpenBSD__) || defined(__FreeBSD__)
348 static const char *const sysLExtDir = "/usr/local/share/mozilla/extensions";
349 #else
350 static const char *const sysLExtDir = "/usr/share/mozilla/extensions";
351 #endif
352 return NS_NewNativeLocalFile(nsDependentCString(sysLExtDir),
353 false, aFile);
354 #else
355 return NS_ERROR_FAILURE;
356 #endif
357 }
358 #endif
359 else if (!strcmp(aProperty, XRE_USER_SYS_EXTENSION_DIR)) {
360 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
361 return GetSysUserExtensionsDirectory(aFile);
362 #else
363 return NS_ERROR_FAILURE;
364 #endif
365 }
366 else if (!strcmp(aProperty, XRE_APP_DISTRIBUTION_DIR)) {
367 bool persistent = false;
368 rv = GetFile(XRE_EXECUTABLE_FILE, &persistent, getter_AddRefs(file));
369 if (NS_SUCCEEDED(rv))
370 rv = file->SetNativeLeafName(NS_LITERAL_CSTRING("distribution"));
371 }
372 else if (NS_SUCCEEDED(GetProfileStartupDir(getter_AddRefs(file)))) {
373 // We need to allow component, xpt, and chrome registration to
374 // occur prior to the profile-after-change notification.
375 if (!strcmp(aProperty, NS_APP_USER_CHROME_DIR)) {
376 rv = file->AppendNative(NS_LITERAL_CSTRING("chrome"));
377 }
378 }
380 if (NS_SUCCEEDED(rv) && file) {
381 NS_ADDREF(*aFile = file);
382 return NS_OK;
383 }
385 bool ensureFilePermissions = false;
387 if (NS_SUCCEEDED(GetProfileDir(getter_AddRefs(file)))) {
388 if (!strcmp(aProperty, NS_APP_PREFS_50_DIR)) {
389 rv = NS_OK;
390 }
391 else if (!strcmp(aProperty, NS_APP_PREFS_50_FILE)) {
392 rv = file->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
393 }
394 else if (!strcmp(aProperty, NS_METRO_APP_PREFS_50_FILE)) {
395 rv = file->AppendNative(NS_LITERAL_CSTRING("metro-prefs.js"));
396 }
397 else if (!strcmp(aProperty, NS_LOCALSTORE_UNSAFE_FILE)) {
398 rv = file->AppendNative(NS_LITERAL_CSTRING("localstore.rdf"));
399 }
400 else if (!strcmp(aProperty, NS_APP_LOCALSTORE_50_FILE)) {
401 if (gSafeMode) {
402 rv = file->AppendNative(NS_LITERAL_CSTRING("localstore-safe.rdf"));
403 file->Remove(false);
404 }
405 else {
406 rv = file->AppendNative(NS_LITERAL_CSTRING("localstore.rdf"));
407 EnsureProfileFileExists(file);
408 ensureFilePermissions = true;
409 }
410 }
411 else if (!strcmp(aProperty, NS_APP_USER_MIMETYPES_50_FILE)) {
412 rv = file->AppendNative(NS_LITERAL_CSTRING("mimeTypes.rdf"));
413 EnsureProfileFileExists(file);
414 ensureFilePermissions = true;
415 }
416 else if (!strcmp(aProperty, NS_APP_DOWNLOADS_50_FILE)) {
417 rv = file->AppendNative(NS_LITERAL_CSTRING("downloads.rdf"));
418 }
419 else if (!strcmp(aProperty, NS_APP_PREFS_OVERRIDE_DIR)) {
420 rv = mProfileDir->Clone(getter_AddRefs(file));
421 nsresult tmp = file->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
422 if (NS_FAILED(tmp)) {
423 rv = tmp;
424 }
425 tmp = EnsureDirectoryExists(file);
426 if (NS_FAILED(tmp)) {
427 rv = tmp;
428 }
429 }
430 }
431 if (NS_FAILED(rv) || !file)
432 return NS_ERROR_FAILURE;
434 if (ensureFilePermissions) {
435 bool fileToEnsureExists;
436 bool isWritable;
437 if (NS_SUCCEEDED(file->Exists(&fileToEnsureExists)) && fileToEnsureExists
438 && NS_SUCCEEDED(file->IsWritable(&isWritable)) && !isWritable) {
439 uint32_t permissions;
440 if (NS_SUCCEEDED(file->GetPermissions(&permissions))) {
441 rv = file->SetPermissions(permissions | 0600);
442 NS_ASSERTION(NS_SUCCEEDED(rv), "failed to ensure file permissions");
443 }
444 }
445 }
447 NS_ADDREF(*aFile = file);
448 return NS_OK;
449 }
451 static void
452 LoadDirIntoArray(nsIFile* dir,
453 const char *const *aAppendList,
454 nsCOMArray<nsIFile>& aDirectories)
455 {
456 if (!dir)
457 return;
459 nsCOMPtr<nsIFile> subdir;
460 dir->Clone(getter_AddRefs(subdir));
461 if (!subdir)
462 return;
464 for (const char *const *a = aAppendList; *a; ++a) {
465 subdir->AppendNative(nsDependentCString(*a));
466 }
468 bool exists;
469 if (NS_SUCCEEDED(subdir->Exists(&exists)) && exists) {
470 aDirectories.AppendObject(subdir);
471 }
472 }
474 static void
475 LoadDirsIntoArray(nsCOMArray<nsIFile>& aSourceDirs,
476 const char *const* aAppendList,
477 nsCOMArray<nsIFile>& aDirectories)
478 {
479 nsCOMPtr<nsIFile> appended;
480 bool exists;
482 for (int32_t i = 0; i < aSourceDirs.Count(); ++i) {
483 aSourceDirs[i]->Clone(getter_AddRefs(appended));
484 if (!appended)
485 continue;
487 nsAutoCString leaf;
488 appended->GetNativeLeafName(leaf);
489 if (!Substring(leaf, leaf.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi"))) {
490 LoadDirIntoArray(appended,
491 aAppendList,
492 aDirectories);
493 }
494 else if (NS_SUCCEEDED(appended->Exists(&exists)) && exists)
495 aDirectories.AppendObject(appended);
496 }
497 }
499 NS_IMETHODIMP
500 nsXREDirProvider::GetFiles(const char* aProperty, nsISimpleEnumerator** aResult)
501 {
502 nsresult rv;
504 nsCOMPtr<nsISimpleEnumerator> appEnum;
505 nsCOMPtr<nsIDirectoryServiceProvider2>
506 appP2(do_QueryInterface(mAppProvider));
507 if (appP2) {
508 rv = appP2->GetFiles(aProperty, getter_AddRefs(appEnum));
509 if (NS_FAILED(rv)) {
510 appEnum = nullptr;
511 }
512 else if (rv != NS_SUCCESS_AGGREGATE_RESULT) {
513 NS_ADDREF(*aResult = appEnum);
514 return NS_OK;
515 }
516 }
518 nsCOMPtr<nsISimpleEnumerator> xreEnum;
519 rv = GetFilesInternal(aProperty, getter_AddRefs(xreEnum));
520 if (NS_FAILED(rv)) {
521 if (appEnum) {
522 NS_ADDREF(*aResult = appEnum);
523 return NS_SUCCESS_AGGREGATE_RESULT;
524 }
526 return rv;
527 }
529 rv = NS_NewUnionEnumerator(aResult, appEnum, xreEnum);
530 if (NS_FAILED(rv))
531 return rv;
533 return NS_SUCCESS_AGGREGATE_RESULT;
534 }
536 static void
537 LoadExtensionDirectories(nsINIParser &parser,
538 const char *aSection,
539 nsCOMArray<nsIFile> &aDirectories,
540 NSLocationType aType)
541 {
542 nsresult rv;
543 int32_t i = 0;
544 do {
545 nsAutoCString buf("Extension");
546 buf.AppendInt(i++);
548 nsAutoCString path;
549 rv = parser.GetString(aSection, buf.get(), path);
550 if (NS_FAILED(rv))
551 return;
553 nsCOMPtr<nsIFile> dir = do_CreateInstance("@mozilla.org/file/local;1", &rv);
554 if (NS_FAILED(rv))
555 continue;
557 rv = dir->SetPersistentDescriptor(path);
558 if (NS_FAILED(rv))
559 continue;
561 aDirectories.AppendObject(dir);
562 if (Substring(path, path.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi"))) {
563 XRE_AddJarManifestLocation(aType, dir);
564 }
565 else {
566 nsCOMPtr<nsIFile> manifest =
567 CloneAndAppend(dir, "chrome.manifest");
568 XRE_AddManifestLocation(aType, manifest);
569 }
570 }
571 while (true);
572 }
574 void
575 nsXREDirProvider::LoadExtensionBundleDirectories()
576 {
577 if (!mozilla::Preferences::GetBool("extensions.defaultProviders.enabled", true))
578 return;
580 if (mProfileDir && !gSafeMode) {
581 nsCOMPtr<nsIFile> extensionsINI;
582 mProfileDir->Clone(getter_AddRefs(extensionsINI));
583 if (!extensionsINI)
584 return;
586 extensionsINI->AppendNative(NS_LITERAL_CSTRING("extensions.ini"));
588 nsCOMPtr<nsIFile> extensionsINILF =
589 do_QueryInterface(extensionsINI);
590 if (!extensionsINILF)
591 return;
593 nsINIParser parser;
594 nsresult rv = parser.Init(extensionsINILF);
595 if (NS_FAILED(rv))
596 return;
598 LoadExtensionDirectories(parser, "ExtensionDirs", mExtensionDirectories,
599 NS_COMPONENT_LOCATION);
600 LoadExtensionDirectories(parser, "ThemeDirs", mThemeDirectories,
601 NS_SKIN_LOCATION);
602 }
603 }
605 void
606 nsXREDirProvider::LoadAppBundleDirs()
607 {
608 nsCOMPtr<nsIFile> dir;
609 bool persistent = false;
610 nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &persistent, getter_AddRefs(dir));
611 if (NS_FAILED(rv))
612 return;
614 dir->SetNativeLeafName(NS_LITERAL_CSTRING("distribution"));
615 dir->AppendNative(NS_LITERAL_CSTRING("bundles"));
617 nsCOMPtr<nsISimpleEnumerator> e;
618 rv = dir->GetDirectoryEntries(getter_AddRefs(e));
619 if (NS_FAILED(rv))
620 return;
622 nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e);
623 if (!files)
624 return;
626 nsCOMPtr<nsIFile> subdir;
627 while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(subdir))) && subdir) {
628 mAppBundleDirectories.AppendObject(subdir);
630 nsCOMPtr<nsIFile> manifest =
631 CloneAndAppend(subdir, "chrome.manifest");
632 XRE_AddManifestLocation(NS_COMPONENT_LOCATION, manifest);
633 }
634 }
636 static const char *const kAppendPrefDir[] = { "defaults", "preferences", nullptr };
638 #ifdef DEBUG_bsmedberg
639 static void
640 DumpFileArray(const char *key,
641 nsCOMArray<nsIFile> dirs)
642 {
643 fprintf(stderr, "nsXREDirProvider::GetFilesInternal(%s)\n", key);
645 nsAutoCString path;
646 for (int32_t i = 0; i < dirs.Count(); ++i) {
647 dirs[i]->GetNativePath(path);
648 fprintf(stderr, " %s\n", path.get());
649 }
650 }
651 #endif // DEBUG_bsmedberg
653 nsresult
654 nsXREDirProvider::GetFilesInternal(const char* aProperty,
655 nsISimpleEnumerator** aResult)
656 {
657 nsresult rv = NS_OK;
658 *aResult = nullptr;
660 if (!strcmp(aProperty, XRE_EXTENSIONS_DIR_LIST)) {
661 nsCOMArray<nsIFile> directories;
663 static const char *const kAppendNothing[] = { nullptr };
665 LoadDirsIntoArray(mAppBundleDirectories,
666 kAppendNothing, directories);
667 LoadDirsIntoArray(mExtensionDirectories,
668 kAppendNothing, directories);
670 rv = NS_NewArrayEnumerator(aResult, directories);
671 }
672 else if (!strcmp(aProperty, NS_APP_PREFS_DEFAULTS_DIR_LIST)) {
673 nsCOMArray<nsIFile> directories;
675 LoadDirIntoArray(mXULAppDir, kAppendPrefDir, directories);
676 LoadDirsIntoArray(mAppBundleDirectories,
677 kAppendPrefDir, directories);
679 rv = NS_NewArrayEnumerator(aResult, directories);
680 }
681 else if (!strcmp(aProperty, NS_EXT_PREFS_DEFAULTS_DIR_LIST)) {
682 nsCOMArray<nsIFile> directories;
684 LoadDirsIntoArray(mExtensionDirectories,
685 kAppendPrefDir, directories);
687 if (mProfileDir) {
688 nsCOMPtr<nsIFile> overrideFile;
689 mProfileDir->Clone(getter_AddRefs(overrideFile));
690 overrideFile->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
692 bool exists;
693 if (NS_SUCCEEDED(overrideFile->Exists(&exists)) && exists)
694 directories.AppendObject(overrideFile);
695 }
697 rv = NS_NewArrayEnumerator(aResult, directories);
698 }
699 else if (!strcmp(aProperty, NS_APP_CHROME_DIR_LIST)) {
700 // NS_APP_CHROME_DIR_LIST is only used to get default (native) icons
701 // for OS window decoration.
703 static const char *const kAppendChromeDir[] = { "chrome", nullptr };
704 nsCOMArray<nsIFile> directories;
705 LoadDirIntoArray(mXULAppDir,
706 kAppendChromeDir,
707 directories);
708 LoadDirsIntoArray(mAppBundleDirectories,
709 kAppendChromeDir,
710 directories);
711 LoadDirsIntoArray(mExtensionDirectories,
712 kAppendChromeDir,
713 directories);
715 rv = NS_NewArrayEnumerator(aResult, directories);
716 }
717 else if (!strcmp(aProperty, NS_APP_PLUGINS_DIR_LIST)) {
718 nsCOMArray<nsIFile> directories;
720 if (mozilla::Preferences::GetBool("plugins.load_appdir_plugins", false)) {
721 nsCOMPtr<nsIFile> appdir;
722 rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(appdir));
723 if (NS_SUCCEEDED(rv)) {
724 appdir->SetNativeLeafName(NS_LITERAL_CSTRING("plugins"));
725 directories.AppendObject(appdir);
726 }
727 }
729 static const char *const kAppendPlugins[] = { "plugins", nullptr };
731 // The root dirserviceprovider does quite a bit for us: we're mainly
732 // interested in xulapp and extension-provided plugins.
733 LoadDirsIntoArray(mAppBundleDirectories,
734 kAppendPlugins,
735 directories);
736 LoadDirsIntoArray(mExtensionDirectories,
737 kAppendPlugins,
738 directories);
740 if (mProfileDir) {
741 nsCOMArray<nsIFile> profileDir;
742 profileDir.AppendObject(mProfileDir);
743 LoadDirsIntoArray(profileDir,
744 kAppendPlugins,
745 directories);
746 }
748 rv = NS_NewArrayEnumerator(aResult, directories);
749 NS_ENSURE_SUCCESS(rv, rv);
751 rv = NS_SUCCESS_AGGREGATE_RESULT;
752 }
753 else
754 rv = NS_ERROR_FAILURE;
756 return rv;
757 }
759 NS_IMETHODIMP
760 nsXREDirProvider::GetDirectory(nsIFile* *aResult)
761 {
762 NS_ENSURE_TRUE(mProfileDir, NS_ERROR_NOT_INITIALIZED);
764 return mProfileDir->Clone(aResult);
765 }
767 NS_IMETHODIMP
768 nsXREDirProvider::DoStartup()
769 {
770 if (!mProfileNotified) {
771 nsCOMPtr<nsIObserverService> obsSvc =
772 mozilla::services::GetObserverService();
773 if (!obsSvc) return NS_ERROR_FAILURE;
775 mProfileNotified = true;
777 /*
778 Setup prefs before profile-do-change to be able to use them to track
779 crashes and because we want to begin crash tracking before other code run
780 from this notification since they may cause crashes.
781 */
782 nsresult rv = mozilla::Preferences::ResetAndReadUserPrefs();
783 if (NS_FAILED(rv)) NS_WARNING("Failed to setup pref service.");
785 bool safeModeNecessary = false;
786 nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
787 if (appStartup) {
788 rv = appStartup->TrackStartupCrashBegin(&safeModeNecessary);
789 if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE)
790 NS_WARNING("Error while beginning startup crash tracking");
792 if (!gSafeMode && safeModeNecessary) {
793 appStartup->RestartInSafeMode(nsIAppStartup::eForceQuit);
794 return NS_OK;
795 }
796 }
798 static const char16_t kStartup[] = {'s','t','a','r','t','u','p','\0'};
799 obsSvc->NotifyObservers(nullptr, "profile-do-change", kStartup);
800 // Init the Extension Manager
801 nsCOMPtr<nsIObserver> em = do_GetService("@mozilla.org/addons/integration;1");
802 if (em) {
803 em->Observe(nullptr, "addons-startup", nullptr);
804 } else {
805 NS_WARNING("Failed to create Addons Manager.");
806 }
808 LoadExtensionBundleDirectories();
810 obsSvc->NotifyObservers(nullptr, "load-extension-defaults", nullptr);
811 obsSvc->NotifyObservers(nullptr, "profile-after-change", kStartup);
813 // Any component that has registered for the profile-after-change category
814 // should also be created at this time.
815 (void)NS_CreateServicesFromCategory("profile-after-change", nullptr,
816 "profile-after-change");
818 if (gSafeMode && safeModeNecessary) {
819 static const char16_t kCrashed[] = {'c','r','a','s','h','e','d','\0'};
820 obsSvc->NotifyObservers(nullptr, "safemode-forced", kCrashed);
821 }
823 // 1 = Regular mode, 2 = Safe mode, 3 = Safe mode forced
824 int mode = 1;
825 if (gSafeMode) {
826 if (safeModeNecessary)
827 mode = 3;
828 else
829 mode = 2;
830 }
831 mozilla::Telemetry::Accumulate(mozilla::Telemetry::SAFE_MODE_USAGE, mode);
833 obsSvc->NotifyObservers(nullptr, "profile-initial-state", nullptr);
834 }
835 return NS_OK;
836 }
838 void
839 nsXREDirProvider::DoShutdown()
840 {
841 if (mProfileNotified) {
842 nsCOMPtr<nsIObserverService> obsSvc =
843 mozilla::services::GetObserverService();
844 NS_ASSERTION(obsSvc, "No observer service?");
845 if (obsSvc) {
846 static const char16_t kShutdownPersist[] =
847 {'s','h','u','t','d','o','w','n','-','p','e','r','s','i','s','t','\0'};
848 obsSvc->NotifyObservers(nullptr, "profile-change-net-teardown", kShutdownPersist);
849 obsSvc->NotifyObservers(nullptr, "profile-change-teardown", kShutdownPersist);
851 // Phase 2c: Now that things are torn down, force JS GC so that things which depend on
852 // resources which are about to go away in "profile-before-change" are destroyed first.
854 nsCOMPtr<nsIJSRuntimeService> rtsvc
855 (do_GetService("@mozilla.org/js/xpc/RuntimeService;1"));
856 if (rtsvc)
857 {
858 JSRuntime *rt = nullptr;
859 rtsvc->GetRuntime(&rt);
860 if (rt)
861 ::JS_GC(rt);
862 }
864 // Phase 3: Notify observers of a profile change
865 obsSvc->NotifyObservers(nullptr, "profile-before-change", kShutdownPersist);
866 obsSvc->NotifyObservers(nullptr, "profile-before-change2", kShutdownPersist);
867 }
868 mProfileNotified = false;
869 }
870 }
872 #ifdef XP_WIN
873 static nsresult
874 GetShellFolderPath(int folder, nsAString& _retval)
875 {
876 wchar_t* buf;
877 uint32_t bufLength = _retval.GetMutableData(&buf, MAXPATHLEN + 3);
878 NS_ENSURE_TRUE(bufLength >= (MAXPATHLEN + 3), NS_ERROR_OUT_OF_MEMORY);
880 nsresult rv = NS_OK;
882 LPITEMIDLIST pItemIDList = nullptr;
884 if (SUCCEEDED(SHGetSpecialFolderLocation(nullptr, folder, &pItemIDList)) &&
885 SHGetPathFromIDListW(pItemIDList, buf)) {
886 // We're going to use wcslen (wcsnlen not available in msvc7.1) so make
887 // sure to null terminate.
888 buf[bufLength - 1] = L'\0';
889 _retval.SetLength(wcslen(buf));
890 } else {
891 _retval.SetLength(0);
892 rv = NS_ERROR_NOT_AVAILABLE;
893 }
895 CoTaskMemFree(pItemIDList);
897 return rv;
898 }
900 /**
901 * Provides a fallback for getting the path to APPDATA or LOCALAPPDATA by
902 * querying the registry when the call to SHGetSpecialFolderLocation or
903 * SHGetPathFromIDListW is unable to provide these paths (Bug 513958).
904 */
905 static nsresult
906 GetRegWindowsAppDataFolder(bool aLocal, nsAString& _retval)
907 {
908 HKEY key;
909 NS_NAMED_LITERAL_STRING(keyName,
910 "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
911 DWORD res = ::RegOpenKeyExW(HKEY_CURRENT_USER, keyName.get(), 0, KEY_READ,
912 &key);
913 if (res != ERROR_SUCCESS) {
914 _retval.SetLength(0);
915 return NS_ERROR_NOT_AVAILABLE;
916 }
918 DWORD type, size;
919 res = RegQueryValueExW(key, (aLocal ? L"Local AppData" : L"AppData"),
920 nullptr, &type, nullptr, &size);
921 // The call to RegQueryValueExW must succeed, the type must be REG_SZ, the
922 // buffer size must not equal 0, and the buffer size be a multiple of 2.
923 if (res != ERROR_SUCCESS || type != REG_SZ || size == 0 || size % 2 != 0) {
924 ::RegCloseKey(key);
925 _retval.SetLength(0);
926 return NS_ERROR_NOT_AVAILABLE;
927 }
929 // |size| may or may not include room for the terminating null character
930 DWORD resultLen = size / 2;
932 _retval.SetLength(resultLen);
933 nsAString::iterator begin;
934 _retval.BeginWriting(begin);
935 if (begin.size_forward() != resultLen) {
936 ::RegCloseKey(key);
937 _retval.SetLength(0);
938 return NS_ERROR_NOT_AVAILABLE;
939 }
941 res = RegQueryValueExW(key, (aLocal ? L"Local AppData" : L"AppData"),
942 nullptr, nullptr, (LPBYTE) begin.get(), &size);
943 ::RegCloseKey(key);
944 if (res != ERROR_SUCCESS) {
945 _retval.SetLength(0);
946 return NS_ERROR_NOT_AVAILABLE;
947 }
949 if (!_retval.CharAt(resultLen - 1)) {
950 // It was already null terminated.
951 _retval.Truncate(resultLen - 1);
952 }
954 return NS_OK;
955 }
957 static bool
958 GetCachedHash(HKEY rootKey, const nsAString ®Path, const nsAString &path,
959 nsAString &cachedHash)
960 {
961 HKEY baseKey;
962 if (RegOpenKeyExW(rootKey, reinterpret_cast<const wchar_t*>(regPath.BeginReading()), 0, KEY_READ, &baseKey) !=
963 ERROR_SUCCESS) {
964 return false;
965 }
967 wchar_t cachedHashRaw[512];
968 DWORD bufferSize = sizeof(cachedHashRaw);
969 LONG result = RegQueryValueExW(baseKey, reinterpret_cast<const wchar_t*>(path.BeginReading()), 0, nullptr,
970 (LPBYTE)cachedHashRaw, &bufferSize);
971 RegCloseKey(baseKey);
972 if (result == ERROR_SUCCESS) {
973 cachedHash.Assign(cachedHashRaw);
974 }
975 return ERROR_SUCCESS == result;
976 }
978 #endif
980 nsresult
981 nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
982 {
983 nsCOMPtr<nsIFile> updRoot;
984 #if defined(MOZ_WIDGET_GONK)
986 nsresult rv = NS_NewNativeLocalFile(nsDependentCString("/data/local"),
987 true,
988 getter_AddRefs(updRoot));
989 NS_ENSURE_SUCCESS(rv, rv);
991 #else
992 nsCOMPtr<nsIFile> appFile;
993 bool per = false;
994 nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(appFile));
995 NS_ENSURE_SUCCESS(rv, rv);
996 rv = appFile->GetParent(getter_AddRefs(updRoot));
997 NS_ENSURE_SUCCESS(rv, rv);
999 #ifdef XP_WIN
1001 nsAutoString pathHash;
1002 bool pathHashResult = false;
1003 bool hasVendor = gAppData->vendor && strlen(gAppData->vendor) != 0;
1005 nsAutoString appDirPath;
1006 if (SUCCEEDED(updRoot->GetPath(appDirPath))) {
1008 // Figure out where we should check for a cached hash value. If the
1009 // application doesn't have the nsXREAppData vendor value defined check
1010 // under SOFTWARE\Mozilla.
1011 wchar_t regPath[1024] = { L'\0' };
1012 swprintf_s(regPath, mozilla::ArrayLength(regPath), L"SOFTWARE\\%S\\%S\\TaskBarIDs",
1013 (hasVendor ? gAppData->vendor : "Mozilla"), MOZ_APP_BASENAME);
1015 // If we pre-computed the hash, grab it from the registry.
1016 pathHashResult = GetCachedHash(HKEY_LOCAL_MACHINE,
1017 nsDependentString(regPath), appDirPath,
1018 pathHash);
1019 if (!pathHashResult) {
1020 pathHashResult = GetCachedHash(HKEY_CURRENT_USER,
1021 nsDependentString(regPath), appDirPath,
1022 pathHash);
1023 }
1024 }
1026 // Get the local app data directory and if a vendor name exists append it.
1027 // If only a product name exists, append it. If neither exist fallback to
1028 // old handling. We don't use the product name on purpose because we want a
1029 // shared update directory for different apps run from the same path (like
1030 // Metro & Desktop).
1031 nsCOMPtr<nsIFile> localDir;
1032 if (pathHashResult && (hasVendor || gAppData->name) &&
1033 NS_SUCCEEDED(GetUserDataDirectoryHome(getter_AddRefs(localDir), true)) &&
1034 NS_SUCCEEDED(localDir->AppendNative(nsDependentCString(hasVendor ?
1035 gAppData->vendor : gAppData->name))) &&
1036 NS_SUCCEEDED(localDir->Append(NS_LITERAL_STRING("updates"))) &&
1037 NS_SUCCEEDED(localDir->Append(pathHash))) {
1038 NS_ADDREF(*aResult = localDir);
1039 return NS_OK;
1040 }
1042 nsAutoString appPath;
1043 rv = updRoot->GetPath(appPath);
1044 NS_ENSURE_SUCCESS(rv, rv);
1046 // AppDir may be a short path. Convert to long path to make sure
1047 // the consistency of the update folder location
1048 nsString longPath;
1049 wchar_t* buf;
1051 uint32_t bufLength = longPath.GetMutableData(&buf, MAXPATHLEN);
1052 NS_ENSURE_TRUE(bufLength >= MAXPATHLEN, NS_ERROR_OUT_OF_MEMORY);
1054 DWORD len = GetLongPathNameW(appPath.get(), buf, bufLength);
1056 // Failing GetLongPathName() is not fatal.
1057 if (len <= 0 || len >= bufLength)
1058 longPath.Assign(appPath);
1059 else
1060 longPath.SetLength(len);
1062 // Use <UserLocalDataDir>\updates\<relative path to app dir from
1063 // Program Files> if app dir is under Program Files to avoid the
1064 // folder virtualization mess on Windows Vista
1065 nsAutoString programFiles;
1066 rv = GetShellFolderPath(CSIDL_PROGRAM_FILES, programFiles);
1067 NS_ENSURE_SUCCESS(rv, rv);
1069 programFiles.AppendLiteral("\\");
1070 uint32_t programFilesLen = programFiles.Length();
1072 nsAutoString programName;
1073 if (_wcsnicmp(programFiles.get(), longPath.get(), programFilesLen) == 0) {
1074 programName = Substring(longPath, programFilesLen);
1075 } else {
1076 // We need the update root directory to live outside of the installation
1077 // directory, because otherwise the updater writing the log file can cause
1078 // the directory to be locked, which prevents it from being replaced after
1079 // background updates.
1080 programName.AssignASCII(MOZ_APP_NAME);
1081 }
1083 rv = GetUserLocalDataDirectory(getter_AddRefs(updRoot));
1084 NS_ENSURE_SUCCESS(rv, rv);
1086 rv = updRoot->AppendRelativePath(programName);
1087 NS_ENSURE_SUCCESS(rv, rv);
1089 #endif
1090 #endif
1091 NS_ADDREF(*aResult = updRoot);
1092 return NS_OK;
1093 }
1095 nsresult
1096 nsXREDirProvider::GetProfileStartupDir(nsIFile* *aResult)
1097 {
1098 if (mProfileDir)
1099 return mProfileDir->Clone(aResult);
1101 if (mAppProvider) {
1102 nsCOMPtr<nsIFile> needsclone;
1103 bool dummy;
1104 nsresult rv = mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP,
1105 &dummy,
1106 getter_AddRefs(needsclone));
1107 if (NS_SUCCEEDED(rv))
1108 return needsclone->Clone(aResult);
1109 }
1111 return NS_ERROR_FAILURE;
1112 }
1114 nsresult
1115 nsXREDirProvider::GetProfileDir(nsIFile* *aResult)
1116 {
1117 if (mProfileDir) {
1118 if (!mProfileNotified)
1119 return NS_ERROR_FAILURE;
1121 return mProfileDir->Clone(aResult);
1122 }
1124 if (mAppProvider) {
1125 nsCOMPtr<nsIFile> needsclone;
1126 bool dummy;
1127 nsresult rv = mAppProvider->GetFile(NS_APP_USER_PROFILE_50_DIR,
1128 &dummy,
1129 getter_AddRefs(needsclone));
1130 if (NS_SUCCEEDED(rv))
1131 return needsclone->Clone(aResult);
1132 }
1134 return NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aResult);
1135 }
1137 nsresult
1138 nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal)
1139 {
1140 // Copied from nsAppFileLocationProvider (more or less)
1141 NS_ENSURE_ARG_POINTER(aFile);
1142 nsCOMPtr<nsIFile> localDir;
1144 nsresult rv = GetAppDir()->Clone(getter_AddRefs(localDir));
1145 NS_ENSURE_SUCCESS(rv, rv);
1147 int levelsToRemove = 1; // In FF21+, appDir points to browser subdirectory.
1148 #if defined(XP_MACOSX)
1149 levelsToRemove += 2;
1150 #endif
1151 while (localDir && (levelsToRemove > 0)) {
1152 // When crawling up the hierarchy, components named "." do not count.
1153 nsAutoCString removedName;
1154 rv = localDir->GetNativeLeafName(removedName);
1155 NS_ENSURE_SUCCESS(rv, rv);
1156 bool didRemove = !removedName.Equals(".");
1158 // Remove a directory component.
1159 nsCOMPtr<nsIFile> parentDir;
1160 rv = localDir->GetParent(getter_AddRefs(parentDir));
1161 NS_ENSURE_SUCCESS(rv, rv);
1162 localDir = parentDir;
1164 if (didRemove)
1165 --levelsToRemove;
1166 }
1168 if (!localDir)
1169 return NS_ERROR_FAILURE;
1171 rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("TorBrowser"
1172 XPCOM_FILE_PATH_SEPARATOR "Data"
1173 XPCOM_FILE_PATH_SEPARATOR "Browser"));
1174 NS_ENSURE_SUCCESS(rv, rv);
1176 if (aLocal) {
1177 rv = localDir->AppendNative(NS_LITERAL_CSTRING("Caches"));
1178 NS_ENSURE_SUCCESS(rv, rv);
1179 }
1181 NS_IF_ADDREF(*aFile = localDir);
1182 return rv;
1183 }
1185 nsresult
1186 nsXREDirProvider::GetSysUserExtensionsDirectory(nsIFile** aFile)
1187 {
1188 nsCOMPtr<nsIFile> localDir;
1189 nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), false);
1190 NS_ENSURE_SUCCESS(rv, rv);
1192 rv = AppendSysUserExtensionPath(localDir);
1193 NS_ENSURE_SUCCESS(rv, rv);
1195 rv = EnsureDirectoryExists(localDir);
1196 NS_ENSURE_SUCCESS(rv, rv);
1198 NS_ADDREF(*aFile = localDir);
1199 return NS_OK;
1200 }
1202 #if defined(XP_UNIX) || defined(XP_MACOSX)
1203 nsresult
1204 nsXREDirProvider::GetSystemExtensionsDirectory(nsIFile** aFile)
1205 {
1206 nsresult rv;
1207 nsCOMPtr<nsIFile> localDir;
1208 #if defined(XP_MACOSX)
1209 FSRef fsRef;
1210 OSErr err = ::FSFindFolder(kOnSystemDisk, kApplicationSupportFolderType, kCreateFolder, &fsRef);
1211 NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
1213 rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localDir));
1214 NS_ENSURE_SUCCESS(rv, rv);
1216 nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir);
1217 NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED);
1219 rv = dirFileMac->InitWithFSRef(&fsRef);
1220 NS_ENSURE_SUCCESS(rv, rv);
1222 localDir = do_QueryInterface(dirFileMac, &rv);
1224 static const char* const sXR = "Mozilla";
1225 rv = localDir->AppendNative(nsDependentCString(sXR));
1226 NS_ENSURE_SUCCESS(rv, rv);
1228 static const char* const sExtensions = "Extensions";
1229 rv = localDir->AppendNative(nsDependentCString(sExtensions));
1230 NS_ENSURE_SUCCESS(rv, rv);
1231 #elif defined(XP_UNIX)
1232 static const char *const sysSExtDir =
1233 #ifdef HAVE_USR_LIB64_DIR
1234 "/usr/lib64/mozilla/extensions";
1235 #elif defined(__OpenBSD__) || defined(__FreeBSD__)
1236 "/usr/local/lib/mozilla/extensions";
1237 #else
1238 "/usr/lib/mozilla/extensions";
1239 #endif
1241 rv = NS_NewNativeLocalFile(nsDependentCString(sysSExtDir), false,
1242 getter_AddRefs(localDir));
1243 NS_ENSURE_SUCCESS(rv, rv);
1244 #endif
1246 NS_ADDREF(*aFile = localDir);
1247 return NS_OK;
1248 }
1249 #endif
1251 nsresult
1252 nsXREDirProvider::GetUserDataDirectory(nsIFile** aFile, bool aLocal,
1253 const nsACString* aProfileName,
1254 const nsACString* aAppName,
1255 const nsACString* aVendorName)
1256 {
1257 nsCOMPtr<nsIFile> localDir;
1258 nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), aLocal);
1259 NS_ENSURE_SUCCESS(rv, rv);
1261 rv = AppendProfilePath(localDir, aProfileName, aAppName, aVendorName, aLocal);
1262 NS_ENSURE_SUCCESS(rv, rv);
1264 #ifdef DEBUG_jungshik
1265 nsAutoCString cwd;
1266 localDir->GetNativePath(cwd);
1267 printf("nsXREDirProvider::GetUserDataDirectory: %s\n", cwd.get());
1268 #endif
1269 rv = EnsureDirectoryExists(localDir);
1270 NS_ENSURE_SUCCESS(rv, rv);
1272 NS_ADDREF(*aFile = localDir);
1273 return NS_OK;
1274 }
1276 nsresult
1277 nsXREDirProvider::EnsureDirectoryExists(nsIFile* aDirectory)
1278 {
1279 bool exists;
1280 nsresult rv = aDirectory->Exists(&exists);
1281 NS_ENSURE_SUCCESS(rv, rv);
1282 #ifdef DEBUG_jungshik
1283 if (!exists) {
1284 nsAutoCString cwd;
1285 aDirectory->GetNativePath(cwd);
1286 printf("nsXREDirProvider::EnsureDirectoryExists: %s does not\n", cwd.get());
1287 }
1288 #endif
1289 if (!exists)
1290 rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0700);
1291 #ifdef DEBUG_jungshik
1292 if (NS_FAILED(rv))
1293 NS_WARNING("nsXREDirProvider::EnsureDirectoryExists: create failed");
1294 #endif
1296 return rv;
1297 }
1299 void
1300 nsXREDirProvider::EnsureProfileFileExists(nsIFile *aFile)
1301 {
1302 nsresult rv;
1303 bool exists;
1305 rv = aFile->Exists(&exists);
1306 if (NS_FAILED(rv) || exists) return;
1308 nsAutoCString leafName;
1309 rv = aFile->GetNativeLeafName(leafName);
1310 if (NS_FAILED(rv)) return;
1312 nsCOMPtr<nsIFile> defaultsFile;
1313 rv = GetProfileDefaultsDir(getter_AddRefs(defaultsFile));
1314 if (NS_FAILED(rv)) return;
1316 rv = defaultsFile->AppendNative(leafName);
1317 if (NS_FAILED(rv)) return;
1319 defaultsFile->CopyToNative(mProfileDir, EmptyCString());
1320 }
1322 nsresult
1323 nsXREDirProvider::GetProfileDefaultsDir(nsIFile* *aResult)
1324 {
1325 NS_ASSERTION(mGREDir, "nsXREDirProvider not initialized.");
1326 NS_PRECONDITION(aResult, "Null out-param");
1328 nsresult rv;
1329 nsCOMPtr<nsIFile> defaultsDir;
1331 rv = GetAppDir()->Clone(getter_AddRefs(defaultsDir));
1332 NS_ENSURE_SUCCESS(rv, rv);
1334 rv = defaultsDir->AppendNative(NS_LITERAL_CSTRING("defaults"));
1335 NS_ENSURE_SUCCESS(rv, rv);
1337 rv = defaultsDir->AppendNative(NS_LITERAL_CSTRING("profile"));
1338 NS_ENSURE_SUCCESS(rv, rv);
1340 NS_ADDREF(*aResult = defaultsDir);
1341 return NS_OK;
1342 }
1344 nsresult
1345 nsXREDirProvider::AppendSysUserExtensionPath(nsIFile* aFile)
1346 {
1347 NS_ASSERTION(aFile, "Null pointer!");
1349 nsresult rv;
1351 #if defined (XP_MACOSX) || defined(XP_WIN)
1353 static const char* const sXR = "Mozilla";
1354 rv = aFile->AppendNative(nsDependentCString(sXR));
1355 NS_ENSURE_SUCCESS(rv, rv);
1357 static const char* const sExtensions = "Extensions";
1358 rv = aFile->AppendNative(nsDependentCString(sExtensions));
1359 NS_ENSURE_SUCCESS(rv, rv);
1361 #elif defined(XP_UNIX)
1363 static const char* const sXR = ".mozilla";
1364 rv = aFile->AppendNative(nsDependentCString(sXR));
1365 NS_ENSURE_SUCCESS(rv, rv);
1367 static const char* const sExtensions = "extensions";
1368 rv = aFile->AppendNative(nsDependentCString(sExtensions));
1369 NS_ENSURE_SUCCESS(rv, rv);
1371 #else
1372 #error "Don't know how to get XRE user extension path on your platform"
1373 #endif
1374 return NS_OK;
1375 }
1378 nsresult
1379 nsXREDirProvider::AppendProfilePath(nsIFile* aFile,
1380 const nsACString* aProfileName,
1381 const nsACString* aAppName,
1382 const nsACString* aVendorName,
1383 bool aLocal)
1384 {
1385 NS_ASSERTION(aFile, "Null pointer!");
1387 if (!gAppData) {
1388 return NS_ERROR_FAILURE;
1389 }
1391 nsAutoCString profile;
1392 if (aProfileName && !aProfileName->IsEmpty()) {
1393 profile = *aProfileName;
1394 } else if (gAppData->profile) {
1395 profile = gAppData->profile;
1396 }
1398 nsresult rv = NS_ERROR_FAILURE;
1400 #if defined (XP_MACOSX)
1401 if (!profile.IsEmpty()) {
1402 rv = AppendProfileString(aFile, profile.get());
1403 NS_ENSURE_SUCCESS(rv, rv);
1404 }
1406 #elif defined(XP_WIN)
1407 if (!profile.IsEmpty()) {
1408 rv = AppendProfileString(aFile, profile.get());
1409 NS_ENSURE_SUCCESS(rv, rv);
1410 }
1412 #elif defined(ANDROID)
1413 // The directory used for storing profiles
1414 // The parent of this directory is set in GetUserDataDirectoryHome
1415 // XXX: handle gAppData->profile properly
1416 // XXXsmaug ...and the rest of the profile creation!
1417 MOZ_ASSERT(!aAppName,
1418 "Profile creation for external applications is not implemented!");
1419 rv = aFile->AppendNative(nsDependentCString("mozilla"));
1420 NS_ENSURE_SUCCESS(rv, rv);
1421 #elif defined(XP_UNIX)
1422 if (!profile.IsEmpty()) {
1423 // Skip any leading path characters
1424 const char* profileStart = profile.get();
1425 while (*profileStart == '/' || *profileStart == '\\')
1426 profileStart++;
1428 // On the off chance that someone wanted their folder to be hidden don't
1429 // let it become ".."
1430 if (*profileStart == '.')
1431 profileStart++;
1433 // Make it hidden (by starting with ".").
1434 nsAutoCString folder(".");
1435 folder.Append(profileStart);
1436 ToLowerCase(folder);
1438 rv = AppendProfileString(aFile, folder.BeginReading());
1439 NS_ENSURE_SUCCESS(rv, rv);
1440 }
1442 #else
1443 #error "Don't know how to get profile path on your platform"
1444 #endif
1445 return NS_OK;
1446 }
1448 nsresult
1449 nsXREDirProvider::AppendProfileString(nsIFile* aFile, const char* aPath)
1450 {
1451 NS_ASSERTION(aFile, "Null file!");
1452 NS_ASSERTION(aPath, "Null path!");
1454 nsAutoCString pathDup(aPath);
1456 char* path = pathDup.BeginWriting();
1458 nsresult rv;
1459 char* subdir;
1460 while ((subdir = NS_strtok("/\\", &path))) {
1461 rv = aFile->AppendNative(nsDependentCString(subdir));
1462 NS_ENSURE_SUCCESS(rv, rv);
1463 }
1465 return NS_OK;
1466 }