1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2002
20 * the Initial Developer. All Rights Reserved.
23 * Brian Ryner <bryner@brianryner.com>
24 * Benjamin Smedberg <bsmedberg@covad.net>
25 * Ben Goodger <ben@mozilla.org>
26 * Jens Bannmann <jens.b@web.de>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either the GNU General Public License Version 2 or later (the "GPL"), or
30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #include "nsAppRunner.h"
43 #include "nsXREDirProvider.h"
47 #include "nsIJSContextStack.h"
48 #include "nsIDirectoryEnumerator.h"
49 #include "nsILocalFile.h"
50 #include "nsIObserverService.h"
51 #include "nsIProfileChangeStatus.h"
52 #include "nsISimpleEnumerator.h"
53 #include "nsIToolkitChromeRegistry.h"
55 #include "nsAppDirectoryServiceDefs.h"
56 #include "nsDirectoryServiceDefs.h"
57 #include "nsDirectoryServiceUtils.h"
58 #include "nsXULAppAPI.h"
60 #include "nsINIParser.h"
61 #include "nsDependentString.h"
62 #include "nsCOMArray.h"
63 #include "nsArrayEnumerator.h"
64 #include "nsEnumeratorUtils.h"
65 #include "nsReadableUtils.h"
72 // This is not defined by VC6.
73 #ifndef CSIDL_LOCAL_APPDATA
74 #define CSIDL_LOCAL_APPDATA 0x001C
78 #include "nsILocalFileMac.h"
81 #include <be/kernel/image.h>
82 #include <FindDirectory.h>
92 #if defined(XP_MACOSX)
93 #define APP_REGISTRY_NAME "Application Registry"
94 #elif defined(XP_WIN) || defined(XP_OS2)
95 #define APP_REGISTRY_NAME "registry.dat"
97 #define APP_REGISTRY_NAME "appreg"
100 #define PREF_OVERRIDE_DIRNAME "preferences"
102 nsXREDirProvider
* gDirServiceProvider
= nsnull
;
104 nsXREDirProvider::nsXREDirProvider() :
105 mProfileNotified(PR_FALSE
),
106 mExtensionsLoaded(PR_FALSE
)
108 gDirServiceProvider
= this;
111 nsXREDirProvider::~nsXREDirProvider()
113 gDirServiceProvider
= nsnull
;
117 nsXREDirProvider::Initialize(nsIFile
*aXULAppDir
,
118 nsILocalFile
*aGREDir
,
119 nsIDirectoryServiceProvider
* aAppProvider
)
121 NS_ENSURE_ARG(aGREDir
);
123 mAppProvider
= aAppProvider
;
124 mXULAppDir
= aXULAppDir
;
131 nsXREDirProvider::SetProfile(nsIFile
* aDir
, nsIFile
* aLocalDir
)
133 NS_ASSERTION(aDir
&& aLocalDir
, "We don't support no-profile apps yet!");
137 rv
= EnsureDirectoryExists(aDir
);
141 rv
= EnsureDirectoryExists(aLocalDir
);
146 mProfileLocalDir
= aLocalDir
;
150 NS_IMPL_QUERY_INTERFACE3(nsXREDirProvider
,
151 nsIDirectoryServiceProvider
,
152 nsIDirectoryServiceProvider2
,
155 NS_IMETHODIMP_(nsrefcnt
)
156 nsXREDirProvider::AddRef()
161 NS_IMETHODIMP_(nsrefcnt
)
162 nsXREDirProvider::Release()
168 nsXREDirProvider::GetFile(const char* aProperty
, PRBool
* aPersistent
,
173 PRBool gettingProfile
= PR_FALSE
;
175 if (!strcmp(aProperty
, NS_APP_USER_PROFILE_LOCAL_50_DIR
)) {
176 // If XRE_NotifyProfile hasn't been called, don't fall through to
177 // mAppProvider on the profile keys.
178 if (!mProfileNotified
)
179 return NS_ERROR_FAILURE
;
181 if (mProfileLocalDir
)
182 return mProfileLocalDir
->Clone(aFile
);
185 return mAppProvider
->GetFile(aProperty
, aPersistent
, aFile
);
187 // This falls through to the case below
188 gettingProfile
= PR_TRUE
;
190 if (!strcmp(aProperty
, NS_APP_USER_PROFILE_50_DIR
) || gettingProfile
) {
191 if (!mProfileNotified
)
192 return NS_ERROR_FAILURE
;
195 return mProfileDir
->Clone(aFile
);
198 return mAppProvider
->GetFile(aProperty
, aPersistent
, aFile
);
200 // If we don't succeed here, bail early so that we aren't reentrant
201 // through the "GetProfileDir" call below.
202 return NS_ERROR_FAILURE
;
206 rv
= mAppProvider
->GetFile(aProperty
, aPersistent
, aFile
);
207 if (NS_SUCCEEDED(rv
) && *aFile
)
211 *aPersistent
= PR_TRUE
;
213 if (!strcmp(aProperty
, NS_GRE_DIR
)) {
214 return mGREDir
->Clone(aFile
);
216 else if (!strcmp(aProperty
, NS_OS_CURRENT_PROCESS_DIR
) ||
217 !strcmp(aProperty
, NS_APP_INSTALL_CLEANUP_DIR
)) {
218 return GetAppDir()->Clone(aFile
);
221 rv
= NS_ERROR_FAILURE
;
222 nsCOMPtr
<nsIFile
> file
;
224 if (!strcmp(aProperty
, NS_APP_PROFILE_DEFAULTS_50_DIR
) ||
225 !strcmp(aProperty
, NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR
)) {
226 return GetProfileDefaultsDir(aFile
);
228 else if (!strcmp(aProperty
, NS_APP_PREF_DEFAULTS_50_DIR
))
230 // return the GRE default prefs directory here, and the app default prefs
231 // directory (if applicable) in NS_APP_PREFS_DEFAULTS_DIR_LIST.
232 rv
= mGREDir
->Clone(getter_AddRefs(file
));
233 if (NS_SUCCEEDED(rv
)) {
234 rv
= file
->AppendNative(NS_LITERAL_CSTRING("defaults"));
235 if (NS_SUCCEEDED(rv
))
236 rv
= file
->AppendNative(NS_LITERAL_CSTRING("pref"));
239 else if (!strcmp(aProperty
, NS_APP_APPLICATION_REGISTRY_DIR
) ||
240 !strcmp(aProperty
, XRE_USER_APP_DATA_DIR
)) {
241 rv
= GetUserAppDataDirectory((nsILocalFile
**)(nsIFile
**) getter_AddRefs(file
));
243 else if (!strcmp(aProperty
, XRE_UPDATE_ROOT_DIR
)) {
245 rv
= GetUpdateRootDir(getter_AddRefs(file
));
247 // Only supported on Windows, so just immediately fail.
248 return NS_ERROR_FAILURE
;
251 else if (!strcmp(aProperty
, NS_APP_APPLICATION_REGISTRY_FILE
)) {
252 rv
= GetUserAppDataDirectory((nsILocalFile
**)(nsIFile
**) getter_AddRefs(file
));
253 if (NS_SUCCEEDED(rv
))
254 rv
= file
->AppendNative(NS_LITERAL_CSTRING(APP_REGISTRY_NAME
));
256 else if (!strcmp(aProperty
, NS_APP_USER_PROFILES_ROOT_DIR
)) {
257 rv
= GetUserAppDataDirectory((nsILocalFile
**)(nsIFile
**) getter_AddRefs(file
));
259 if (NS_SUCCEEDED(rv
)) {
260 #if !defined(XP_UNIX) || defined(XP_MACOSX)
261 rv
= file
->AppendNative(NS_LITERAL_CSTRING("Profiles"));
264 // We must create the profile directory here if it does not exist.
265 rv
|= EnsureDirectoryExists(file
);
268 else if (!strcmp(aProperty
, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR
)) {
269 rv
= GetUserLocalDataDirectory((nsILocalFile
**)(nsIFile
**) getter_AddRefs(file
));
271 if (NS_SUCCEEDED(rv
)) {
272 #if !defined(XP_UNIX) || defined(XP_MACOSX)
273 rv
= file
->AppendNative(NS_LITERAL_CSTRING("Profiles"));
276 // We must create the profile directory here if it does not exist.
277 rv
|= EnsureDirectoryExists(file
);
280 else if (!strcmp(aProperty
, XRE_EXECUTABLE_FILE
) && gArgv
[0]) {
281 nsCOMPtr
<nsILocalFile
> lf
;
282 rv
= XRE_GetBinaryPath(gArgv
[0], getter_AddRefs(lf
));
283 if (NS_SUCCEEDED(rv
))
286 else if (!strcmp(aProperty
, "resource:app")) {
287 rv
= GetAppDir()->Clone(getter_AddRefs(file
));
290 else if (!strcmp(aProperty
, NS_APP_PROFILE_DIR_STARTUP
) && mProfileDir
) {
291 return mProfileDir
->Clone(aFile
);
293 else if (!strcmp(aProperty
, NS_APP_PROFILE_LOCAL_DIR_STARTUP
)) {
294 if (mProfileLocalDir
)
295 return mProfileLocalDir
->Clone(aFile
);
298 return mProfileDir
->Clone(aFile
);
301 return mAppProvider
->GetFile(NS_APP_PROFILE_DIR_STARTUP
, aPersistent
,
304 #if defined(XP_UNIX) || defined(XP_MACOSX)
305 else if (!strcmp(aProperty
, XRE_SYS_LOCAL_EXTENSION_PARENT_DIR
)) {
306 return GetSystemExtensionsDirectory((nsILocalFile
**)(nsIFile
**) aFile
);
309 #if defined(XP_UNIX) && !defined(XP_MACOSX)
310 else if (!strcmp(aProperty
, XRE_SYS_SHARE_EXTENSION_PARENT_DIR
)) {
311 static const char *const sysLExtDir
= "/usr/share/mozilla/extensions";
312 return NS_NewNativeLocalFile(nsDependentCString(sysLExtDir
),
313 PR_FALSE
, (nsILocalFile
**)(nsIFile
**) aFile
);
316 else if (!strcmp(aProperty
, XRE_USER_SYS_EXTENSION_DIR
)) {
317 return GetSysUserExtensionsDirectory((nsILocalFile
**)(nsIFile
**) aFile
);
319 else if (NS_SUCCEEDED(GetProfileStartupDir(getter_AddRefs(file
)))) {
320 // We need to allow component, xpt, and chrome registration to
321 // occur prior to the profile-after-change notification.
322 if (!strcmp(aProperty
, NS_XPCOM_COMPONENT_REGISTRY_FILE
)) {
323 rv
= file
->AppendNative(NS_LITERAL_CSTRING("compreg.dat"));
325 else if (!strcmp(aProperty
, NS_XPCOM_XPTI_REGISTRY_FILE
)) {
326 rv
= file
->AppendNative(NS_LITERAL_CSTRING("xpti.dat"));
328 else if (!strcmp(aProperty
, NS_APP_USER_CHROME_DIR
)) {
329 rv
= file
->AppendNative(NS_LITERAL_CSTRING("chrome"));
333 if (NS_SUCCEEDED(rv
) && file
) {
334 NS_ADDREF(*aFile
= file
);
338 PRBool ensureFilePermissions
= PR_FALSE
;
340 if (NS_SUCCEEDED(GetProfileDir(getter_AddRefs(file
)))) {
341 if (!strcmp(aProperty
, NS_APP_PREFS_50_DIR
)) {
344 else if (!strcmp(aProperty
, NS_APP_PREFS_50_FILE
)) {
345 rv
= file
->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
347 else if (!strcmp(aProperty
, NS_LOCALSTORE_UNSAFE_FILE
)) {
348 rv
= file
->AppendNative(NS_LITERAL_CSTRING("localstore.rdf"));
350 else if (!strcmp(aProperty
, NS_APP_LOCALSTORE_50_FILE
)) {
352 rv
= file
->AppendNative(NS_LITERAL_CSTRING("localstore-safe.rdf"));
353 file
->Remove(PR_FALSE
);
356 rv
= file
->AppendNative(NS_LITERAL_CSTRING("localstore.rdf"));
357 EnsureProfileFileExists(file
);
358 ensureFilePermissions
= PR_TRUE
;
361 else if (!strcmp(aProperty
, NS_APP_HISTORY_50_FILE
)) {
362 rv
= file
->AppendNative(NS_LITERAL_CSTRING("history.dat"));
364 else if (!strcmp(aProperty
, NS_APP_USER_MIMETYPES_50_FILE
)) {
365 rv
= file
->AppendNative(NS_LITERAL_CSTRING("mimeTypes.rdf"));
366 EnsureProfileFileExists(file
);
367 ensureFilePermissions
= PR_TRUE
;
369 else if (!strcmp(aProperty
, NS_APP_STORAGE_50_FILE
)) {
370 rv
= file
->AppendNative(NS_LITERAL_CSTRING("storage.sdb"));
372 else if (!strcmp(aProperty
, NS_APP_DOWNLOADS_50_FILE
)) {
373 rv
= file
->AppendNative(NS_LITERAL_CSTRING("downloads.rdf"));
375 else if (!strcmp(aProperty
, NS_APP_PREFS_OVERRIDE_DIR
)) {
376 rv
= mProfileDir
->Clone(getter_AddRefs(file
));
377 rv
|= file
->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME
));
378 rv
|= EnsureDirectoryExists(file
);
381 if (NS_FAILED(rv
) || !file
)
382 return NS_ERROR_FAILURE
;
384 if (ensureFilePermissions
) {
385 PRBool fileToEnsureExists
;
387 if (NS_SUCCEEDED(file
->Exists(&fileToEnsureExists
)) && fileToEnsureExists
388 && NS_SUCCEEDED(file
->IsWritable(&isWritable
)) && !isWritable
) {
389 PRUint32 permissions
;
390 if (NS_SUCCEEDED(file
->GetPermissions(&permissions
))) {
391 rv
= file
->SetPermissions(permissions
| 0600);
392 NS_ASSERTION(NS_SUCCEEDED(rv
), "failed to ensure file permissions");
397 NS_ADDREF(*aFile
= file
);
402 LoadPlatformDirectory(nsIFile
* aBundleDirectory
,
403 nsCOMArray
<nsIFile
> &aDirectories
)
405 nsCOMPtr
<nsIFile
> platformDir
;
406 nsresult rv
= aBundleDirectory
->Clone(getter_AddRefs(platformDir
));
410 platformDir
->AppendNative(NS_LITERAL_CSTRING("platform"));
413 nsCOMPtr
<nsIFile
> platformABIDir
;
414 rv
= platformDir
->Clone(getter_AddRefs(platformABIDir
));
419 platformDir
->AppendNative(NS_LITERAL_CSTRING(OS_TARGET
));
422 if (NS_SUCCEEDED(platformDir
->Exists(&exists
)) && exists
)
423 aDirectories
.AppendObject(platformDir
);
426 platformABIDir
->AppendNative(NS_LITERAL_CSTRING(TARGET_OS_ABI
));
427 if (NS_SUCCEEDED(platformABIDir
->Exists(&exists
)) && exists
)
428 aDirectories
.AppendObject(platformABIDir
);
433 LoadAppDirIntoArray(nsIFile
* aXULAppDir
,
434 const char *const *aAppendList
,
435 nsCOMArray
<nsIFile
>& aDirectories
)
440 nsCOMPtr
<nsIFile
> subdir
;
441 aXULAppDir
->Clone(getter_AddRefs(subdir
));
445 for (; *aAppendList
; ++aAppendList
)
446 subdir
->AppendNative(nsDependentCString(*aAppendList
));
449 if (NS_SUCCEEDED(subdir
->Exists(&exists
)) && exists
)
450 aDirectories
.AppendObject(subdir
);
454 LoadDirsIntoArray(nsCOMArray
<nsIFile
>& aSourceDirs
,
455 const char *const* aAppendList
,
456 nsCOMArray
<nsIFile
>& aDirectories
)
458 nsCOMPtr
<nsIFile
> appended
;
461 for (PRInt32 i
= 0; i
< aSourceDirs
.Count(); ++i
) {
462 aSourceDirs
[i
]->Clone(getter_AddRefs(appended
));
466 for (const char *const *a
= aAppendList
; *a
; ++a
)
467 appended
->AppendNative(nsDependentCString(*a
));
469 if (NS_SUCCEEDED(appended
->Exists(&exists
)) && exists
)
470 aDirectories
.AppendObject(appended
);
474 static const char *const kAppendChromeManifests
[] =
475 { "chrome.manifest", nsnull
};
478 nsXREDirProvider::GetFiles(const char* aProperty
, nsISimpleEnumerator
** aResult
)
482 nsCOMPtr
<nsISimpleEnumerator
> appEnum
;
483 nsCOMPtr
<nsIDirectoryServiceProvider2
>
484 appP2(do_QueryInterface(mAppProvider
));
486 rv
= appP2
->GetFiles(aProperty
, getter_AddRefs(appEnum
));
490 else if (rv
!= NS_SUCCESS_AGGREGATE_RESULT
) {
491 NS_ADDREF(*aResult
= appEnum
);
496 nsCOMPtr
<nsISimpleEnumerator
> xreEnum
;
497 rv
= GetFilesInternal(aProperty
, getter_AddRefs(xreEnum
));
500 NS_ADDREF(*aResult
= appEnum
);
501 return NS_SUCCESS_AGGREGATE_RESULT
;
507 rv
= NS_NewUnionEnumerator(aResult
, appEnum
, xreEnum
);
511 return NS_SUCCESS_AGGREGATE_RESULT
;
515 LoadExtensionDirectories(nsINIParser
&parser
,
516 const char *aSection
,
517 nsCOMArray
<nsIFile
> &aDirectories
)
522 nsCAutoString
buf("Extension");
526 rv
= parser
.GetString(aSection
, buf
.get(), path
);
530 nsCOMPtr
<nsILocalFile
> dir
= do_CreateInstance("@mozilla.org/file/local;1", &rv
);
534 rv
= dir
->SetPersistentDescriptor(path
);
538 aDirectories
.AppendObject(dir
);
539 LoadPlatformDirectory(dir
, aDirectories
);
545 nsXREDirProvider::LoadBundleDirectories()
547 if (mExtensionsLoaded
)
550 mExtensionsLoaded
= PR_TRUE
;
552 // first load distribution/bundles
554 LoadPlatformDirectory(mXULAppDir
, mAppBundleDirectories
);
559 if (mProfileDir
&& !gSafeMode
) {
560 nsCOMPtr
<nsIFile
> extensionsINI
;
561 mProfileDir
->Clone(getter_AddRefs(extensionsINI
));
565 extensionsINI
->AppendNative(NS_LITERAL_CSTRING("extensions.ini"));
567 nsCOMPtr
<nsILocalFile
> extensionsINILF
=
568 do_QueryInterface(extensionsINI
);
569 if (!extensionsINILF
)
573 nsresult rv
= parser
.Init(extensionsINILF
);
577 LoadExtensionDirectories(parser
, "ExtensionDirs", mExtensionDirectories
);
578 LoadExtensionDirectories(parser
, "ThemeDirs", mThemeDirectories
);
583 nsXREDirProvider::LoadAppBundleDirs()
588 nsCOMPtr
<nsIFile
> dir
;
589 nsresult rv
= mXULAppDir
->Clone(getter_AddRefs(dir
));
593 dir
->AppendNative(NS_LITERAL_CSTRING("distribution"));
594 dir
->AppendNative(NS_LITERAL_CSTRING("bundles"));
597 if (NS_FAILED(dir
->Exists(&exists
)) || !exists
)
600 nsCOMPtr
<nsISimpleEnumerator
> e
;
601 rv
= dir
->GetDirectoryEntries(getter_AddRefs(e
));
605 nsCOMPtr
<nsIDirectoryEnumerator
> files
= do_QueryInterface(e
);
609 nsCOMPtr
<nsIFile
> subdir
;
610 while (NS_SUCCEEDED(files
->GetNextFile(getter_AddRefs(subdir
))) && subdir
) {
611 mAppBundleDirectories
.AppendObject(subdir
);
612 LoadPlatformDirectory(subdir
, mAppBundleDirectories
);
616 static const char *const kAppendPrefDir
[] = { "defaults", "preferences", nsnull
};
618 #ifdef DEBUG_bsmedberg
620 DumpFileArray(const char *key
,
621 nsCOMArray
<nsIFile
> dirs
)
623 fprintf(stderr
, "nsXREDirProvider::GetFilesInternal(%s)\n", key
);
626 for (PRInt32 i
= 0; i
< dirs
.Count(); ++i
) {
627 dirs
[i
]->GetNativePath(path
);
628 fprintf(stderr
, " %s\n", path
.get());
631 #endif // DEBUG_bsmedberg
634 nsXREDirProvider::GetFilesInternal(const char* aProperty
,
635 nsISimpleEnumerator
** aResult
)
640 if (!strcmp(aProperty
, XRE_EXTENSIONS_DIR_LIST
)) {
641 nsCOMArray
<nsIFile
> directories
;
643 static const char *const kAppendNothing
[] = { nsnull
};
645 LoadBundleDirectories();
646 LoadDirsIntoArray(mAppBundleDirectories
,
647 kAppendNothing
, directories
);
648 LoadDirsIntoArray(mExtensionDirectories
,
649 kAppendNothing
, directories
);
651 rv
= NS_NewArrayEnumerator(aResult
, directories
);
653 else if (!strcmp(aProperty
, NS_XPCOM_COMPONENT_DIR_LIST
)) {
654 static const char *const kAppendCompDir
[] = { "components", nsnull
};
655 nsCOMArray
<nsIFile
> directories
;
657 LoadBundleDirectories();
658 LoadDirsIntoArray(mAppBundleDirectories
,
659 kAppendCompDir
, directories
);
660 LoadDirsIntoArray(mExtensionDirectories
,
661 kAppendCompDir
, directories
);
663 rv
= NS_NewArrayEnumerator(aResult
, directories
);
665 else if (!strcmp(aProperty
, NS_APP_PREFS_DEFAULTS_DIR_LIST
)) {
666 nsCOMArray
<nsIFile
> directories
;
668 LoadBundleDirectories();
670 LoadAppDirIntoArray(mXULAppDir
, kAppendPrefDir
, directories
);
671 LoadDirsIntoArray(mAppBundleDirectories
,
672 kAppendPrefDir
, directories
);
674 rv
= NS_NewArrayEnumerator(aResult
, directories
);
676 else if (!strcmp(aProperty
, NS_EXT_PREFS_DEFAULTS_DIR_LIST
)) {
677 nsCOMArray
<nsIFile
> directories
;
679 LoadBundleDirectories();
680 LoadDirsIntoArray(mExtensionDirectories
,
681 kAppendPrefDir
, directories
);
684 nsCOMPtr
<nsIFile
> overrideFile
;
685 mProfileDir
->Clone(getter_AddRefs(overrideFile
));
686 overrideFile
->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME
));
689 if (NS_SUCCEEDED(overrideFile
->Exists(&exists
)) && exists
)
690 directories
.AppendObject(overrideFile
);
693 rv
= NS_NewArrayEnumerator(aResult
, directories
);
695 else if (!strcmp(aProperty
, NS_CHROME_MANIFESTS_FILE_LIST
)) {
696 nsCOMArray
<nsIFile
> manifests
;
698 nsCOMPtr
<nsIFile
> manifest
;
699 mGREDir
->Clone(getter_AddRefs(manifest
));
700 manifest
->AppendNative(NS_LITERAL_CSTRING("chrome"));
701 manifests
.AppendObject(manifest
);
704 nsCOMPtr
<nsIFile
> file
;
705 mXULAppDir
->Clone(getter_AddRefs(file
));
706 file
->AppendNative(NS_LITERAL_CSTRING("chrome"));
708 if (NS_SUCCEEDED(file
->Exists(&exists
)) && exists
)
709 manifests
.AppendObject(file
);
712 LoadBundleDirectories();
713 LoadDirsIntoArray(mAppBundleDirectories
,
714 kAppendChromeManifests
,
716 LoadDirsIntoArray(mExtensionDirectories
,
717 kAppendChromeManifests
,
720 rv
= NS_NewArrayEnumerator(aResult
, manifests
);
722 else if (!strcmp(aProperty
, NS_SKIN_MANIFESTS_FILE_LIST
)) {
723 nsCOMArray
<nsIFile
> manifests
;
725 LoadBundleDirectories();
726 LoadDirsIntoArray(mThemeDirectories
,
727 kAppendChromeManifests
, manifests
);
729 rv
= NS_NewArrayEnumerator(aResult
, manifests
);
731 else if (!strcmp(aProperty
, NS_APP_CHROME_DIR_LIST
)) {
732 // NS_APP_CHROME_DIR_LIST is only used to get default (native) icons
733 // for OS window decoration.
735 static const char *const kAppendChromeDir
[] = { "chrome", nsnull
};
736 nsCOMArray
<nsIFile
> directories
;
737 LoadBundleDirectories();
738 LoadAppDirIntoArray(mXULAppDir
,
741 LoadDirsIntoArray(mAppBundleDirectories
,
744 LoadDirsIntoArray(mExtensionDirectories
,
748 rv
= NS_NewArrayEnumerator(aResult
, directories
);
750 else if (!strcmp(aProperty
, NS_APP_PLUGINS_DIR_LIST
)) {
751 static const char *const kAppendPlugins
[] = { "plugins", nsnull
};
752 nsCOMArray
<nsIFile
> directories
;
754 // The root dirserviceprovider does quite a bit for us: we're mainly
755 // interested in xulapp and extension-provided plugins.
756 LoadBundleDirectories();
757 LoadDirsIntoArray(mAppBundleDirectories
,
760 LoadDirsIntoArray(mExtensionDirectories
,
764 rv
= NS_NewArrayEnumerator(aResult
, directories
);
765 NS_ENSURE_SUCCESS(rv
, rv
);
767 rv
= NS_SUCCESS_AGGREGATE_RESULT
;
770 rv
= NS_ERROR_FAILURE
;
776 nsXREDirProvider::GetDirectory(nsIFile
* *aResult
)
778 NS_ENSURE_TRUE(mProfileDir
, NS_ERROR_NOT_INITIALIZED
);
780 return mProfileDir
->Clone(aResult
);
784 nsXREDirProvider::DoStartup()
786 if (!mProfileNotified
) {
787 nsCOMPtr
<nsIObserverService
> obsSvc
788 (do_GetService("@mozilla.org/observer-service;1"));
789 if (!obsSvc
) return NS_ERROR_FAILURE
;
791 mProfileNotified
= PR_TRUE
;
793 static const PRUnichar kStartup
[] = {'s','t','a','r','t','u','p','\0'};
794 obsSvc
->NotifyObservers(nsnull
, "profile-do-change", kStartup
);
795 obsSvc
->NotifyObservers(nsnull
, "profile-after-change", kStartup
);
800 class ProfileChangeStatusImpl
: public nsIProfileChangeStatus
804 NS_DECL_NSIPROFILECHANGESTATUS
805 ProfileChangeStatusImpl() { }
807 ~ProfileChangeStatusImpl() { }
810 NS_IMPL_ISUPPORTS1(ProfileChangeStatusImpl
, nsIProfileChangeStatus
)
813 ProfileChangeStatusImpl::VetoChange()
815 NS_ERROR("Can't veto change!");
816 return NS_ERROR_FAILURE
;
820 ProfileChangeStatusImpl::ChangeFailed()
822 NS_ERROR("Profile change cancellation.");
823 return NS_ERROR_FAILURE
;
827 nsXREDirProvider::DoShutdown()
829 if (mProfileNotified
) {
830 nsCOMPtr
<nsIObserverService
> obssvc
831 (do_GetService("@mozilla.org/observer-service;1"));
832 NS_ASSERTION(obssvc
, "No observer service?");
834 nsCOMPtr
<nsIProfileChangeStatus
> cs
= new ProfileChangeStatusImpl();
835 static const PRUnichar kShutdownPersist
[] =
836 {'s','h','u','t','d','o','w','n','-','p','e','r','s','i','s','t','\0'};
837 obssvc
->NotifyObservers(cs
, "profile-change-net-teardown", kShutdownPersist
);
838 obssvc
->NotifyObservers(cs
, "profile-change-teardown", kShutdownPersist
);
840 // Phase 2c: Now that things are torn down, force JS GC so that things which depend on
841 // resources which are about to go away in "profile-before-change" are destroyed first.
842 nsCOMPtr
<nsIThreadJSContextStack
> stack
843 (do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
846 JSContext
*cx
= nsnull
;
847 stack
->GetSafeJSContext(&cx
);
852 // Phase 3: Notify observers of a profile change
853 obssvc
->NotifyObservers(cs
, "profile-before-change", kShutdownPersist
);
855 mProfileNotified
= PR_FALSE
;
861 GetShellFolderPath(int folder
, nsAString
& _retval
)
863 LPITEMIDLIST pItemIDList
= NULL
;
866 PRUint32 bufLength
= _retval
.GetMutableData(&buf
, MAXPATHLEN
);
867 NS_ENSURE_TRUE(bufLength
>= MAXPATHLEN
, NS_ERROR_OUT_OF_MEMORY
);
870 if (SUCCEEDED(SHGetSpecialFolderLocation(NULL
, folder
, &pItemIDList
)) &&
871 SHGetPathFromIDListW(pItemIDList
, buf
)) {
872 // We're going to use wcslen (wcsnlen not available in msvc7.1) so make
873 // sure to null terminate.
874 buf
[bufLength
- 1] = L
'\0';
875 _retval
.SetLength(wcslen(buf
));
878 _retval
.SetLength(0);
879 rv
= NS_ERROR_NOT_AVAILABLE
;
882 CoTaskMemFree(pItemIDList
);
888 nsXREDirProvider::GetUpdateRootDir(nsIFile
* *aResult
)
890 nsCOMPtr
<nsIFile
> appDir
= GetAppDir();
892 nsAutoString appPath
;
893 nsresult rv
= appDir
->GetPath(appPath
);
894 NS_ENSURE_SUCCESS(rv
, rv
);
896 // AppDir may be a short path. Convert to long path to make sure
897 // the consistency of the update folder location
901 PRUint32 bufLength
= longPath
.GetMutableData(&buf
, MAXPATHLEN
);
902 NS_ENSURE_TRUE(bufLength
>= MAXPATHLEN
, NS_ERROR_OUT_OF_MEMORY
);
904 DWORD len
= GetLongPathNameW(appPath
.get(), buf
, bufLength
);
906 // Failing GetLongPathName() is not fatal.
907 if (len
<= 0 || len
>= bufLength
)
908 longPath
.Assign(appPath
);
910 longPath
.SetLength(len
);
912 // Use <UserLocalDataDir>\updates\<relative path to app dir from
913 // Program Files> if app dir is under Program Files to avoid the
914 // folder virtualization mess on Windows Vista
915 nsAutoString programFiles
;
916 rv
= GetShellFolderPath(CSIDL_PROGRAM_FILES
, programFiles
);
917 NS_ENSURE_SUCCESS(rv
, rv
);
919 programFiles
.AppendLiteral("\\");
920 PRUint32 programFilesLen
= programFiles
.Length();
922 if (longPath
.Length() < programFilesLen
)
923 return NS_ERROR_FAILURE
;
925 if (_wcsnicmp(programFiles
.get(), longPath
.get(), programFilesLen
) != 0)
926 return NS_ERROR_FAILURE
;
928 nsCOMPtr
<nsILocalFile
> updRoot
;
929 rv
= GetUserLocalDataDirectory(getter_AddRefs(updRoot
));
930 NS_ENSURE_SUCCESS(rv
, rv
);
932 rv
= updRoot
->AppendRelativePath(Substring(longPath
, programFilesLen
));
933 NS_ENSURE_SUCCESS(rv
, rv
);
935 NS_ADDREF(*aResult
= updRoot
);
941 nsXREDirProvider::GetProfileStartupDir(nsIFile
* *aResult
)
944 return mProfileDir
->Clone(aResult
);
947 nsCOMPtr
<nsIFile
> needsclone
;
949 nsresult rv
= mAppProvider
->GetFile(NS_APP_PROFILE_DIR_STARTUP
,
951 getter_AddRefs(needsclone
));
952 if (NS_SUCCEEDED(rv
))
953 return needsclone
->Clone(aResult
);
956 return NS_ERROR_FAILURE
;
960 nsXREDirProvider::GetProfileDir(nsIFile
* *aResult
)
963 if (!mProfileNotified
)
964 return NS_ERROR_FAILURE
;
966 return mProfileDir
->Clone(aResult
);
970 nsCOMPtr
<nsIFile
> needsclone
;
972 nsresult rv
= mAppProvider
->GetFile(NS_APP_USER_PROFILE_50_DIR
,
974 getter_AddRefs(needsclone
));
975 if (NS_SUCCEEDED(rv
))
976 return needsclone
->Clone(aResult
);
979 return NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
, aResult
);
983 nsXREDirProvider::GetUserDataDirectoryHome(nsILocalFile
** aFile
, PRBool aLocal
)
986 return NS_ERROR_FAILURE
;
988 // Copied from nsAppFileLocationProvider (more or less)
990 nsCOMPtr
<nsILocalFile
> localDir
;
992 #if defined(XP_MACOSX)
996 folderType
= kCachedDataFolderType
;
998 #ifdef MOZ_THUNDERBIRD
999 folderType
= kDomainLibraryFolderType
;
1001 folderType
= kApplicationSupportFolderType
;
1004 OSErr err
= ::FSFindFolder(kUserDomain
, folderType
, kCreateFolder
, &fsRef
);
1005 NS_ENSURE_FALSE(err
, NS_ERROR_FAILURE
);
1007 rv
= NS_NewNativeLocalFile(EmptyCString(), PR_TRUE
, getter_AddRefs(localDir
));
1008 NS_ENSURE_SUCCESS(rv
, rv
);
1010 nsCOMPtr
<nsILocalFileMac
> dirFileMac
= do_QueryInterface(localDir
);
1011 NS_ENSURE_TRUE(dirFileMac
, NS_ERROR_UNEXPECTED
);
1013 rv
= dirFileMac
->InitWithFSRef(&fsRef
);
1014 NS_ENSURE_SUCCESS(rv
, rv
);
1016 localDir
= do_QueryInterface(dirFileMac
, &rv
);
1017 #elif defined(XP_WIN)
1020 rv
= GetShellFolderPath(CSIDL_LOCAL_APPDATA
, path
);
1021 if (!aLocal
|| NS_FAILED(rv
))
1022 rv
= GetShellFolderPath(CSIDL_APPDATA
, path
);
1023 NS_ENSURE_SUCCESS(rv
, rv
);
1025 rv
= NS_NewLocalFile(path
, PR_TRUE
, getter_AddRefs(localDir
));
1026 #elif defined(XP_OS2)
1027 #if 0 /* For OS/2 we want to always use MOZILLA_HOME */
1028 // we want an environment variable of the form
1029 // FIREFOX_HOME, etc
1030 nsDependentCString
envVar(nsDependentCString(gAppData
->name
));
1031 envVar
.Append("_HOME");
1032 char *pHome
= getenv(envVar
.get());
1034 char *pHome
= getenv("MOZILLA_HOME");
1035 if (pHome
&& *pHome
) {
1036 rv
= NS_NewNativeLocalFile(nsDependentCString(pHome
), PR_TRUE
,
1037 getter_AddRefs(localDir
));
1041 char appDir
[CCHMAXPATH
];
1043 DosGetInfoBlocks(&ptib
, &ppib
);
1044 DosQueryModuleName(ppib
->pib_hmte
, CCHMAXPATH
, appDir
);
1045 *strrchr(appDir
, '\\') = '\0';
1046 rv
= NS_NewNativeLocalFile(nsDependentCString(appDir
), PR_TRUE
, getter_AddRefs(localDir
));
1048 #elif defined(XP_BEOS)
1049 char appDir
[MAXPATHLEN
];
1050 if (find_directory(B_USER_SETTINGS_DIRECTORY
, NULL
, true, appDir
, MAXPATHLEN
))
1051 return NS_ERROR_FAILURE
;
1053 int len
= strlen(appDir
);
1055 appDir
[len
+1] = '\0';
1057 rv
= NS_NewNativeLocalFile(nsDependentCString(appDir
), PR_TRUE
,
1058 getter_AddRefs(localDir
));
1059 #elif defined(XP_UNIX)
1060 const char* homeDir
= getenv("HOME");
1061 if (!homeDir
|| !*homeDir
)
1062 return NS_ERROR_FAILURE
;
1064 rv
= NS_NewNativeLocalFile(nsDependentCString(homeDir
), PR_TRUE
,
1065 getter_AddRefs(localDir
));
1067 #error "Don't know how to get product dir on your platform"
1070 NS_IF_ADDREF(*aFile
= localDir
);
1075 nsXREDirProvider::GetSysUserExtensionsDirectory(nsILocalFile
** aFile
)
1077 nsCOMPtr
<nsILocalFile
> localDir
;
1078 nsresult rv
= GetUserDataDirectoryHome(getter_AddRefs(localDir
), PR_FALSE
);
1079 NS_ENSURE_SUCCESS(rv
, rv
);
1081 rv
= AppendSysUserExtensionPath(localDir
);
1082 NS_ENSURE_SUCCESS(rv
, rv
);
1084 rv
= EnsureDirectoryExists(localDir
);
1085 NS_ENSURE_SUCCESS(rv
, rv
);
1087 NS_ADDREF(*aFile
= localDir
);
1091 #if defined(XP_UNIX) || defined(XP_MACOSX)
1093 nsXREDirProvider::GetSystemExtensionsDirectory(nsILocalFile
** aFile
)
1096 nsCOMPtr
<nsILocalFile
> localDir
;
1097 #if defined(XP_MACOSX)
1099 OSErr err
= ::FSFindFolder(kOnSystemDisk
, kApplicationSupportFolderType
, kCreateFolder
, &fsRef
);
1100 NS_ENSURE_FALSE(err
, NS_ERROR_FAILURE
);
1102 rv
= NS_NewNativeLocalFile(EmptyCString(), PR_TRUE
, getter_AddRefs(localDir
));
1103 NS_ENSURE_SUCCESS(rv
, rv
);
1105 nsCOMPtr
<nsILocalFileMac
> dirFileMac
= do_QueryInterface(localDir
);
1106 NS_ENSURE_TRUE(dirFileMac
, NS_ERROR_UNEXPECTED
);
1108 rv
= dirFileMac
->InitWithFSRef(&fsRef
);
1109 NS_ENSURE_SUCCESS(rv
, rv
);
1111 localDir
= do_QueryInterface(dirFileMac
, &rv
);
1113 static const char* const sXR
= "Mozilla";
1114 rv
= localDir
->AppendNative(nsDependentCString(sXR
));
1115 NS_ENSURE_SUCCESS(rv
, rv
);
1117 static const char* const sExtensions
= "Extensions";
1118 rv
= localDir
->AppendNative(nsDependentCString(sExtensions
));
1119 NS_ENSURE_SUCCESS(rv
, rv
);
1120 #elif defined(XP_UNIX)
1121 static const char *const sysSExtDir
=
1122 #ifdef HAVE_USR_LIB64_DIR
1123 "/usr/lib64/mozilla/extensions";
1125 "/usr/lib/mozilla/extensions";
1128 rv
= NS_NewNativeLocalFile(nsDependentCString(sysSExtDir
), PR_FALSE
,
1129 getter_AddRefs(localDir
));
1130 NS_ENSURE_SUCCESS(rv
, rv
);
1133 rv
= EnsureDirectoryExists(localDir
);
1134 NS_ENSURE_SUCCESS(rv
, rv
);
1136 NS_ADDREF(*aFile
= localDir
);
1142 nsXREDirProvider::GetUserDataDirectory(nsILocalFile
** aFile
, PRBool aLocal
)
1144 nsCOMPtr
<nsILocalFile
> localDir
;
1145 nsresult rv
= GetUserDataDirectoryHome(getter_AddRefs(localDir
), aLocal
);
1146 NS_ENSURE_SUCCESS(rv
, rv
);
1148 rv
= AppendProfilePath(localDir
);
1149 NS_ENSURE_SUCCESS(rv
, rv
);
1151 #ifdef DEBUG_jungshik
1153 localDir
->GetNativePath(cwd
);
1154 printf("nsXREDirProvider::GetUserDataDirectory: %s\n", cwd
.get());
1156 rv
= EnsureDirectoryExists(localDir
);
1157 NS_ENSURE_SUCCESS(rv
, rv
);
1159 NS_ADDREF(*aFile
= localDir
);
1164 nsXREDirProvider::EnsureDirectoryExists(nsIFile
* aDirectory
)
1167 nsresult rv
= aDirectory
->Exists(&exists
);
1168 NS_ENSURE_SUCCESS(rv
, rv
);
1169 #ifdef DEBUG_jungshik
1172 aDirectory
->GetNativePath(cwd
);
1173 printf("nsXREDirProvider::EnsureDirectoryExists: %s does not\n", cwd
.get());
1177 rv
= aDirectory
->Create(nsIFile::DIRECTORY_TYPE
, 0700);
1178 #ifdef DEBUG_jungshik
1180 NS_WARNING("nsXREDirProvider::EnsureDirectoryExists: create failed");
1187 nsXREDirProvider::EnsureProfileFileExists(nsIFile
*aFile
)
1192 rv
= aFile
->Exists(&exists
);
1193 if (NS_FAILED(rv
) || exists
) return;
1195 nsCAutoString leafName
;
1196 rv
= aFile
->GetNativeLeafName(leafName
);
1197 if (NS_FAILED(rv
)) return;
1199 nsCOMPtr
<nsIFile
> defaultsFile
;
1200 rv
= GetProfileDefaultsDir(getter_AddRefs(defaultsFile
));
1201 if (NS_FAILED(rv
)) return;
1203 rv
= defaultsFile
->AppendNative(leafName
);
1204 if (NS_FAILED(rv
)) return;
1206 defaultsFile
->CopyToNative(mProfileDir
, EmptyCString());
1210 nsXREDirProvider::GetProfileDefaultsDir(nsIFile
* *aResult
)
1212 NS_ASSERTION(mGREDir
, "nsXREDirProvider not initialized.");
1213 NS_PRECONDITION(aResult
, "Null out-param");
1216 nsCOMPtr
<nsIFile
> defaultsDir
;
1218 rv
= GetAppDir()->Clone(getter_AddRefs(defaultsDir
));
1219 NS_ENSURE_SUCCESS(rv
, rv
);
1221 rv
= defaultsDir
->AppendNative(NS_LITERAL_CSTRING("defaults"));
1222 NS_ENSURE_SUCCESS(rv
, rv
);
1224 rv
= defaultsDir
->AppendNative(NS_LITERAL_CSTRING("profile"));
1225 NS_ENSURE_SUCCESS(rv
, rv
);
1227 NS_ADDREF(*aResult
= defaultsDir
);
1232 nsXREDirProvider::AppendSysUserExtensionPath(nsIFile
* aFile
)
1234 NS_ASSERTION(aFile
, "Null pointer!");
1238 #if defined (XP_MACOSX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS)
1240 static const char* const sXR
= "Mozilla";
1241 rv
= aFile
->AppendNative(nsDependentCString(sXR
));
1242 NS_ENSURE_SUCCESS(rv
, rv
);
1244 static const char* const sExtensions
= "Extensions";
1245 rv
= aFile
->AppendNative(nsDependentCString(sExtensions
));
1246 NS_ENSURE_SUCCESS(rv
, rv
);
1248 #elif defined(XP_UNIX)
1250 static const char* const sXR
= ".mozilla";
1251 rv
= aFile
->AppendNative(nsDependentCString(sXR
));
1252 NS_ENSURE_SUCCESS(rv
, rv
);
1254 static const char* const sExtensions
= "extensions";
1255 rv
= aFile
->AppendNative(nsDependentCString(sExtensions
));
1256 NS_ENSURE_SUCCESS(rv
, rv
);
1259 #error "Don't know how to get XRE user extension path on your platform"
1266 nsXREDirProvider::AppendProfilePath(nsIFile
* aFile
)
1268 NS_ASSERTION(aFile
, "Null pointer!");
1272 #if defined (XP_MACOSX)
1273 if (gAppData
->profile
) {
1274 rv
= AppendProfileString(aFile
, gAppData
->profile
);
1277 // Note that MacOS ignores the vendor when creating the profile hierarchy -
1278 // all application preferences directories live alongside one another in
1279 // ~/Library/Application Support/
1280 rv
= aFile
->AppendNative(nsDependentCString(gAppData
->name
));
1282 NS_ENSURE_SUCCESS(rv
, rv
);
1284 #elif defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS)
1285 if (gAppData
->profile
) {
1286 rv
= AppendProfileString(aFile
, gAppData
->profile
);
1289 if (gAppData
->vendor
) {
1290 rv
= aFile
->AppendNative(nsDependentCString(gAppData
->vendor
));
1291 NS_ENSURE_SUCCESS(rv
, rv
);
1293 rv
= aFile
->AppendNative(nsDependentCString(gAppData
->name
));
1295 NS_ENSURE_SUCCESS(rv
, rv
);
1297 #elif defined(XP_UNIX)
1298 // Make it hidden (i.e. using the ".")
1299 nsCAutoString
folder(".");
1301 if (gAppData
->profile
) {
1302 // Skip any leading path characters
1303 const char* profileStart
= gAppData
->profile
;
1304 while (*profileStart
== '/' || *profileStart
== '\\')
1307 // On the off chance that someone wanted their folder to be hidden don't
1308 // let it become ".."
1309 if (*profileStart
== '.')
1312 folder
.Append(profileStart
);
1313 ToLowerCase(folder
);
1315 rv
= AppendProfileString(aFile
, folder
.BeginReading());
1318 if (gAppData
->vendor
) {
1319 folder
.Append(gAppData
->vendor
);
1320 ToLowerCase(folder
);
1322 rv
= aFile
->AppendNative(folder
);
1323 NS_ENSURE_SUCCESS(rv
, rv
);
1328 folder
.Append(gAppData
->name
);
1329 ToLowerCase(folder
);
1331 rv
= aFile
->AppendNative(folder
);
1333 NS_ENSURE_SUCCESS(rv
, rv
);
1336 #error "Don't know how to get profile path on your platform"
1342 nsXREDirProvider::AppendProfileString(nsIFile
* aFile
, const char* aPath
)
1344 NS_ASSERTION(aFile
, "Null file!");
1345 NS_ASSERTION(aPath
, "Null path!");
1347 nsCAutoString
pathDup(aPath
);
1349 char* path
= pathDup
.BeginWriting();
1353 while ((subdir
= NS_strtok("/\\", &path
))) {
1354 rv
= aFile
->AppendNative(nsDependentCString(subdir
));
1355 NS_ENSURE_SUCCESS(rv
, rv
);