toolkit/xre/nsXREDirProvider.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:75b2e1df4a3a
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/. */
5
6 #include "nsAppRunner.h"
7 #include "nsToolkitCompsCID.h"
8 #include "nsXREDirProvider.h"
9
10 #include "jsapi.h"
11
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"
20
21 #include "nsAppDirectoryServiceDefs.h"
22 #include "nsDirectoryServiceDefs.h"
23 #include "nsDirectoryServiceUtils.h"
24 #include "nsXULAppAPI.h"
25 #include "nsCategoryManagerUtils.h"
26
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"
38
39 #include <stdlib.h>
40
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
54
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
62
63 #define PREF_OVERRIDE_DIRNAME "preferences"
64
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 }
73
74 nsXREDirProvider* gDirServiceProvider = nullptr;
75
76 nsXREDirProvider::nsXREDirProvider() :
77 mProfileNotified(false)
78 {
79 gDirServiceProvider = this;
80 }
81
82 nsXREDirProvider::~nsXREDirProvider()
83 {
84 gDirServiceProvider = nullptr;
85 }
86
87 nsXREDirProvider*
88 nsXREDirProvider::GetSingleton()
89 {
90 return gDirServiceProvider;
91 }
92
93 nsresult
94 nsXREDirProvider::Initialize(nsIFile *aXULAppDir,
95 nsIFile *aGREDir,
96 nsIDirectoryServiceProvider* aAppProvider)
97 {
98 NS_ENSURE_ARG(aXULAppDir);
99 NS_ENSURE_ARG(aGREDir);
100
101 mAppProvider = aAppProvider;
102 mXULAppDir = aXULAppDir;
103 mGREDir = aGREDir;
104
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 }
114
115 LoadAppBundleDirs();
116 return NS_OK;
117 }
118
119 nsresult
120 nsXREDirProvider::SetProfile(nsIFile* aDir, nsIFile* aLocalDir)
121 {
122 NS_ASSERTION(aDir && aLocalDir, "We don't support no-profile apps yet!");
123
124 nsresult rv;
125
126 rv = EnsureDirectoryExists(aDir);
127 if (NS_FAILED(rv))
128 return rv;
129
130 rv = EnsureDirectoryExists(aLocalDir);
131 if (NS_FAILED(rv))
132 return rv;
133
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
157
158 mProfileDir = aDir;
159 mProfileLocalDir = aLocalDir;
160 return NS_OK;
161 }
162
163 NS_IMPL_QUERY_INTERFACE(nsXREDirProvider,
164 nsIDirectoryServiceProvider,
165 nsIDirectoryServiceProvider2,
166 nsIProfileStartup)
167
168 NS_IMETHODIMP_(MozExternalRefCountType)
169 nsXREDirProvider::AddRef()
170 {
171 return 1;
172 }
173
174 NS_IMETHODIMP_(MozExternalRefCountType)
175 nsXREDirProvider::Release()
176 {
177 return 0;
178 }
179
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);
190
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 }
201
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);
212
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 }
223
224 NS_IMETHODIMP
225 nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
226 nsIFile** aFile)
227 {
228 nsresult rv;
229
230 bool gettingProfile = false;
231
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;
237
238 if (mProfileLocalDir)
239 return mProfileLocalDir->Clone(aFile);
240
241 if (mAppProvider)
242 return mAppProvider->GetFile(aProperty, aPersistent, aFile);
243
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;
250
251 if (mProfileDir)
252 return mProfileDir->Clone(aFile);
253
254 if (mAppProvider)
255 return mAppProvider->GetFile(aProperty, aPersistent, aFile);
256
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 }
261
262 if (mAppProvider) {
263 rv = mAppProvider->GetFile(aProperty, aPersistent, aFile);
264 if (NS_SUCCEEDED(rv) && *aFile)
265 return rv;
266 }
267
268 *aPersistent = true;
269
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 }
277
278 rv = NS_ERROR_FAILURE;
279 nsCOMPtr<nsIFile> file;
280
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 }
320
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);
327
328 if (mProfileDir)
329 return mProfileDir->Clone(aFile);
330
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 }
379
380 if (NS_SUCCEEDED(rv) && file) {
381 NS_ADDREF(*aFile = file);
382 return NS_OK;
383 }
384
385 bool ensureFilePermissions = false;
386
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;
433
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 }
446
447 NS_ADDREF(*aFile = file);
448 return NS_OK;
449 }
450
451 static void
452 LoadDirIntoArray(nsIFile* dir,
453 const char *const *aAppendList,
454 nsCOMArray<nsIFile>& aDirectories)
455 {
456 if (!dir)
457 return;
458
459 nsCOMPtr<nsIFile> subdir;
460 dir->Clone(getter_AddRefs(subdir));
461 if (!subdir)
462 return;
463
464 for (const char *const *a = aAppendList; *a; ++a) {
465 subdir->AppendNative(nsDependentCString(*a));
466 }
467
468 bool exists;
469 if (NS_SUCCEEDED(subdir->Exists(&exists)) && exists) {
470 aDirectories.AppendObject(subdir);
471 }
472 }
473
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;
481
482 for (int32_t i = 0; i < aSourceDirs.Count(); ++i) {
483 aSourceDirs[i]->Clone(getter_AddRefs(appended));
484 if (!appended)
485 continue;
486
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 }
498
499 NS_IMETHODIMP
500 nsXREDirProvider::GetFiles(const char* aProperty, nsISimpleEnumerator** aResult)
501 {
502 nsresult rv;
503
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 }
517
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 }
525
526 return rv;
527 }
528
529 rv = NS_NewUnionEnumerator(aResult, appEnum, xreEnum);
530 if (NS_FAILED(rv))
531 return rv;
532
533 return NS_SUCCESS_AGGREGATE_RESULT;
534 }
535
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++);
547
548 nsAutoCString path;
549 rv = parser.GetString(aSection, buf.get(), path);
550 if (NS_FAILED(rv))
551 return;
552
553 nsCOMPtr<nsIFile> dir = do_CreateInstance("@mozilla.org/file/local;1", &rv);
554 if (NS_FAILED(rv))
555 continue;
556
557 rv = dir->SetPersistentDescriptor(path);
558 if (NS_FAILED(rv))
559 continue;
560
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 }
573
574 void
575 nsXREDirProvider::LoadExtensionBundleDirectories()
576 {
577 if (!mozilla::Preferences::GetBool("extensions.defaultProviders.enabled", true))
578 return;
579
580 if (mProfileDir && !gSafeMode) {
581 nsCOMPtr<nsIFile> extensionsINI;
582 mProfileDir->Clone(getter_AddRefs(extensionsINI));
583 if (!extensionsINI)
584 return;
585
586 extensionsINI->AppendNative(NS_LITERAL_CSTRING("extensions.ini"));
587
588 nsCOMPtr<nsIFile> extensionsINILF =
589 do_QueryInterface(extensionsINI);
590 if (!extensionsINILF)
591 return;
592
593 nsINIParser parser;
594 nsresult rv = parser.Init(extensionsINILF);
595 if (NS_FAILED(rv))
596 return;
597
598 LoadExtensionDirectories(parser, "ExtensionDirs", mExtensionDirectories,
599 NS_COMPONENT_LOCATION);
600 LoadExtensionDirectories(parser, "ThemeDirs", mThemeDirectories,
601 NS_SKIN_LOCATION);
602 }
603 }
604
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;
613
614 dir->SetNativeLeafName(NS_LITERAL_CSTRING("distribution"));
615 dir->AppendNative(NS_LITERAL_CSTRING("bundles"));
616
617 nsCOMPtr<nsISimpleEnumerator> e;
618 rv = dir->GetDirectoryEntries(getter_AddRefs(e));
619 if (NS_FAILED(rv))
620 return;
621
622 nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e);
623 if (!files)
624 return;
625
626 nsCOMPtr<nsIFile> subdir;
627 while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(subdir))) && subdir) {
628 mAppBundleDirectories.AppendObject(subdir);
629
630 nsCOMPtr<nsIFile> manifest =
631 CloneAndAppend(subdir, "chrome.manifest");
632 XRE_AddManifestLocation(NS_COMPONENT_LOCATION, manifest);
633 }
634 }
635
636 static const char *const kAppendPrefDir[] = { "defaults", "preferences", nullptr };
637
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);
644
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
652
653 nsresult
654 nsXREDirProvider::GetFilesInternal(const char* aProperty,
655 nsISimpleEnumerator** aResult)
656 {
657 nsresult rv = NS_OK;
658 *aResult = nullptr;
659
660 if (!strcmp(aProperty, XRE_EXTENSIONS_DIR_LIST)) {
661 nsCOMArray<nsIFile> directories;
662
663 static const char *const kAppendNothing[] = { nullptr };
664
665 LoadDirsIntoArray(mAppBundleDirectories,
666 kAppendNothing, directories);
667 LoadDirsIntoArray(mExtensionDirectories,
668 kAppendNothing, directories);
669
670 rv = NS_NewArrayEnumerator(aResult, directories);
671 }
672 else if (!strcmp(aProperty, NS_APP_PREFS_DEFAULTS_DIR_LIST)) {
673 nsCOMArray<nsIFile> directories;
674
675 LoadDirIntoArray(mXULAppDir, kAppendPrefDir, directories);
676 LoadDirsIntoArray(mAppBundleDirectories,
677 kAppendPrefDir, directories);
678
679 rv = NS_NewArrayEnumerator(aResult, directories);
680 }
681 else if (!strcmp(aProperty, NS_EXT_PREFS_DEFAULTS_DIR_LIST)) {
682 nsCOMArray<nsIFile> directories;
683
684 LoadDirsIntoArray(mExtensionDirectories,
685 kAppendPrefDir, directories);
686
687 if (mProfileDir) {
688 nsCOMPtr<nsIFile> overrideFile;
689 mProfileDir->Clone(getter_AddRefs(overrideFile));
690 overrideFile->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
691
692 bool exists;
693 if (NS_SUCCEEDED(overrideFile->Exists(&exists)) && exists)
694 directories.AppendObject(overrideFile);
695 }
696
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.
702
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);
714
715 rv = NS_NewArrayEnumerator(aResult, directories);
716 }
717 else if (!strcmp(aProperty, NS_APP_PLUGINS_DIR_LIST)) {
718 nsCOMArray<nsIFile> directories;
719
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 }
728
729 static const char *const kAppendPlugins[] = { "plugins", nullptr };
730
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);
739
740 if (mProfileDir) {
741 nsCOMArray<nsIFile> profileDir;
742 profileDir.AppendObject(mProfileDir);
743 LoadDirsIntoArray(profileDir,
744 kAppendPlugins,
745 directories);
746 }
747
748 rv = NS_NewArrayEnumerator(aResult, directories);
749 NS_ENSURE_SUCCESS(rv, rv);
750
751 rv = NS_SUCCESS_AGGREGATE_RESULT;
752 }
753 else
754 rv = NS_ERROR_FAILURE;
755
756 return rv;
757 }
758
759 NS_IMETHODIMP
760 nsXREDirProvider::GetDirectory(nsIFile* *aResult)
761 {
762 NS_ENSURE_TRUE(mProfileDir, NS_ERROR_NOT_INITIALIZED);
763
764 return mProfileDir->Clone(aResult);
765 }
766
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;
774
775 mProfileNotified = true;
776
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.");
784
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");
791
792 if (!gSafeMode && safeModeNecessary) {
793 appStartup->RestartInSafeMode(nsIAppStartup::eForceQuit);
794 return NS_OK;
795 }
796 }
797
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 }
807
808 LoadExtensionBundleDirectories();
809
810 obsSvc->NotifyObservers(nullptr, "load-extension-defaults", nullptr);
811 obsSvc->NotifyObservers(nullptr, "profile-after-change", kStartup);
812
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");
817
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 }
822
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);
832
833 obsSvc->NotifyObservers(nullptr, "profile-initial-state", nullptr);
834 }
835 return NS_OK;
836 }
837
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);
850
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.
853
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 }
863
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 }
871
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);
879
880 nsresult rv = NS_OK;
881
882 LPITEMIDLIST pItemIDList = nullptr;
883
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 }
894
895 CoTaskMemFree(pItemIDList);
896
897 return rv;
898 }
899
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 }
917
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 }
928
929 // |size| may or may not include room for the terminating null character
930 DWORD resultLen = size / 2;
931
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 }
940
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 }
948
949 if (!_retval.CharAt(resultLen - 1)) {
950 // It was already null terminated.
951 _retval.Truncate(resultLen - 1);
952 }
953
954 return NS_OK;
955 }
956
957 static bool
958 GetCachedHash(HKEY rootKey, const nsAString &regPath, 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 }
966
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 }
977
978 #endif
979
980 nsresult
981 nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
982 {
983 nsCOMPtr<nsIFile> updRoot;
984 #if defined(MOZ_WIDGET_GONK)
985
986 nsresult rv = NS_NewNativeLocalFile(nsDependentCString("/data/local"),
987 true,
988 getter_AddRefs(updRoot));
989 NS_ENSURE_SUCCESS(rv, rv);
990
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);
998
999 #ifdef XP_WIN
1000
1001 nsAutoString pathHash;
1002 bool pathHashResult = false;
1003 bool hasVendor = gAppData->vendor && strlen(gAppData->vendor) != 0;
1004
1005 nsAutoString appDirPath;
1006 if (SUCCEEDED(updRoot->GetPath(appDirPath))) {
1007
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);
1014
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 }
1025
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 }
1041
1042 nsAutoString appPath;
1043 rv = updRoot->GetPath(appPath);
1044 NS_ENSURE_SUCCESS(rv, rv);
1045
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;
1050
1051 uint32_t bufLength = longPath.GetMutableData(&buf, MAXPATHLEN);
1052 NS_ENSURE_TRUE(bufLength >= MAXPATHLEN, NS_ERROR_OUT_OF_MEMORY);
1053
1054 DWORD len = GetLongPathNameW(appPath.get(), buf, bufLength);
1055
1056 // Failing GetLongPathName() is not fatal.
1057 if (len <= 0 || len >= bufLength)
1058 longPath.Assign(appPath);
1059 else
1060 longPath.SetLength(len);
1061
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);
1068
1069 programFiles.AppendLiteral("\\");
1070 uint32_t programFilesLen = programFiles.Length();
1071
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 }
1082
1083 rv = GetUserLocalDataDirectory(getter_AddRefs(updRoot));
1084 NS_ENSURE_SUCCESS(rv, rv);
1085
1086 rv = updRoot->AppendRelativePath(programName);
1087 NS_ENSURE_SUCCESS(rv, rv);
1088
1089 #endif
1090 #endif
1091 NS_ADDREF(*aResult = updRoot);
1092 return NS_OK;
1093 }
1094
1095 nsresult
1096 nsXREDirProvider::GetProfileStartupDir(nsIFile* *aResult)
1097 {
1098 if (mProfileDir)
1099 return mProfileDir->Clone(aResult);
1100
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 }
1110
1111 return NS_ERROR_FAILURE;
1112 }
1113
1114 nsresult
1115 nsXREDirProvider::GetProfileDir(nsIFile* *aResult)
1116 {
1117 if (mProfileDir) {
1118 if (!mProfileNotified)
1119 return NS_ERROR_FAILURE;
1120
1121 return mProfileDir->Clone(aResult);
1122 }
1123
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 }
1133
1134 return NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aResult);
1135 }
1136
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;
1143
1144 nsresult rv = GetAppDir()->Clone(getter_AddRefs(localDir));
1145 NS_ENSURE_SUCCESS(rv, rv);
1146
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(".");
1157
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;
1163
1164 if (didRemove)
1165 --levelsToRemove;
1166 }
1167
1168 if (!localDir)
1169 return NS_ERROR_FAILURE;
1170
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);
1175
1176 if (aLocal) {
1177 rv = localDir->AppendNative(NS_LITERAL_CSTRING("Caches"));
1178 NS_ENSURE_SUCCESS(rv, rv);
1179 }
1180
1181 NS_IF_ADDREF(*aFile = localDir);
1182 return rv;
1183 }
1184
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);
1191
1192 rv = AppendSysUserExtensionPath(localDir);
1193 NS_ENSURE_SUCCESS(rv, rv);
1194
1195 rv = EnsureDirectoryExists(localDir);
1196 NS_ENSURE_SUCCESS(rv, rv);
1197
1198 NS_ADDREF(*aFile = localDir);
1199 return NS_OK;
1200 }
1201
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);
1212
1213 rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localDir));
1214 NS_ENSURE_SUCCESS(rv, rv);
1215
1216 nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir);
1217 NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED);
1218
1219 rv = dirFileMac->InitWithFSRef(&fsRef);
1220 NS_ENSURE_SUCCESS(rv, rv);
1221
1222 localDir = do_QueryInterface(dirFileMac, &rv);
1223
1224 static const char* const sXR = "Mozilla";
1225 rv = localDir->AppendNative(nsDependentCString(sXR));
1226 NS_ENSURE_SUCCESS(rv, rv);
1227
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
1240
1241 rv = NS_NewNativeLocalFile(nsDependentCString(sysSExtDir), false,
1242 getter_AddRefs(localDir));
1243 NS_ENSURE_SUCCESS(rv, rv);
1244 #endif
1245
1246 NS_ADDREF(*aFile = localDir);
1247 return NS_OK;
1248 }
1249 #endif
1250
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);
1260
1261 rv = AppendProfilePath(localDir, aProfileName, aAppName, aVendorName, aLocal);
1262 NS_ENSURE_SUCCESS(rv, rv);
1263
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);
1271
1272 NS_ADDREF(*aFile = localDir);
1273 return NS_OK;
1274 }
1275
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
1295
1296 return rv;
1297 }
1298
1299 void
1300 nsXREDirProvider::EnsureProfileFileExists(nsIFile *aFile)
1301 {
1302 nsresult rv;
1303 bool exists;
1304
1305 rv = aFile->Exists(&exists);
1306 if (NS_FAILED(rv) || exists) return;
1307
1308 nsAutoCString leafName;
1309 rv = aFile->GetNativeLeafName(leafName);
1310 if (NS_FAILED(rv)) return;
1311
1312 nsCOMPtr<nsIFile> defaultsFile;
1313 rv = GetProfileDefaultsDir(getter_AddRefs(defaultsFile));
1314 if (NS_FAILED(rv)) return;
1315
1316 rv = defaultsFile->AppendNative(leafName);
1317 if (NS_FAILED(rv)) return;
1318
1319 defaultsFile->CopyToNative(mProfileDir, EmptyCString());
1320 }
1321
1322 nsresult
1323 nsXREDirProvider::GetProfileDefaultsDir(nsIFile* *aResult)
1324 {
1325 NS_ASSERTION(mGREDir, "nsXREDirProvider not initialized.");
1326 NS_PRECONDITION(aResult, "Null out-param");
1327
1328 nsresult rv;
1329 nsCOMPtr<nsIFile> defaultsDir;
1330
1331 rv = GetAppDir()->Clone(getter_AddRefs(defaultsDir));
1332 NS_ENSURE_SUCCESS(rv, rv);
1333
1334 rv = defaultsDir->AppendNative(NS_LITERAL_CSTRING("defaults"));
1335 NS_ENSURE_SUCCESS(rv, rv);
1336
1337 rv = defaultsDir->AppendNative(NS_LITERAL_CSTRING("profile"));
1338 NS_ENSURE_SUCCESS(rv, rv);
1339
1340 NS_ADDREF(*aResult = defaultsDir);
1341 return NS_OK;
1342 }
1343
1344 nsresult
1345 nsXREDirProvider::AppendSysUserExtensionPath(nsIFile* aFile)
1346 {
1347 NS_ASSERTION(aFile, "Null pointer!");
1348
1349 nsresult rv;
1350
1351 #if defined (XP_MACOSX) || defined(XP_WIN)
1352
1353 static const char* const sXR = "Mozilla";
1354 rv = aFile->AppendNative(nsDependentCString(sXR));
1355 NS_ENSURE_SUCCESS(rv, rv);
1356
1357 static const char* const sExtensions = "Extensions";
1358 rv = aFile->AppendNative(nsDependentCString(sExtensions));
1359 NS_ENSURE_SUCCESS(rv, rv);
1360
1361 #elif defined(XP_UNIX)
1362
1363 static const char* const sXR = ".mozilla";
1364 rv = aFile->AppendNative(nsDependentCString(sXR));
1365 NS_ENSURE_SUCCESS(rv, rv);
1366
1367 static const char* const sExtensions = "extensions";
1368 rv = aFile->AppendNative(nsDependentCString(sExtensions));
1369 NS_ENSURE_SUCCESS(rv, rv);
1370
1371 #else
1372 #error "Don't know how to get XRE user extension path on your platform"
1373 #endif
1374 return NS_OK;
1375 }
1376
1377
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!");
1386
1387 if (!gAppData) {
1388 return NS_ERROR_FAILURE;
1389 }
1390
1391 nsAutoCString profile;
1392 if (aProfileName && !aProfileName->IsEmpty()) {
1393 profile = *aProfileName;
1394 } else if (gAppData->profile) {
1395 profile = gAppData->profile;
1396 }
1397
1398 nsresult rv = NS_ERROR_FAILURE;
1399
1400 #if defined (XP_MACOSX)
1401 if (!profile.IsEmpty()) {
1402 rv = AppendProfileString(aFile, profile.get());
1403 NS_ENSURE_SUCCESS(rv, rv);
1404 }
1405
1406 #elif defined(XP_WIN)
1407 if (!profile.IsEmpty()) {
1408 rv = AppendProfileString(aFile, profile.get());
1409 NS_ENSURE_SUCCESS(rv, rv);
1410 }
1411
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++;
1427
1428 // On the off chance that someone wanted their folder to be hidden don't
1429 // let it become ".."
1430 if (*profileStart == '.')
1431 profileStart++;
1432
1433 // Make it hidden (by starting with ".").
1434 nsAutoCString folder(".");
1435 folder.Append(profileStart);
1436 ToLowerCase(folder);
1437
1438 rv = AppendProfileString(aFile, folder.BeginReading());
1439 NS_ENSURE_SUCCESS(rv, rv);
1440 }
1441
1442 #else
1443 #error "Don't know how to get profile path on your platform"
1444 #endif
1445 return NS_OK;
1446 }
1447
1448 nsresult
1449 nsXREDirProvider::AppendProfileString(nsIFile* aFile, const char* aPath)
1450 {
1451 NS_ASSERTION(aFile, "Null file!");
1452 NS_ASSERTION(aPath, "Null path!");
1453
1454 nsAutoCString pathDup(aPath);
1455
1456 char* path = pathDup.BeginWriting();
1457
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 }
1464
1465 return NS_OK;
1466 }

mercurial