Fixed entry typemap having wrong allocation size.
[mozilla-central.git] / toolkit / xre / nsXREDirProvider.cpp
blob7a73e63c195cbd6b5b7fcbf7f0128e495b51b2b4
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
13 * License.
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.
22 * Contributor(s):
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"
45 #include "jsapi.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"
67 #include <stdlib.h>
69 #ifdef XP_WIN
70 #include <windows.h>
71 #include <shlobj.h>
72 // This is not defined by VC6.
73 #ifndef CSIDL_LOCAL_APPDATA
74 #define CSIDL_LOCAL_APPDATA 0x001C
75 #endif
76 #endif
77 #ifdef XP_MACOSX
78 #include "nsILocalFileMac.h"
79 #endif
80 #ifdef XP_BEOS
81 #include <be/kernel/image.h>
82 #include <FindDirectory.h>
83 #endif
84 #ifdef XP_UNIX
85 #include <ctype.h>
86 #endif
87 #ifdef XP_OS2
88 #define INCL_DOS
89 #include <os2.h>
90 #endif
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"
96 #else
97 #define APP_REGISTRY_NAME "appreg"
98 #endif
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;
116 nsresult
117 nsXREDirProvider::Initialize(nsIFile *aXULAppDir,
118 nsILocalFile *aGREDir,
119 nsIDirectoryServiceProvider* aAppProvider)
121 NS_ENSURE_ARG(aGREDir);
123 mAppProvider = aAppProvider;
124 mXULAppDir = aXULAppDir;
125 mGREDir = aGREDir;
127 return NS_OK;
130 nsresult
131 nsXREDirProvider::SetProfile(nsIFile* aDir, nsIFile* aLocalDir)
133 NS_ASSERTION(aDir && aLocalDir, "We don't support no-profile apps yet!");
135 nsresult rv;
137 rv = EnsureDirectoryExists(aDir);
138 if (NS_FAILED(rv))
139 return rv;
141 rv = EnsureDirectoryExists(aLocalDir);
142 if (NS_FAILED(rv))
143 return rv;
145 mProfileDir = aDir;
146 mProfileLocalDir = aLocalDir;
147 return NS_OK;
150 NS_IMPL_QUERY_INTERFACE3(nsXREDirProvider,
151 nsIDirectoryServiceProvider,
152 nsIDirectoryServiceProvider2,
153 nsIProfileStartup)
155 NS_IMETHODIMP_(nsrefcnt)
156 nsXREDirProvider::AddRef()
158 return 1;
161 NS_IMETHODIMP_(nsrefcnt)
162 nsXREDirProvider::Release()
164 return 0;
167 NS_IMETHODIMP
168 nsXREDirProvider::GetFile(const char* aProperty, PRBool* aPersistent,
169 nsIFile** aFile)
171 nsresult rv;
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);
184 if (mAppProvider)
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;
194 if (mProfileDir)
195 return mProfileDir->Clone(aFile);
197 if (mAppProvider)
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;
205 if (mAppProvider) {
206 rv = mAppProvider->GetFile(aProperty, aPersistent, aFile);
207 if (NS_SUCCEEDED(rv) && *aFile)
208 return rv;
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)) {
244 #ifdef XP_WIN
245 rv = GetUpdateRootDir(getter_AddRefs(file));
246 #else
247 // Only supported on Windows, so just immediately fail.
248 return NS_ERROR_FAILURE;
249 #endif
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"));
262 #endif
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"));
274 #endif
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))
284 file = lf;
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);
297 if (mProfileDir)
298 return mProfileDir->Clone(aFile);
300 if (mAppProvider)
301 return mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP, aPersistent,
302 aFile);
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);
308 #endif
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);
315 #endif
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);
335 return NS_OK;
338 PRBool ensureFilePermissions = PR_FALSE;
340 if (NS_SUCCEEDED(GetProfileDir(getter_AddRefs(file)))) {
341 if (!strcmp(aProperty, NS_APP_PREFS_50_DIR)) {
342 rv = NS_OK;
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)) {
351 if (gSafeMode) {
352 rv = file->AppendNative(NS_LITERAL_CSTRING("localstore-safe.rdf"));
353 file->Remove(PR_FALSE);
355 else {
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;
386 PRBool isWritable;
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);
398 return NS_OK;
401 static void
402 LoadPlatformDirectory(nsIFile* aBundleDirectory,
403 nsCOMArray<nsIFile> &aDirectories)
405 nsCOMPtr<nsIFile> platformDir;
406 nsresult rv = aBundleDirectory->Clone(getter_AddRefs(platformDir));
407 if (NS_FAILED(rv))
408 return;
410 platformDir->AppendNative(NS_LITERAL_CSTRING("platform"));
412 #ifdef TARGET_OS_ABI
413 nsCOMPtr<nsIFile> platformABIDir;
414 rv = platformDir->Clone(getter_AddRefs(platformABIDir));
415 if (NS_FAILED(rv))
416 return;
417 #endif
419 platformDir->AppendNative(NS_LITERAL_CSTRING(OS_TARGET));
421 PRBool exists;
422 if (NS_SUCCEEDED(platformDir->Exists(&exists)) && exists)
423 aDirectories.AppendObject(platformDir);
425 #ifdef TARGET_OS_ABI
426 platformABIDir->AppendNative(NS_LITERAL_CSTRING(TARGET_OS_ABI));
427 if (NS_SUCCEEDED(platformABIDir->Exists(&exists)) && exists)
428 aDirectories.AppendObject(platformABIDir);
429 #endif
432 static void
433 LoadAppDirIntoArray(nsIFile* aXULAppDir,
434 const char *const *aAppendList,
435 nsCOMArray<nsIFile>& aDirectories)
437 if (!aXULAppDir)
438 return;
440 nsCOMPtr<nsIFile> subdir;
441 aXULAppDir->Clone(getter_AddRefs(subdir));
442 if (!subdir)
443 return;
445 for (; *aAppendList; ++aAppendList)
446 subdir->AppendNative(nsDependentCString(*aAppendList));
448 PRBool exists;
449 if (NS_SUCCEEDED(subdir->Exists(&exists)) && exists)
450 aDirectories.AppendObject(subdir);
453 static void
454 LoadDirsIntoArray(nsCOMArray<nsIFile>& aSourceDirs,
455 const char *const* aAppendList,
456 nsCOMArray<nsIFile>& aDirectories)
458 nsCOMPtr<nsIFile> appended;
459 PRBool exists;
461 for (PRInt32 i = 0; i < aSourceDirs.Count(); ++i) {
462 aSourceDirs[i]->Clone(getter_AddRefs(appended));
463 if (!appended)
464 continue;
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 };
477 NS_IMETHODIMP
478 nsXREDirProvider::GetFiles(const char* aProperty, nsISimpleEnumerator** aResult)
480 nsresult rv;
482 nsCOMPtr<nsISimpleEnumerator> appEnum;
483 nsCOMPtr<nsIDirectoryServiceProvider2>
484 appP2(do_QueryInterface(mAppProvider));
485 if (appP2) {
486 rv = appP2->GetFiles(aProperty, getter_AddRefs(appEnum));
487 if (NS_FAILED(rv)) {
488 appEnum = nsnull;
490 else if (rv != NS_SUCCESS_AGGREGATE_RESULT) {
491 NS_ADDREF(*aResult = appEnum);
492 return NS_OK;
496 nsCOMPtr<nsISimpleEnumerator> xreEnum;
497 rv = GetFilesInternal(aProperty, getter_AddRefs(xreEnum));
498 if (NS_FAILED(rv)) {
499 if (appEnum) {
500 NS_ADDREF(*aResult = appEnum);
501 return NS_SUCCESS_AGGREGATE_RESULT;
504 return rv;
507 rv = NS_NewUnionEnumerator(aResult, appEnum, xreEnum);
508 if (NS_FAILED(rv))
509 return rv;
511 return NS_SUCCESS_AGGREGATE_RESULT;
514 static void
515 LoadExtensionDirectories(nsINIParser &parser,
516 const char *aSection,
517 nsCOMArray<nsIFile> &aDirectories)
519 nsresult rv;
520 PRInt32 i = 0;
521 do {
522 nsCAutoString buf("Extension");
523 buf.AppendInt(i++);
525 nsCAutoString path;
526 rv = parser.GetString(aSection, buf.get(), path);
527 if (NS_FAILED(rv))
528 return;
530 nsCOMPtr<nsILocalFile> dir = do_CreateInstance("@mozilla.org/file/local;1", &rv);
531 if (NS_FAILED(rv))
532 continue;
534 rv = dir->SetPersistentDescriptor(path);
535 if (NS_FAILED(rv))
536 continue;
538 aDirectories.AppendObject(dir);
539 LoadPlatformDirectory(dir, aDirectories);
541 while (PR_TRUE);
544 void
545 nsXREDirProvider::LoadBundleDirectories()
547 if (mExtensionsLoaded)
548 return;
550 mExtensionsLoaded = PR_TRUE;
552 // first load distribution/bundles
553 if (mXULAppDir) {
554 LoadPlatformDirectory(mXULAppDir, mAppBundleDirectories);
556 LoadAppBundleDirs();
559 if (mProfileDir && !gSafeMode) {
560 nsCOMPtr<nsIFile> extensionsINI;
561 mProfileDir->Clone(getter_AddRefs(extensionsINI));
562 if (!extensionsINI)
563 return;
565 extensionsINI->AppendNative(NS_LITERAL_CSTRING("extensions.ini"));
567 nsCOMPtr<nsILocalFile> extensionsINILF =
568 do_QueryInterface(extensionsINI);
569 if (!extensionsINILF)
570 return;
572 nsINIParser parser;
573 nsresult rv = parser.Init(extensionsINILF);
574 if (NS_FAILED(rv))
575 return;
577 LoadExtensionDirectories(parser, "ExtensionDirs", mExtensionDirectories);
578 LoadExtensionDirectories(parser, "ThemeDirs", mThemeDirectories);
582 void
583 nsXREDirProvider::LoadAppBundleDirs()
585 if (!mXULAppDir)
586 return;
588 nsCOMPtr<nsIFile> dir;
589 nsresult rv = mXULAppDir->Clone(getter_AddRefs(dir));
590 if (NS_FAILED(rv))
591 return;
593 dir->AppendNative(NS_LITERAL_CSTRING("distribution"));
594 dir->AppendNative(NS_LITERAL_CSTRING("bundles"));
596 PRBool exists;
597 if (NS_FAILED(dir->Exists(&exists)) || !exists)
598 return;
600 nsCOMPtr<nsISimpleEnumerator> e;
601 rv = dir->GetDirectoryEntries(getter_AddRefs(e));
602 if (NS_FAILED(rv))
603 return;
605 nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e);
606 if (!files)
607 return;
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
619 static void
620 DumpFileArray(const char *key,
621 nsCOMArray<nsIFile> dirs)
623 fprintf(stderr, "nsXREDirProvider::GetFilesInternal(%s)\n", key);
625 nsCAutoString path;
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
633 nsresult
634 nsXREDirProvider::GetFilesInternal(const char* aProperty,
635 nsISimpleEnumerator** aResult)
637 nsresult rv = NS_OK;
638 *aResult = nsnull;
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);
683 if (mProfileDir) {
684 nsCOMPtr<nsIFile> overrideFile;
685 mProfileDir->Clone(getter_AddRefs(overrideFile));
686 overrideFile->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
688 PRBool exists;
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);
703 if (mXULAppDir) {
704 nsCOMPtr<nsIFile> file;
705 mXULAppDir->Clone(getter_AddRefs(file));
706 file->AppendNative(NS_LITERAL_CSTRING("chrome"));
707 PRBool exists;
708 if (NS_SUCCEEDED(file->Exists(&exists)) && exists)
709 manifests.AppendObject(file);
712 LoadBundleDirectories();
713 LoadDirsIntoArray(mAppBundleDirectories,
714 kAppendChromeManifests,
715 manifests);
716 LoadDirsIntoArray(mExtensionDirectories,
717 kAppendChromeManifests,
718 manifests);
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,
739 kAppendChromeDir,
740 directories);
741 LoadDirsIntoArray(mAppBundleDirectories,
742 kAppendChromeDir,
743 directories);
744 LoadDirsIntoArray(mExtensionDirectories,
745 kAppendChromeDir,
746 directories);
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,
758 kAppendPlugins,
759 directories);
760 LoadDirsIntoArray(mExtensionDirectories,
761 kAppendPlugins,
762 directories);
764 rv = NS_NewArrayEnumerator(aResult, directories);
765 NS_ENSURE_SUCCESS(rv, rv);
767 rv = NS_SUCCESS_AGGREGATE_RESULT;
769 else
770 rv = NS_ERROR_FAILURE;
772 return rv;
775 NS_IMETHODIMP
776 nsXREDirProvider::GetDirectory(nsIFile* *aResult)
778 NS_ENSURE_TRUE(mProfileDir, NS_ERROR_NOT_INITIALIZED);
780 return mProfileDir->Clone(aResult);
783 NS_IMETHODIMP
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);
797 return NS_OK;
800 class ProfileChangeStatusImpl : public nsIProfileChangeStatus
802 public:
803 NS_DECL_ISUPPORTS
804 NS_DECL_NSIPROFILECHANGESTATUS
805 ProfileChangeStatusImpl() { }
806 private:
807 ~ProfileChangeStatusImpl() { }
810 NS_IMPL_ISUPPORTS1(ProfileChangeStatusImpl, nsIProfileChangeStatus)
812 NS_IMETHODIMP
813 ProfileChangeStatusImpl::VetoChange()
815 NS_ERROR("Can't veto change!");
816 return NS_ERROR_FAILURE;
819 NS_IMETHODIMP
820 ProfileChangeStatusImpl::ChangeFailed()
822 NS_ERROR("Profile change cancellation.");
823 return NS_ERROR_FAILURE;
826 void
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?");
833 if (obssvc) {
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"));
844 if (stack)
846 JSContext *cx = nsnull;
847 stack->GetSafeJSContext(&cx);
848 if (cx)
849 ::JS_GC(cx);
852 // Phase 3: Notify observers of a profile change
853 obssvc->NotifyObservers(cs, "profile-before-change", kShutdownPersist);
855 mProfileNotified = PR_FALSE;
859 #ifdef XP_WIN
860 static nsresult
861 GetShellFolderPath(int folder, nsAString& _retval)
863 LPITEMIDLIST pItemIDList = NULL;
865 PRUnichar* buf;
866 PRUint32 bufLength = _retval.GetMutableData(&buf, MAXPATHLEN);
867 NS_ENSURE_TRUE(bufLength >= MAXPATHLEN, NS_ERROR_OUT_OF_MEMORY);
869 nsresult rv;
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));
876 rv = NS_OK;
877 } else {
878 _retval.SetLength(0);
879 rv = NS_ERROR_NOT_AVAILABLE;
882 CoTaskMemFree(pItemIDList);
884 return rv;
887 nsresult
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
898 nsString longPath;
899 PRUnichar* buf;
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);
909 else
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);
936 return NS_OK;
938 #endif
940 nsresult
941 nsXREDirProvider::GetProfileStartupDir(nsIFile* *aResult)
943 if (mProfileDir)
944 return mProfileDir->Clone(aResult);
946 if (mAppProvider) {
947 nsCOMPtr<nsIFile> needsclone;
948 PRBool dummy;
949 nsresult rv = mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP,
950 &dummy,
951 getter_AddRefs(needsclone));
952 if (NS_SUCCEEDED(rv))
953 return needsclone->Clone(aResult);
956 return NS_ERROR_FAILURE;
959 nsresult
960 nsXREDirProvider::GetProfileDir(nsIFile* *aResult)
962 if (mProfileDir) {
963 if (!mProfileNotified)
964 return NS_ERROR_FAILURE;
966 return mProfileDir->Clone(aResult);
969 if (mAppProvider) {
970 nsCOMPtr<nsIFile> needsclone;
971 PRBool dummy;
972 nsresult rv = mAppProvider->GetFile(NS_APP_USER_PROFILE_50_DIR,
973 &dummy,
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);
982 nsresult
983 nsXREDirProvider::GetUserDataDirectoryHome(nsILocalFile** aFile, PRBool aLocal)
985 if (!gAppData)
986 return NS_ERROR_FAILURE;
988 // Copied from nsAppFileLocationProvider (more or less)
989 nsresult rv;
990 nsCOMPtr<nsILocalFile> localDir;
992 #if defined(XP_MACOSX)
993 FSRef fsRef;
994 OSType folderType;
995 if (aLocal) {
996 folderType = kCachedDataFolderType;
997 } else {
998 #ifdef MOZ_THUNDERBIRD
999 folderType = kDomainLibraryFolderType;
1000 #else
1001 folderType = kApplicationSupportFolderType;
1002 #endif
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)
1018 nsString path;
1019 if (aLocal)
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());
1033 #endif
1034 char *pHome = getenv("MOZILLA_HOME");
1035 if (pHome && *pHome) {
1036 rv = NS_NewNativeLocalFile(nsDependentCString(pHome), PR_TRUE,
1037 getter_AddRefs(localDir));
1038 } else {
1039 PPIB ppib;
1040 PTIB ptib;
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);
1054 appDir[len] = '/';
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));
1066 #else
1067 #error "Don't know how to get product dir on your platform"
1068 #endif
1070 NS_IF_ADDREF(*aFile = localDir);
1071 return rv;
1074 nsresult
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);
1088 return NS_OK;
1091 #if defined(XP_UNIX) || defined(XP_MACOSX)
1092 nsresult
1093 nsXREDirProvider::GetSystemExtensionsDirectory(nsILocalFile** aFile)
1095 nsresult rv;
1096 nsCOMPtr<nsILocalFile> localDir;
1097 #if defined(XP_MACOSX)
1098 FSRef fsRef;
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";
1124 #else
1125 "/usr/lib/mozilla/extensions";
1126 #endif
1128 rv = NS_NewNativeLocalFile(nsDependentCString(sysSExtDir), PR_FALSE,
1129 getter_AddRefs(localDir));
1130 NS_ENSURE_SUCCESS(rv, rv);
1131 #endif
1133 rv = EnsureDirectoryExists(localDir);
1134 NS_ENSURE_SUCCESS(rv, rv);
1136 NS_ADDREF(*aFile = localDir);
1137 return NS_OK;
1139 #endif
1141 nsresult
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
1152 nsCAutoString cwd;
1153 localDir->GetNativePath(cwd);
1154 printf("nsXREDirProvider::GetUserDataDirectory: %s\n", cwd.get());
1155 #endif
1156 rv = EnsureDirectoryExists(localDir);
1157 NS_ENSURE_SUCCESS(rv, rv);
1159 NS_ADDREF(*aFile = localDir);
1160 return NS_OK;
1163 nsresult
1164 nsXREDirProvider::EnsureDirectoryExists(nsIFile* aDirectory)
1166 PRBool exists;
1167 nsresult rv = aDirectory->Exists(&exists);
1168 NS_ENSURE_SUCCESS(rv, rv);
1169 #ifdef DEBUG_jungshik
1170 if (!exists) {
1171 nsCAutoString cwd;
1172 aDirectory->GetNativePath(cwd);
1173 printf("nsXREDirProvider::EnsureDirectoryExists: %s does not\n", cwd.get());
1175 #endif
1176 if (!exists)
1177 rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0700);
1178 #ifdef DEBUG_jungshik
1179 if (NS_FAILED(rv))
1180 NS_WARNING("nsXREDirProvider::EnsureDirectoryExists: create failed");
1181 #endif
1183 return rv;
1186 void
1187 nsXREDirProvider::EnsureProfileFileExists(nsIFile *aFile)
1189 nsresult rv;
1190 PRBool exists;
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());
1209 nsresult
1210 nsXREDirProvider::GetProfileDefaultsDir(nsIFile* *aResult)
1212 NS_ASSERTION(mGREDir, "nsXREDirProvider not initialized.");
1213 NS_PRECONDITION(aResult, "Null out-param");
1215 nsresult rv;
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);
1228 return NS_OK;
1231 nsresult
1232 nsXREDirProvider::AppendSysUserExtensionPath(nsIFile* aFile)
1234 NS_ASSERTION(aFile, "Null pointer!");
1236 nsresult rv;
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);
1258 #else
1259 #error "Don't know how to get XRE user extension path on your platform"
1260 #endif
1261 return NS_OK;
1265 nsresult
1266 nsXREDirProvider::AppendProfilePath(nsIFile* aFile)
1268 NS_ASSERTION(aFile, "Null pointer!");
1270 nsresult rv;
1272 #if defined (XP_MACOSX)
1273 if (gAppData->profile) {
1274 rv = AppendProfileString(aFile, gAppData->profile);
1276 else {
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);
1288 else {
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 == '\\')
1305 profileStart++;
1307 // On the off chance that someone wanted their folder to be hidden don't
1308 // let it become ".."
1309 if (*profileStart == '.')
1310 profileStart++;
1312 folder.Append(profileStart);
1313 ToLowerCase(folder);
1315 rv = AppendProfileString(aFile, folder.BeginReading());
1317 else {
1318 if (gAppData->vendor) {
1319 folder.Append(gAppData->vendor);
1320 ToLowerCase(folder);
1322 rv = aFile->AppendNative(folder);
1323 NS_ENSURE_SUCCESS(rv, rv);
1325 folder.Truncate();
1328 folder.Append(gAppData->name);
1329 ToLowerCase(folder);
1331 rv = aFile->AppendNative(folder);
1333 NS_ENSURE_SUCCESS(rv, rv);
1335 #else
1336 #error "Don't know how to get profile path on your platform"
1337 #endif
1338 return NS_OK;
1341 nsresult
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();
1351 nsresult rv;
1352 char* subdir;
1353 while ((subdir = NS_strtok("/\\", &path))) {
1354 rv = aFile->AppendNative(nsDependentCString(subdir));
1355 NS_ENSURE_SUCCESS(rv, rv);
1358 return NS_OK;