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"
10 #include "nsEnumeratorUtils.h"
12 #include "nsIDirectoryService.h"
15 #include "nsSimpleEnumerator.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>
30 // WARNING: These hard coded names need to go away. They need to
31 // come from localizable resources
33 #if defined(MOZ_WIDGET_COCOA)
34 # define APP_REGISTRY_NAME "Application Registry"_ns
35 # define ESSENTIAL_FILES "Essential Files"_ns
37 # define APP_REGISTRY_NAME "registry.dat"_ns
39 # define APP_REGISTRY_NAME "appreg"_ns
42 // define default product directory
43 #define DEFAULT_PRODUCT_DIR nsLiteralCString(MOZ_USER_DIR)
45 // Locally defined keys used by nsAppDirectoryEnumerator
46 #define NS_USER_PLUGINS_DIR "UserPlugins"
48 #ifdef MOZ_WIDGET_COCOA
49 # define NS_MACOSX_USER_PLUGIN_DIR "OSXUserPlugins"
50 # define NS_MACOSX_LOCAL_PLUGIN_DIR "OSXLocalPlugins"
52 # define NS_SYSTEM_PLUGINS_DIR "SysPlugins"
55 #define DEFAULTS_DIR_NAME "defaults"_ns
56 #define DEFAULTS_PREF_DIR_NAME "pref"_ns
57 #define RES_DIR_NAME "res"_ns
58 #define CHROME_DIR_NAME "chrome"_ns
59 #define PLUGINS_DIR_NAME "plugins"_ns
61 //*****************************************************************************
62 // nsAppFileLocationProvider::Constructor/Destructor
63 //*****************************************************************************
65 nsAppFileLocationProvider::nsAppFileLocationProvider() = default;
67 //*****************************************************************************
68 // nsAppFileLocationProvider::nsISupports
69 //*****************************************************************************
71 NS_IMPL_ISUPPORTS(nsAppFileLocationProvider
, nsIDirectoryServiceProvider
,
72 nsIDirectoryServiceProvider2
)
74 //*****************************************************************************
75 // nsAppFileLocationProvider::nsIDirectoryServiceProvider
76 //*****************************************************************************
79 nsAppFileLocationProvider::GetFile(const char* aProp
, bool* aPersistent
,
81 if (NS_WARN_IF(!aProp
)) {
82 return NS_ERROR_INVALID_ARG
;
85 nsCOMPtr
<nsIFile
> localFile
;
86 nsresult rv
= NS_ERROR_FAILURE
;
91 #ifdef MOZ_WIDGET_COCOA
93 nsCOMPtr
<nsILocalFileMac
> macFile
;
96 if (nsCRT::strcmp(aProp
, NS_APP_APPLICATION_REGISTRY_DIR
) == 0) {
97 rv
= GetProductDirectory(getter_AddRefs(localFile
));
98 } else if (nsCRT::strcmp(aProp
, NS_APP_APPLICATION_REGISTRY_FILE
) == 0) {
99 rv
= GetProductDirectory(getter_AddRefs(localFile
));
100 if (NS_SUCCEEDED(rv
)) {
101 rv
= localFile
->AppendNative(APP_REGISTRY_NAME
);
103 } else if (nsCRT::strcmp(aProp
, NS_APP_DEFAULTS_50_DIR
) == 0) {
104 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
105 if (NS_SUCCEEDED(rv
)) {
106 rv
= localFile
->AppendRelativeNativePath(DEFAULTS_DIR_NAME
);
108 } else if (nsCRT::strcmp(aProp
, NS_APP_PREF_DEFAULTS_50_DIR
) == 0) {
109 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
110 if (NS_SUCCEEDED(rv
)) {
111 rv
= localFile
->AppendRelativeNativePath(DEFAULTS_DIR_NAME
);
112 if (NS_SUCCEEDED(rv
)) {
113 rv
= localFile
->AppendRelativeNativePath(DEFAULTS_PREF_DIR_NAME
);
116 } else if (nsCRT::strcmp(aProp
, NS_APP_USER_PROFILES_ROOT_DIR
) == 0) {
117 rv
= GetDefaultUserProfileRoot(getter_AddRefs(localFile
));
118 } else if (nsCRT::strcmp(aProp
, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR
) == 0) {
119 rv
= GetDefaultUserProfileRoot(getter_AddRefs(localFile
), true);
120 } else if (nsCRT::strcmp(aProp
, NS_APP_RES_DIR
) == 0) {
121 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
122 if (NS_SUCCEEDED(rv
)) {
123 rv
= localFile
->AppendRelativeNativePath(RES_DIR_NAME
);
125 } else if (nsCRT::strcmp(aProp
, NS_APP_CHROME_DIR
) == 0) {
126 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
127 if (NS_SUCCEEDED(rv
)) {
128 rv
= localFile
->AppendRelativeNativePath(CHROME_DIR_NAME
);
131 #ifdef MOZ_WIDGET_COCOA
132 else if (nsCRT::strcmp(aProp
, NS_MACOSX_USER_PLUGIN_DIR
) == 0) {
133 if (::FSFindFolder(kUserDomain
, kInternetPlugInFolderType
, false,
134 &fileRef
) == noErr
) {
135 rv
= NS_NewLocalFileWithFSRef(&fileRef
, true, getter_AddRefs(macFile
));
136 if (NS_SUCCEEDED(rv
)) {
140 } else if (nsCRT::strcmp(aProp
, NS_MACOSX_LOCAL_PLUGIN_DIR
) == 0) {
141 if (::FSFindFolder(kLocalDomain
, kInternetPlugInFolderType
, false,
142 &fileRef
) == noErr
) {
143 rv
= NS_NewLocalFileWithFSRef(&fileRef
, true, getter_AddRefs(macFile
));
144 if (NS_SUCCEEDED(rv
)) {
150 else if (nsCRT::strcmp(aProp
, NS_USER_PLUGINS_DIR
) == 0) {
151 # ifdef ENABLE_SYSTEM_EXTENSION_DIRS
152 rv
= GetProductDirectory(getter_AddRefs(localFile
));
153 if (NS_SUCCEEDED(rv
)) {
154 rv
= localFile
->AppendRelativeNativePath(PLUGINS_DIR_NAME
);
157 rv
= NS_ERROR_FAILURE
;
161 else if (nsCRT::strcmp(aProp
, NS_SYSTEM_PLUGINS_DIR
) == 0) {
162 # ifdef ENABLE_SYSTEM_EXTENSION_DIRS
163 static const char* const sysLPlgDir
=
164 # if defined(HAVE_USR_LIB64_DIR) && defined(__LP64__)
165 "/usr/lib64/mozilla/plugins";
166 # elif defined(__OpenBSD__) || defined(__FreeBSD__)
167 "/usr/local/lib/mozilla/plugins";
169 "/usr/lib/mozilla/plugins";
171 rv
= NS_NewNativeLocalFile(nsDependentCString(sysLPlgDir
), false,
172 getter_AddRefs(localFile
));
174 rv
= NS_ERROR_FAILURE
;
179 else if (nsCRT::strcmp(aProp
, NS_APP_INSTALL_CLEANUP_DIR
) == 0) {
180 // This is cloned so that embeddors will have a hook to override
181 // with their own cleanup dir. See bugzilla bug #105087
182 rv
= CloneMozBinDirectory(getter_AddRefs(localFile
));
185 if (localFile
&& NS_SUCCEEDED(rv
)) {
186 localFile
.forget(aResult
);
193 nsresult
nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile
** aLocalFile
) {
194 if (NS_WARN_IF(!aLocalFile
)) {
195 return NS_ERROR_INVALID_ARG
;
199 if (!mMozBinDirectory
) {
200 // Get the mozilla bin directory
201 // 1. Check the directory service first for NS_XPCOM_CURRENT_PROCESS_DIR
202 // This will be set if a directory was passed to NS_InitXPCOM
203 // 2. If that doesn't work, set it to be the current process directory
204 nsCOMPtr
<nsIProperties
> directoryService(
205 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
, &rv
));
211 directoryService
->Get(NS_XPCOM_CURRENT_PROCESS_DIR
, NS_GET_IID(nsIFile
),
212 getter_AddRefs(mMozBinDirectory
));
214 rv
= directoryService
->Get(NS_OS_CURRENT_PROCESS_DIR
, NS_GET_IID(nsIFile
),
215 getter_AddRefs(mMozBinDirectory
));
222 nsCOMPtr
<nsIFile
> aFile
;
223 rv
= mMozBinDirectory
->Clone(getter_AddRefs(aFile
));
228 NS_IF_ADDREF(*aLocalFile
= aFile
);
232 //----------------------------------------------------------------------------------------
233 // GetProductDirectory - Gets the directory which contains the application data
236 // UNIX : ~/.mozilla/
237 // WIN : <Application Data folder on user's machine>\Mozilla
238 // Mac : :Documents:Mozilla:
239 //----------------------------------------------------------------------------------------
240 nsresult
nsAppFileLocationProvider::GetProductDirectory(nsIFile
** aLocalFile
,
242 if (NS_WARN_IF(!aLocalFile
)) {
243 return NS_ERROR_INVALID_ARG
;
248 nsCOMPtr
<nsIFile
> localDir
;
250 #if defined(MOZ_WIDGET_COCOA)
253 aLocal
? (OSType
)kCachedDataFolderType
: (OSType
)kDomainLibraryFolderType
;
254 OSErr err
= ::FSFindFolder(kUserDomain
, folderType
, kCreateFolder
, &fsRef
);
256 return NS_ERROR_FAILURE
;
258 NS_NewLocalFile(u
""_ns
, true, getter_AddRefs(localDir
));
260 return NS_ERROR_FAILURE
;
262 nsCOMPtr
<nsILocalFileMac
> localDirMac(do_QueryInterface(localDir
));
263 rv
= localDirMac
->InitWithFSRef(&fsRef
);
267 #elif defined(XP_WIN)
268 nsCOMPtr
<nsIProperties
> directoryService
=
269 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
, &rv
);
273 const char* prop
= aLocal
? NS_WIN_LOCAL_APPDATA_DIR
: NS_WIN_APPDATA_DIR
;
274 rv
= directoryService
->Get(prop
, NS_GET_IID(nsIFile
),
275 getter_AddRefs(localDir
));
279 #elif defined(XP_UNIX)
280 rv
= NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), true,
281 getter_AddRefs(localDir
));
286 # error dont_know_how_to_get_product_dir_on_your_platform
289 rv
= localDir
->AppendRelativeNativePath(DEFAULT_PRODUCT_DIR
);
293 rv
= localDir
->Exists(&exists
);
295 if (NS_SUCCEEDED(rv
) && !exists
) {
296 rv
= localDir
->Create(nsIFile::DIRECTORY_TYPE
, 0700);
303 localDir
.forget(aLocalFile
);
308 //----------------------------------------------------------------------------------------
309 // GetDefaultUserProfileRoot - Gets the directory which contains each user
312 // UNIX : ~/.mozilla/
313 // WIN : <Application Data folder on user's machine>\Mozilla\Profiles
314 // Mac : :Documents:Mozilla:Profiles:
315 //----------------------------------------------------------------------------------------
316 nsresult
nsAppFileLocationProvider::GetDefaultUserProfileRoot(
317 nsIFile
** aLocalFile
, bool aLocal
) {
318 if (NS_WARN_IF(!aLocalFile
)) {
319 return NS_ERROR_INVALID_ARG
;
323 nsCOMPtr
<nsIFile
> localDir
;
325 rv
= GetProductDirectory(getter_AddRefs(localDir
), aLocal
);
330 #if defined(MOZ_WIDGET_COCOA) || defined(XP_WIN)
331 // These 3 platforms share this part of the path - do them as one
332 rv
= localDir
->AppendRelativeNativePath("Profiles"_ns
);
338 rv
= localDir
->Exists(&exists
);
339 if (NS_SUCCEEDED(rv
) && !exists
) {
340 rv
= localDir
->Create(nsIFile::DIRECTORY_TYPE
, 0775);
347 localDir
.forget(aLocalFile
);
352 //*****************************************************************************
353 // nsAppFileLocationProvider::nsIDirectoryServiceProvider2
354 //*****************************************************************************
356 class nsAppDirectoryEnumerator
: public nsSimpleEnumerator
{
359 * aKeyList is a null-terminated list of properties which are provided by
360 * aProvider They do not need to be publicly defined keys.
362 nsAppDirectoryEnumerator(nsIDirectoryServiceProvider
* aProvider
,
363 const char* aKeyList
[])
364 : mProvider(aProvider
), mCurrentKey(aKeyList
) {}
366 const nsID
& DefaultInterface() override
{ return NS_GET_IID(nsIFile
); }
368 NS_IMETHOD
HasMoreElements(bool* aResult
) override
{
369 while (!mNext
&& *mCurrentKey
) {
371 nsCOMPtr
<nsIFile
> testFile
;
372 (void)mProvider
->GetFile(*mCurrentKey
++, &dontCare
,
373 getter_AddRefs(testFile
));
376 *aResult
= mNext
!= nullptr;
380 NS_IMETHOD
GetNext(nsISupports
** aResult
) override
{
381 if (NS_WARN_IF(!aResult
)) {
382 return NS_ERROR_INVALID_ARG
;
387 HasMoreElements(&hasMore
);
389 return NS_ERROR_FAILURE
;
393 NS_IF_ADDREF(*aResult
);
396 return *aResult
? NS_OK
: NS_ERROR_FAILURE
;
400 nsCOMPtr
<nsIDirectoryServiceProvider
> mProvider
;
401 const char** mCurrentKey
;
402 nsCOMPtr
<nsIFile
> mNext
;
406 nsAppFileLocationProvider::GetFiles(const char* aProp
,
407 nsISimpleEnumerator
** aResult
) {
408 if (NS_WARN_IF(!aResult
)) {
409 return NS_ERROR_INVALID_ARG
;
412 nsresult rv
= NS_ERROR_FAILURE
;
414 if (!nsCRT::strcmp(aProp
, NS_APP_PLUGINS_DIR_LIST
)) {
415 #ifdef MOZ_WIDGET_COCOA
416 static const char* keys
[] = {NS_MACOSX_USER_PLUGIN_DIR
,
417 NS_MACOSX_LOCAL_PLUGIN_DIR
, nullptr};
420 static const char* keys
[] = {NS_USER_PLUGINS_DIR
, NS_SYSTEM_PLUGINS_DIR
,
423 static const char* keys
[] = {NS_USER_PLUGINS_DIR
, nullptr};
426 *aResult
= new nsAppDirectoryEnumerator(this, keys
);