1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsAppFileLocationProvider.h"
8 #include "nsAppDirectoryServiceDefs.h"
9 #include "nsDirectoryServiceDefs.h"
13 #include "nsXPIDLString.h"
14 #include "nsISimpleEnumerator.h"
18 #if defined(MOZ_WIDGET_COCOA)
19 #include <Carbon/Carbon.h>
20 #include "nsILocalFileMac.h"
24 #elif defined(XP_UNIX)
27 #include <sys/param.h>
31 // WARNING: These hard coded names need to go away. They need to
32 // come from localizable resources
34 #if defined(MOZ_WIDGET_COCOA)
35 #define APP_REGISTRY_NAME NS_LITERAL_CSTRING("Application Registry")
36 #define ESSENTIAL_FILES NS_LITERAL_CSTRING("Essential Files")
38 #define APP_REGISTRY_NAME NS_LITERAL_CSTRING("registry.dat")
40 #define APP_REGISTRY_NAME NS_LITERAL_CSTRING("appreg")
43 // define default product directory
44 #define DEFAULT_PRODUCT_DIR NS_LITERAL_CSTRING(MOZ_USER_DIR)
46 // Locally defined keys used by nsAppDirectoryEnumerator
47 #define NS_ENV_PLUGINS_DIR "EnvPlugins" // env var MOZ_PLUGIN_PATH
48 #define NS_USER_PLUGINS_DIR "UserPlugins"
50 #ifdef MOZ_WIDGET_COCOA
51 #define NS_MACOSX_USER_PLUGIN_DIR "OSXUserPlugins"
52 #define NS_MACOSX_LOCAL_PLUGIN_DIR "OSXLocalPlugins"
53 #define NS_MACOSX_JAVA2_PLUGIN_DIR "OSXJavaPlugins"
55 #define NS_SYSTEM_PLUGINS_DIR "SysPlugins"
58 #define DEFAULTS_DIR_NAME NS_LITERAL_CSTRING("defaults")
59 #define DEFAULTS_PREF_DIR_NAME NS_LITERAL_CSTRING("pref")
60 #define DEFAULTS_PROFILE_DIR_NAME NS_LITERAL_CSTRING("profile")
61 #define RES_DIR_NAME NS_LITERAL_CSTRING("res")
62 #define CHROME_DIR_NAME NS_LITERAL_CSTRING("chrome")
63 #define PLUGINS_DIR_NAME NS_LITERAL_CSTRING("plugins")
64 #define SEARCH_DIR_NAME NS_LITERAL_CSTRING("searchplugins")
66 //*****************************************************************************
67 // nsAppFileLocationProvider::Constructor/Destructor
68 //*****************************************************************************
70 nsAppFileLocationProvider::nsAppFileLocationProvider()
74 //*****************************************************************************
75 // nsAppFileLocationProvider::nsISupports
76 //*****************************************************************************
78 NS_IMPL_ISUPPORTS(nsAppFileLocationProvider
,
79 nsIDirectoryServiceProvider
,
80 nsIDirectoryServiceProvider2
)
82 //*****************************************************************************
83 // nsAppFileLocationProvider::nsIDirectoryServiceProvider
84 //*****************************************************************************
87 nsAppFileLocationProvider::GetFile(const char* aProp
, bool* aPersistent
,
90 if (NS_WARN_IF(!aProp
)) {
91 return NS_ERROR_INVALID_ARG
;
94 nsCOMPtr
<nsIFile
> localFile
;
95 nsresult rv
= NS_ERROR_FAILURE
;
100 #ifdef MOZ_WIDGET_COCOA
102 nsCOMPtr
<nsILocalFileMac
> macFile
;
105 if (nsCRT::strcmp(aProp
, NS_APP_APPLICATION_REGISTRY_DIR
) == 0) {
106 rv
= GetProductDirectory(getter_AddRefs(localFile
));
107 } else if (nsCRT::strcmp(aProp
, NS_APP_APPLICATION_REGISTRY_FILE
) == 0) {
108 rv
= GetProductDirectory(getter_AddRefs(localFile
));
109 if (NS_SUCCEEDED(rv
)) {
110 rv
= localFile
->AppendNative(APP_REGISTRY_NAME
);
112 } else if (nsCRT::strcmp(aProp
, NS_APP_DEFAULTS_50_DIR
) == 0) {
113 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
114 if (NS_SUCCEEDED(rv
)) {
115 rv
= localFile
->AppendRelativeNativePath(DEFAULTS_DIR_NAME
);
117 } else if (nsCRT::strcmp(aProp
, NS_APP_PREF_DEFAULTS_50_DIR
) == 0) {
118 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
119 if (NS_SUCCEEDED(rv
)) {
120 rv
= localFile
->AppendRelativeNativePath(DEFAULTS_DIR_NAME
);
121 if (NS_SUCCEEDED(rv
)) {
122 rv
= localFile
->AppendRelativeNativePath(DEFAULTS_PREF_DIR_NAME
);
125 } else if (nsCRT::strcmp(aProp
, NS_APP_PROFILE_DEFAULTS_50_DIR
) == 0 ||
126 nsCRT::strcmp(aProp
, NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR
) == 0) {
127 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
128 if (NS_SUCCEEDED(rv
)) {
129 rv
= localFile
->AppendRelativeNativePath(DEFAULTS_DIR_NAME
);
130 if (NS_SUCCEEDED(rv
)) {
131 rv
= localFile
->AppendRelativeNativePath(DEFAULTS_PROFILE_DIR_NAME
);
134 } else if (nsCRT::strcmp(aProp
, NS_APP_USER_PROFILES_ROOT_DIR
) == 0) {
135 rv
= GetDefaultUserProfileRoot(getter_AddRefs(localFile
));
136 } else if (nsCRT::strcmp(aProp
, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR
) == 0) {
137 rv
= GetDefaultUserProfileRoot(getter_AddRefs(localFile
), true);
138 } else if (nsCRT::strcmp(aProp
, NS_APP_RES_DIR
) == 0) {
139 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
140 if (NS_SUCCEEDED(rv
)) {
141 rv
= localFile
->AppendRelativeNativePath(RES_DIR_NAME
);
143 } else if (nsCRT::strcmp(aProp
, NS_APP_CHROME_DIR
) == 0) {
144 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
145 if (NS_SUCCEEDED(rv
)) {
146 rv
= localFile
->AppendRelativeNativePath(CHROME_DIR_NAME
);
148 } else if (nsCRT::strcmp(aProp
, NS_APP_PLUGINS_DIR
) == 0) {
149 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
150 if (NS_SUCCEEDED(rv
)) {
151 rv
= localFile
->AppendRelativeNativePath(PLUGINS_DIR_NAME
);
154 #ifdef MOZ_WIDGET_COCOA
155 else if (nsCRT::strcmp(aProp
, NS_MACOSX_USER_PLUGIN_DIR
) == 0) {
156 if (::FSFindFolder(kUserDomain
, kInternetPlugInFolderType
, false,
157 &fileRef
) == noErr
) {
158 rv
= NS_NewLocalFileWithFSRef(&fileRef
, true, getter_AddRefs(macFile
));
159 if (NS_SUCCEEDED(rv
)) {
163 } else if (nsCRT::strcmp(aProp
, NS_MACOSX_LOCAL_PLUGIN_DIR
) == 0) {
164 if (::FSFindFolder(kLocalDomain
, kInternetPlugInFolderType
, false,
165 &fileRef
) == noErr
) {
166 rv
= NS_NewLocalFileWithFSRef(&fileRef
, true, getter_AddRefs(macFile
));
167 if (NS_SUCCEEDED(rv
)) {
171 } else if (nsCRT::strcmp(aProp
, NS_MACOSX_JAVA2_PLUGIN_DIR
) == 0) {
172 static const char* const java2PluginDirPath
=
173 "/System/Library/Java/Support/Deploy.bundle/Contents/Resources/";
174 rv
= NS_NewNativeLocalFile(nsDependentCString(java2PluginDirPath
), true,
175 getter_AddRefs(localFile
));
178 else if (nsCRT::strcmp(aProp
, NS_ENV_PLUGINS_DIR
) == 0) {
179 NS_ERROR("Don't use nsAppFileLocationProvider::GetFile(NS_ENV_PLUGINS_DIR, ...). "
180 "Use nsAppFileLocationProvider::GetFiles(...).");
181 const char* pathVar
= PR_GetEnv("MOZ_PLUGIN_PATH");
182 if (pathVar
&& *pathVar
)
183 rv
= NS_NewNativeLocalFile(nsDependentCString(pathVar
), true,
184 getter_AddRefs(localFile
));
185 } else if (nsCRT::strcmp(aProp
, NS_USER_PLUGINS_DIR
) == 0) {
186 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
187 rv
= GetProductDirectory(getter_AddRefs(localFile
));
188 if (NS_SUCCEEDED(rv
)) {
189 rv
= localFile
->AppendRelativeNativePath(PLUGINS_DIR_NAME
);
192 rv
= NS_ERROR_FAILURE
;
196 else if (nsCRT::strcmp(aProp
, NS_SYSTEM_PLUGINS_DIR
) == 0) {
197 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
198 static const char* const sysLPlgDir
=
199 #if defined(HAVE_USR_LIB64_DIR) && defined(__LP64__)
200 "/usr/lib64/mozilla/plugins";
201 #elif defined(__OpenBSD__) || defined (__FreeBSD__)
202 "/usr/local/lib/mozilla/plugins";
204 "/usr/lib/mozilla/plugins";
206 rv
= NS_NewNativeLocalFile(nsDependentCString(sysLPlgDir
),
207 false, getter_AddRefs(localFile
));
209 rv
= NS_ERROR_FAILURE
;
214 else if (nsCRT::strcmp(aProp
, NS_APP_SEARCH_DIR
) == 0) {
215 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
216 if (NS_SUCCEEDED(rv
)) {
217 rv
= localFile
->AppendRelativeNativePath(SEARCH_DIR_NAME
);
219 } else if (nsCRT::strcmp(aProp
, NS_APP_USER_SEARCH_DIR
) == 0) {
220 rv
= NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR
, aResult
);
221 if (NS_SUCCEEDED(rv
)) {
222 rv
= (*aResult
)->AppendNative(SEARCH_DIR_NAME
);
224 } else if (nsCRT::strcmp(aProp
, NS_APP_INSTALL_CLEANUP_DIR
) == 0) {
225 // This is cloned so that embeddors will have a hook to override
226 // with their own cleanup dir. See bugzilla bug #105087
227 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
230 if (localFile
&& NS_SUCCEEDED(rv
)) {
231 return localFile
->QueryInterface(NS_GET_IID(nsIFile
), (void**)aResult
);
239 nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile
** aLocalFile
)
241 if (NS_WARN_IF(!aLocalFile
)) {
242 return NS_ERROR_INVALID_ARG
;
246 if (!mMozBinDirectory
) {
247 // Get the mozilla bin directory
248 // 1. Check the directory service first for NS_XPCOM_CURRENT_PROCESS_DIR
249 // This will be set if a directory was passed to NS_InitXPCOM
250 // 2. If that doesn't work, set it to be the current process directory
251 nsCOMPtr
<nsIProperties
>
252 directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
, &rv
));
257 rv
= directoryService
->Get(NS_XPCOM_CURRENT_PROCESS_DIR
, NS_GET_IID(nsIFile
),
258 getter_AddRefs(mMozBinDirectory
));
260 rv
= directoryService
->Get(NS_OS_CURRENT_PROCESS_DIR
, NS_GET_IID(nsIFile
),
261 getter_AddRefs(mMozBinDirectory
));
268 nsCOMPtr
<nsIFile
> aFile
;
269 rv
= mMozBinDirectory
->Clone(getter_AddRefs(aFile
));
274 NS_IF_ADDREF(*aLocalFile
= aFile
);
279 //----------------------------------------------------------------------------------------
280 // GetProductDirectory - Gets the directory which contains the application data folder
282 // UNIX : ~/.mozilla/
283 // WIN : <Application Data folder on user's machine>\Mozilla
284 // Mac : :Documents:Mozilla:
285 //----------------------------------------------------------------------------------------
287 nsAppFileLocationProvider::GetProductDirectory(nsIFile
** aLocalFile
,
290 if (NS_WARN_IF(!aLocalFile
)) {
291 return NS_ERROR_INVALID_ARG
;
296 nsCOMPtr
<nsIFile
> localDir
;
298 #if defined(MOZ_WIDGET_COCOA)
300 OSType folderType
= aLocal
? (OSType
)kCachedDataFolderType
:
301 (OSType
)kDomainLibraryFolderType
;
302 OSErr err
= ::FSFindFolder(kUserDomain
, folderType
, kCreateFolder
, &fsRef
);
304 return NS_ERROR_FAILURE
;
306 NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localDir
));
308 return NS_ERROR_FAILURE
;
310 nsCOMPtr
<nsILocalFileMac
> localDirMac(do_QueryInterface(localDir
));
311 rv
= localDirMac
->InitWithFSRef(&fsRef
);
315 #elif defined(XP_WIN)
316 nsCOMPtr
<nsIProperties
> directoryService
=
317 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
, &rv
);
321 const char* prop
= aLocal
? NS_WIN_LOCAL_APPDATA_DIR
: NS_WIN_APPDATA_DIR
;
322 rv
= directoryService
->Get(prop
, NS_GET_IID(nsIFile
), getter_AddRefs(localDir
));
326 #elif defined(XP_UNIX)
327 rv
= NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), true,
328 getter_AddRefs(localDir
));
333 #error dont_know_how_to_get_product_dir_on_your_platform
336 rv
= localDir
->AppendRelativeNativePath(DEFAULT_PRODUCT_DIR
);
340 rv
= localDir
->Exists(&exists
);
342 if (NS_SUCCEEDED(rv
) && !exists
) {
343 rv
= localDir
->Create(nsIFile::DIRECTORY_TYPE
, 0700);
350 *aLocalFile
= localDir
;
351 NS_ADDREF(*aLocalFile
);
357 //----------------------------------------------------------------------------------------
358 // GetDefaultUserProfileRoot - Gets the directory which contains each user profile dir
360 // UNIX : ~/.mozilla/
361 // WIN : <Application Data folder on user's machine>\Mozilla\Profiles
362 // Mac : :Documents:Mozilla:Profiles:
363 //----------------------------------------------------------------------------------------
365 nsAppFileLocationProvider::GetDefaultUserProfileRoot(nsIFile
** aLocalFile
,
368 if (NS_WARN_IF(!aLocalFile
)) {
369 return NS_ERROR_INVALID_ARG
;
373 nsCOMPtr
<nsIFile
> localDir
;
375 rv
= GetProductDirectory(getter_AddRefs(localDir
), aLocal
);
380 #if defined(MOZ_WIDGET_COCOA) || defined(XP_WIN)
381 // These 3 platforms share this part of the path - do them as one
382 rv
= localDir
->AppendRelativeNativePath(NS_LITERAL_CSTRING("Profiles"));
388 rv
= localDir
->Exists(&exists
);
389 if (NS_SUCCEEDED(rv
) && !exists
) {
390 rv
= localDir
->Create(nsIFile::DIRECTORY_TYPE
, 0775);
397 *aLocalFile
= localDir
;
398 NS_ADDREF(*aLocalFile
);
403 //*****************************************************************************
404 // nsAppFileLocationProvider::nsIDirectoryServiceProvider2
405 //*****************************************************************************
407 class nsAppDirectoryEnumerator
: public nsISimpleEnumerator
413 * aKeyList is a null-terminated list of properties which are provided by aProvider
414 * They do not need to be publicly defined keys.
416 nsAppDirectoryEnumerator(nsIDirectoryServiceProvider
* aProvider
,
417 const char* aKeyList
[]) :
418 mProvider(aProvider
),
419 mCurrentKey(aKeyList
)
423 NS_IMETHOD
HasMoreElements(bool* aResult
)
425 while (!mNext
&& *mCurrentKey
) {
427 nsCOMPtr
<nsIFile
> testFile
;
428 (void)mProvider
->GetFile(*mCurrentKey
++, &dontCare
, getter_AddRefs(testFile
));
429 // Don't return a file which does not exist.
431 if (testFile
&& NS_SUCCEEDED(testFile
->Exists(&exists
)) && exists
) {
435 *aResult
= mNext
!= nullptr;
439 NS_IMETHOD
GetNext(nsISupports
** aResult
)
441 if (NS_WARN_IF(!aResult
)) {
442 return NS_ERROR_INVALID_ARG
;
447 HasMoreElements(&hasMore
);
449 return NS_ERROR_FAILURE
;
453 NS_IF_ADDREF(*aResult
);
456 return *aResult
? NS_OK
: NS_ERROR_FAILURE
;
460 nsIDirectoryServiceProvider
* mProvider
;
461 const char** mCurrentKey
;
462 nsCOMPtr
<nsIFile
> mNext
;
464 // Virtual destructor since subclass nsPathsDirectoryEnumerator
465 // does not re-implement Release()
466 virtual ~nsAppDirectoryEnumerator()
471 NS_IMPL_ISUPPORTS(nsAppDirectoryEnumerator
, nsISimpleEnumerator
)
473 /* nsPathsDirectoryEnumerator and PATH_SEPARATOR
474 * are not used on MacOS/X. */
476 #if defined(XP_WIN) /* Win32 */
477 #define PATH_SEPARATOR ';'
479 #define PATH_SEPARATOR ':'
482 class nsPathsDirectoryEnumerator MOZ_FINAL
483 : public nsAppDirectoryEnumerator
485 ~nsPathsDirectoryEnumerator() {}
489 * aKeyList is a null-terminated list.
490 * The first element is a path list.
491 * The remainder are properties provided by aProvider.
492 * They do not need to be publicly defined keys.
494 nsPathsDirectoryEnumerator(nsIDirectoryServiceProvider
* aProvider
,
495 const char* aKeyList
[]) :
496 nsAppDirectoryEnumerator(aProvider
, aKeyList
+ 1),
497 mEndPath(aKeyList
[0])
501 NS_IMETHOD
HasMoreElements(bool* aResult
)
504 while (!mNext
&& *mEndPath
) {
505 const char* pathVar
= mEndPath
;
507 // skip PATH_SEPARATORs at the begining of the mEndPath
508 while (*pathVar
== PATH_SEPARATOR
) {
514 } while (*mEndPath
&& *mEndPath
!= PATH_SEPARATOR
);
516 nsCOMPtr
<nsIFile
> localFile
;
517 NS_NewNativeLocalFile(Substring(pathVar
, mEndPath
),
519 getter_AddRefs(localFile
));
520 if (*mEndPath
== PATH_SEPARATOR
) {
523 // Don't return a "file" (directory) which does not exist.
526 NS_SUCCEEDED(localFile
->Exists(&exists
)) &&
534 nsAppDirectoryEnumerator::HasMoreElements(aResult
);
541 const char* mEndPath
;
545 nsAppFileLocationProvider::GetFiles(const char* aProp
,
546 nsISimpleEnumerator
** aResult
)
548 if (NS_WARN_IF(!aResult
)) {
549 return NS_ERROR_INVALID_ARG
;
552 nsresult rv
= NS_ERROR_FAILURE
;
554 if (!nsCRT::strcmp(aProp
, NS_APP_PLUGINS_DIR_LIST
)) {
555 #ifdef MOZ_WIDGET_COCOA
556 // As of Java for Mac OS X 10.5 Update 10, Apple has (in effect) deprecated Java Plugin2 on
557 // on OS X 10.5, and removed the soft link to it from /Library/Internet Plug-Ins/. Java
558 // Plugin2 is still present and usable, but there are no longer any links to it in the
559 // "normal" locations. So we won't be able to find it unless we look in the "non-normal"
560 // location where it actually is. Safari can use the WebKit-specific JavaPluginCocoa.bundle,
561 // which (of course) is still fully supported on OS X 10.5. But we have no alternative to
562 // using Java Plugin2. For more information see bug 668639.
563 static const char* keys
[] = {
565 NS_MACOSX_USER_PLUGIN_DIR
,
566 NS_MACOSX_LOCAL_PLUGIN_DIR
,
567 IsOSXLeopard() ? NS_MACOSX_JAVA2_PLUGIN_DIR
: nullptr,
570 *aResult
= new nsAppDirectoryEnumerator(this, keys
);
573 static const char* keys
[] = { nullptr, NS_USER_PLUGINS_DIR
, NS_APP_PLUGINS_DIR
, NS_SYSTEM_PLUGINS_DIR
, nullptr };
575 static const char* keys
[] = { nullptr, NS_USER_PLUGINS_DIR
, NS_APP_PLUGINS_DIR
, nullptr };
577 if (!keys
[0] && !(keys
[0] = PR_GetEnv("MOZ_PLUGIN_PATH"))) {
578 static const char nullstr
= 0;
581 *aResult
= new nsPathsDirectoryEnumerator(this, keys
);
583 NS_IF_ADDREF(*aResult
);
584 rv
= *aResult
? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
586 if (!nsCRT::strcmp(aProp
, NS_APP_SEARCH_DIR_LIST
)) {
587 static const char* keys
[] = { nullptr, NS_APP_SEARCH_DIR
, NS_APP_USER_SEARCH_DIR
, nullptr };
588 if (!keys
[0] && !(keys
[0] = PR_GetEnv("MOZ_SEARCH_ENGINE_PATH"))) {
589 static const char nullstr
= 0;
592 *aResult
= new nsPathsDirectoryEnumerator(this, keys
);
593 NS_IF_ADDREF(*aResult
);
594 rv
= *aResult
? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
599 #if defined(MOZ_WIDGET_COCOA)
601 nsAppFileLocationProvider::IsOSXLeopard()
603 static SInt32 version
= 0;
606 OSErr err
= ::Gestalt(gestaltSystemVersion
, &version
);
610 version
&= 0xFFFF; // The system version is in the low order word
614 return ((version
>= 0x1050) && (version
< 0x1060));