Bug 1690340 - Part 4: Insert the "Page Source" before the "Extensions for Developers...
[gecko.git] / xpcom / io / nsAppFileLocationProvider.cpp
blobef974f99048f80995bdd8cd0ed0141b6d9af4771
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"
11 #include "nsAtom.h"
12 #include "nsIDirectoryService.h"
13 #include "nsIFile.h"
14 #include "nsString.h"
15 #include "nsSimpleEnumerator.h"
16 #include "prenv.h"
17 #include "nsCRT.h"
18 #if defined(MOZ_WIDGET_COCOA)
19 # include <Carbon/Carbon.h>
20 # include "nsILocalFileMac.h"
21 #elif defined(XP_WIN)
22 # include <windows.h>
23 # include <shlobj.h>
24 #elif defined(XP_UNIX)
25 # include <unistd.h>
26 # include <stdlib.h>
27 # include <sys/param.h>
28 #endif
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
36 #elif defined(XP_WIN)
37 # define APP_REGISTRY_NAME "registry.dat"_ns
38 #else
39 # define APP_REGISTRY_NAME "appreg"_ns
40 #endif
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"
51 #elif XP_UNIX
52 # define NS_SYSTEM_PLUGINS_DIR "SysPlugins"
53 #endif
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 //*****************************************************************************
78 NS_IMETHODIMP
79 nsAppFileLocationProvider::GetFile(const char* aProp, bool* aPersistent,
80 nsIFile** aResult) {
81 if (NS_WARN_IF(!aProp)) {
82 return NS_ERROR_INVALID_ARG;
85 nsCOMPtr<nsIFile> localFile;
86 nsresult rv = NS_ERROR_FAILURE;
88 *aResult = nullptr;
89 *aPersistent = true;
91 #ifdef MOZ_WIDGET_COCOA
92 FSRef fileRef;
93 nsCOMPtr<nsILocalFileMac> macFile;
94 #endif
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)) {
137 localFile = macFile;
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)) {
145 localFile = macFile;
149 #else
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);
156 # else
157 rv = NS_ERROR_FAILURE;
158 # endif
160 # ifdef XP_UNIX
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";
168 # else
169 "/usr/lib/mozilla/plugins";
170 # endif
171 rv = NS_NewNativeLocalFile(nsDependentCString(sysLPlgDir), false,
172 getter_AddRefs(localFile));
173 # else
174 rv = NS_ERROR_FAILURE;
175 # endif
177 # endif
178 #endif
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);
187 return NS_OK;
190 return rv;
193 nsresult nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile** aLocalFile) {
194 if (NS_WARN_IF(!aLocalFile)) {
195 return NS_ERROR_INVALID_ARG;
197 nsresult rv;
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));
206 if (NS_FAILED(rv)) {
207 return rv;
210 rv =
211 directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile),
212 getter_AddRefs(mMozBinDirectory));
213 if (NS_FAILED(rv)) {
214 rv = directoryService->Get(NS_OS_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile),
215 getter_AddRefs(mMozBinDirectory));
216 if (NS_FAILED(rv)) {
217 return rv;
222 nsCOMPtr<nsIFile> aFile;
223 rv = mMozBinDirectory->Clone(getter_AddRefs(aFile));
224 if (NS_FAILED(rv)) {
225 return rv;
228 NS_IF_ADDREF(*aLocalFile = aFile);
229 return NS_OK;
232 //----------------------------------------------------------------------------------------
233 // GetProductDirectory - Gets the directory which contains the application data
234 // folder
236 // UNIX : ~/.mozilla/
237 // WIN : <Application Data folder on user's machine>\Mozilla
238 // Mac : :Documents:Mozilla:
239 //----------------------------------------------------------------------------------------
240 nsresult nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
241 bool aLocal) {
242 if (NS_WARN_IF(!aLocalFile)) {
243 return NS_ERROR_INVALID_ARG;
246 nsresult rv;
247 bool exists;
248 nsCOMPtr<nsIFile> localDir;
250 #if defined(MOZ_WIDGET_COCOA)
251 FSRef fsRef;
252 OSType folderType =
253 aLocal ? (OSType)kCachedDataFolderType : (OSType)kDomainLibraryFolderType;
254 OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
255 if (err) {
256 return NS_ERROR_FAILURE;
258 NS_NewLocalFile(u""_ns, true, getter_AddRefs(localDir));
259 if (!localDir) {
260 return NS_ERROR_FAILURE;
262 nsCOMPtr<nsILocalFileMac> localDirMac(do_QueryInterface(localDir));
263 rv = localDirMac->InitWithFSRef(&fsRef);
264 if (NS_FAILED(rv)) {
265 return rv;
267 #elif defined(XP_WIN)
268 nsCOMPtr<nsIProperties> directoryService =
269 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
270 if (NS_FAILED(rv)) {
271 return 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));
276 if (NS_FAILED(rv)) {
277 return rv;
279 #elif defined(XP_UNIX)
280 rv = NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), true,
281 getter_AddRefs(localDir));
282 if (NS_FAILED(rv)) {
283 return rv;
285 #else
286 # error dont_know_how_to_get_product_dir_on_your_platform
287 #endif
289 rv = localDir->AppendRelativeNativePath(DEFAULT_PRODUCT_DIR);
290 if (NS_FAILED(rv)) {
291 return rv;
293 rv = localDir->Exists(&exists);
295 if (NS_SUCCEEDED(rv) && !exists) {
296 rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
299 if (NS_FAILED(rv)) {
300 return rv;
303 localDir.forget(aLocalFile);
305 return rv;
308 //----------------------------------------------------------------------------------------
309 // GetDefaultUserProfileRoot - Gets the directory which contains each user
310 // profile dir
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;
322 nsresult rv;
323 nsCOMPtr<nsIFile> localDir;
325 rv = GetProductDirectory(getter_AddRefs(localDir), aLocal);
326 if (NS_FAILED(rv)) {
327 return rv;
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);
333 if (NS_FAILED(rv)) {
334 return rv;
337 bool exists;
338 rv = localDir->Exists(&exists);
339 if (NS_SUCCEEDED(rv) && !exists) {
340 rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
342 if (NS_FAILED(rv)) {
343 return rv;
345 #endif
347 localDir.forget(aLocalFile);
349 return rv;
352 //*****************************************************************************
353 // nsAppFileLocationProvider::nsIDirectoryServiceProvider2
354 //*****************************************************************************
356 class nsAppDirectoryEnumerator : public nsSimpleEnumerator {
357 public:
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) {
370 bool dontCare;
371 nsCOMPtr<nsIFile> testFile;
372 (void)mProvider->GetFile(*mCurrentKey++, &dontCare,
373 getter_AddRefs(testFile));
374 mNext = testFile;
376 *aResult = mNext != nullptr;
377 return NS_OK;
380 NS_IMETHOD GetNext(nsISupports** aResult) override {
381 if (NS_WARN_IF(!aResult)) {
382 return NS_ERROR_INVALID_ARG;
384 *aResult = nullptr;
386 bool hasMore;
387 HasMoreElements(&hasMore);
388 if (!hasMore) {
389 return NS_ERROR_FAILURE;
392 *aResult = mNext;
393 NS_IF_ADDREF(*aResult);
394 mNext = nullptr;
396 return *aResult ? NS_OK : NS_ERROR_FAILURE;
399 protected:
400 nsCOMPtr<nsIDirectoryServiceProvider> mProvider;
401 const char** mCurrentKey;
402 nsCOMPtr<nsIFile> mNext;
405 NS_IMETHODIMP
406 nsAppFileLocationProvider::GetFiles(const char* aProp,
407 nsISimpleEnumerator** aResult) {
408 if (NS_WARN_IF(!aResult)) {
409 return NS_ERROR_INVALID_ARG;
411 *aResult = nullptr;
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};
418 #else
419 # ifdef XP_UNIX
420 static const char* keys[] = {NS_USER_PLUGINS_DIR, NS_SYSTEM_PLUGINS_DIR,
421 nullptr};
422 # else
423 static const char* keys[] = {NS_USER_PLUGINS_DIR, nullptr};
424 # endif
425 #endif
426 *aResult = new nsAppDirectoryEnumerator(this, keys);
427 NS_ADDREF(*aResult);
428 rv = NS_OK;
430 return rv;