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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
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.
21 : *
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>
27 : *
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.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : #include "nsAppRunner.h"
43 : #include "nsToolkitCompsCID.h"
44 : #include "nsXREDirProvider.h"
45 :
46 : #include "jsapi.h"
47 :
48 : #include "nsIJSContextStack.h"
49 : #include "nsIAppStartup.h"
50 : #include "nsIDirectoryEnumerator.h"
51 : #include "nsILocalFile.h"
52 : #include "nsIObserver.h"
53 : #include "nsIObserverService.h"
54 : #include "nsIProfileChangeStatus.h"
55 : #include "nsISimpleEnumerator.h"
56 : #include "nsIToolkitChromeRegistry.h"
57 :
58 : #include "nsAppDirectoryServiceDefs.h"
59 : #include "nsDirectoryServiceDefs.h"
60 : #include "nsDirectoryServiceUtils.h"
61 : #include "nsXULAppAPI.h"
62 : #include "nsCategoryManagerUtils.h"
63 :
64 : #include "nsINIParser.h"
65 : #include "nsDependentString.h"
66 : #include "nsCOMArray.h"
67 : #include "nsArrayEnumerator.h"
68 : #include "nsEnumeratorUtils.h"
69 : #include "nsReadableUtils.h"
70 : #include "mozilla/Services.h"
71 : #include "mozilla/Omnijar.h"
72 : #include "mozilla/Preferences.h"
73 : #include "mozilla/Telemetry.h"
74 :
75 : #include <stdlib.h>
76 :
77 : #ifdef XP_WIN
78 : #include <windows.h>
79 : #include <shlobj.h>
80 : #endif
81 : #ifdef XP_MACOSX
82 : #include "nsILocalFileMac.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
91 :
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
99 :
100 : #define PREF_OVERRIDE_DIRNAME "preferences"
101 :
102 : static already_AddRefed<nsILocalFile>
103 0 : CloneAndAppend(nsIFile* aFile, const char* name)
104 : {
105 0 : nsCOMPtr<nsIFile> file;
106 0 : aFile->Clone(getter_AddRefs(file));
107 0 : nsCOMPtr<nsILocalFile> lfile = do_QueryInterface(file);
108 0 : lfile->AppendNative(nsDependentCString(name));
109 0 : return lfile.forget();
110 : }
111 :
112 : nsXREDirProvider* gDirServiceProvider = nsnull;
113 :
114 23 : nsXREDirProvider::nsXREDirProvider() :
115 23 : mProfileNotified(false)
116 : {
117 23 : gDirServiceProvider = this;
118 23 : }
119 :
120 46 : nsXREDirProvider::~nsXREDirProvider()
121 : {
122 23 : gDirServiceProvider = nsnull;
123 23 : }
124 :
125 : nsresult
126 23 : nsXREDirProvider::Initialize(nsIFile *aXULAppDir,
127 : nsILocalFile *aGREDir,
128 : nsIDirectoryServiceProvider* aAppProvider)
129 : {
130 23 : NS_ENSURE_ARG(aXULAppDir);
131 23 : NS_ENSURE_ARG(aGREDir);
132 :
133 23 : mAppProvider = aAppProvider;
134 23 : mXULAppDir = aXULAppDir;
135 23 : mGREDir = aGREDir;
136 :
137 23 : if (!mProfileDir) {
138 46 : nsCOMPtr<nsIDirectoryServiceProvider> app(do_QueryInterface(mAppProvider));
139 23 : if (app) {
140 0 : bool per = false;
141 0 : app->GetFile(NS_APP_USER_PROFILE_50_DIR, &per, getter_AddRefs(mProfileDir));
142 0 : NS_ASSERTION(per, "NS_APP_USER_PROFILE_50_DIR must be persistent!");
143 0 : NS_ASSERTION(mProfileDir, "NS_APP_USER_PROFILE_50_DIR not defined! This shouldn't happen!");
144 : }
145 : }
146 :
147 23 : LoadAppBundleDirs();
148 23 : return NS_OK;
149 : }
150 :
151 : nsresult
152 0 : nsXREDirProvider::SetProfile(nsIFile* aDir, nsIFile* aLocalDir)
153 : {
154 0 : NS_ASSERTION(aDir && aLocalDir, "We don't support no-profile apps yet!");
155 :
156 : nsresult rv;
157 :
158 0 : rv = EnsureDirectoryExists(aDir);
159 0 : if (NS_FAILED(rv))
160 0 : return rv;
161 :
162 0 : rv = EnsureDirectoryExists(aLocalDir);
163 0 : if (NS_FAILED(rv))
164 0 : return rv;
165 :
166 0 : mProfileDir = aDir;
167 0 : mProfileLocalDir = aLocalDir;
168 0 : return NS_OK;
169 : }
170 :
171 0 : NS_IMPL_QUERY_INTERFACE3(nsXREDirProvider,
172 : nsIDirectoryServiceProvider,
173 : nsIDirectoryServiceProvider2,
174 : nsIProfileStartup)
175 :
176 : NS_IMETHODIMP_(nsrefcnt)
177 0 : nsXREDirProvider::AddRef()
178 : {
179 0 : return 1;
180 : }
181 :
182 : NS_IMETHODIMP_(nsrefcnt)
183 0 : nsXREDirProvider::Release()
184 : {
185 0 : return 0;
186 : }
187 :
188 : NS_IMETHODIMP
189 0 : nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
190 : nsIFile** aFile)
191 : {
192 : nsresult rv;
193 :
194 0 : bool gettingProfile = false;
195 :
196 0 : if (!strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR)) {
197 : // If XRE_NotifyProfile hasn't been called, don't fall through to
198 : // mAppProvider on the profile keys.
199 0 : if (!mProfileNotified)
200 0 : return NS_ERROR_FAILURE;
201 :
202 0 : if (mProfileLocalDir)
203 0 : return mProfileLocalDir->Clone(aFile);
204 :
205 0 : if (mAppProvider)
206 0 : return mAppProvider->GetFile(aProperty, aPersistent, aFile);
207 :
208 : // This falls through to the case below
209 0 : gettingProfile = true;
210 : }
211 0 : if (!strcmp(aProperty, NS_APP_USER_PROFILE_50_DIR) || gettingProfile) {
212 0 : if (!mProfileNotified)
213 0 : return NS_ERROR_FAILURE;
214 :
215 0 : if (mProfileDir)
216 0 : return mProfileDir->Clone(aFile);
217 :
218 0 : if (mAppProvider)
219 0 : return mAppProvider->GetFile(aProperty, aPersistent, aFile);
220 :
221 : // If we don't succeed here, bail early so that we aren't reentrant
222 : // through the "GetProfileDir" call below.
223 0 : return NS_ERROR_FAILURE;
224 : }
225 :
226 0 : if (mAppProvider) {
227 0 : rv = mAppProvider->GetFile(aProperty, aPersistent, aFile);
228 0 : if (NS_SUCCEEDED(rv) && *aFile)
229 0 : return rv;
230 : }
231 :
232 0 : *aPersistent = true;
233 :
234 0 : if (!strcmp(aProperty, NS_GRE_DIR)) {
235 0 : return mGREDir->Clone(aFile);
236 : }
237 0 : else if (!strcmp(aProperty, NS_OS_CURRENT_PROCESS_DIR) ||
238 0 : !strcmp(aProperty, NS_APP_INSTALL_CLEANUP_DIR)) {
239 0 : return GetAppDir()->Clone(aFile);
240 : }
241 :
242 0 : rv = NS_ERROR_FAILURE;
243 0 : nsCOMPtr<nsIFile> file;
244 :
245 0 : if (!strcmp(aProperty, NS_APP_PROFILE_DEFAULTS_50_DIR) ||
246 0 : !strcmp(aProperty, NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR)) {
247 0 : return GetProfileDefaultsDir(aFile);
248 : }
249 0 : else if (!strcmp(aProperty, NS_APP_PREF_DEFAULTS_50_DIR))
250 : {
251 : // return the GRE default prefs directory here, and the app default prefs
252 : // directory (if applicable) in NS_APP_PREFS_DEFAULTS_DIR_LIST.
253 0 : rv = mGREDir->Clone(getter_AddRefs(file));
254 0 : if (NS_SUCCEEDED(rv)) {
255 0 : rv = file->AppendNative(NS_LITERAL_CSTRING("defaults"));
256 0 : if (NS_SUCCEEDED(rv))
257 0 : rv = file->AppendNative(NS_LITERAL_CSTRING("pref"));
258 : }
259 : }
260 0 : else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_DIR) ||
261 0 : !strcmp(aProperty, XRE_USER_APP_DATA_DIR)) {
262 0 : rv = GetUserAppDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file));
263 : }
264 0 : else if (!strcmp(aProperty, XRE_UPDATE_ROOT_DIR)) {
265 : #if defined(XP_WIN)
266 : rv = GetUpdateRootDir(getter_AddRefs(file));
267 : #else
268 : // Only supported on Windows, so just immediately fail.
269 0 : return NS_ERROR_FAILURE;
270 : #endif
271 : }
272 0 : else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_FILE)) {
273 0 : rv = GetUserAppDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file));
274 0 : if (NS_SUCCEEDED(rv))
275 0 : rv = file->AppendNative(NS_LITERAL_CSTRING(APP_REGISTRY_NAME));
276 : }
277 0 : else if (!strcmp(aProperty, NS_APP_USER_PROFILES_ROOT_DIR)) {
278 0 : rv = GetUserAppDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file));
279 :
280 0 : if (NS_SUCCEEDED(rv)) {
281 : #if !defined(XP_UNIX) || defined(XP_MACOSX)
282 : rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
283 : #endif
284 :
285 : // We must create the profile directory here if it does not exist.
286 0 : rv |= EnsureDirectoryExists(file);
287 : }
288 : }
289 0 : else if (!strcmp(aProperty, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR)) {
290 0 : rv = GetUserLocalDataDirectory((nsILocalFile**)(nsIFile**) getter_AddRefs(file));
291 :
292 0 : if (NS_SUCCEEDED(rv)) {
293 : #if !defined(XP_UNIX) || defined(XP_MACOSX)
294 : rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
295 : #endif
296 :
297 : // We must create the profile directory here if it does not exist.
298 0 : rv |= EnsureDirectoryExists(file);
299 : }
300 : }
301 0 : else if (!strcmp(aProperty, XRE_EXECUTABLE_FILE) && gArgv[0]) {
302 0 : nsCOMPtr<nsILocalFile> lf;
303 0 : rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
304 0 : if (NS_SUCCEEDED(rv))
305 0 : file = lf;
306 : }
307 :
308 0 : else if (!strcmp(aProperty, NS_APP_PROFILE_DIR_STARTUP) && mProfileDir) {
309 0 : return mProfileDir->Clone(aFile);
310 : }
311 0 : else if (!strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP)) {
312 0 : if (mProfileLocalDir)
313 0 : return mProfileLocalDir->Clone(aFile);
314 :
315 0 : if (mProfileDir)
316 0 : return mProfileDir->Clone(aFile);
317 :
318 0 : if (mAppProvider)
319 0 : return mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP, aPersistent,
320 0 : aFile);
321 : }
322 : #if defined(XP_UNIX) || defined(XP_MACOSX)
323 0 : else if (!strcmp(aProperty, XRE_SYS_LOCAL_EXTENSION_PARENT_DIR)) {
324 : #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
325 0 : return GetSystemExtensionsDirectory((nsILocalFile**)(nsIFile**) aFile);
326 : #else
327 : return NS_ERROR_FAILURE;
328 : #endif
329 : }
330 : #endif
331 : #if defined(XP_UNIX) && !defined(XP_MACOSX)
332 0 : else if (!strcmp(aProperty, XRE_SYS_SHARE_EXTENSION_PARENT_DIR)) {
333 : #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
334 : static const char *const sysLExtDir = "/usr/share/mozilla/extensions";
335 0 : return NS_NewNativeLocalFile(nsDependentCString(sysLExtDir),
336 0 : false, (nsILocalFile**)(nsIFile**) aFile);
337 : #else
338 : return NS_ERROR_FAILURE;
339 : #endif
340 : }
341 : #endif
342 0 : else if (!strcmp(aProperty, XRE_USER_SYS_EXTENSION_DIR)) {
343 : #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
344 0 : return GetSysUserExtensionsDirectory((nsILocalFile**)(nsIFile**) aFile);
345 : #else
346 : return NS_ERROR_FAILURE;
347 : #endif
348 : }
349 0 : else if (!strcmp(aProperty, XRE_APP_DISTRIBUTION_DIR)) {
350 0 : rv = GetAppDir()->Clone(getter_AddRefs(file));
351 0 : if (NS_SUCCEEDED(rv))
352 0 : rv = file->AppendNative(NS_LITERAL_CSTRING("distribution"));
353 : }
354 0 : else if (NS_SUCCEEDED(GetProfileStartupDir(getter_AddRefs(file)))) {
355 : // We need to allow component, xpt, and chrome registration to
356 : // occur prior to the profile-after-change notification.
357 0 : if (!strcmp(aProperty, NS_APP_USER_CHROME_DIR)) {
358 0 : rv = file->AppendNative(NS_LITERAL_CSTRING("chrome"));
359 : }
360 : }
361 :
362 0 : if (NS_SUCCEEDED(rv) && file) {
363 0 : NS_ADDREF(*aFile = file);
364 0 : return NS_OK;
365 : }
366 :
367 0 : bool ensureFilePermissions = false;
368 :
369 0 : if (NS_SUCCEEDED(GetProfileDir(getter_AddRefs(file)))) {
370 0 : if (!strcmp(aProperty, NS_APP_PREFS_50_DIR)) {
371 0 : rv = NS_OK;
372 : }
373 0 : else if (!strcmp(aProperty, NS_APP_PREFS_50_FILE)) {
374 0 : rv = file->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
375 : }
376 0 : else if (!strcmp(aProperty, NS_LOCALSTORE_UNSAFE_FILE)) {
377 0 : rv = file->AppendNative(NS_LITERAL_CSTRING("localstore.rdf"));
378 : }
379 0 : else if (!strcmp(aProperty, NS_APP_LOCALSTORE_50_FILE)) {
380 0 : if (gSafeMode) {
381 0 : rv = file->AppendNative(NS_LITERAL_CSTRING("localstore-safe.rdf"));
382 0 : file->Remove(false);
383 : }
384 : else {
385 0 : rv = file->AppendNative(NS_LITERAL_CSTRING("localstore.rdf"));
386 0 : EnsureProfileFileExists(file);
387 0 : ensureFilePermissions = true;
388 : }
389 : }
390 0 : else if (!strcmp(aProperty, NS_APP_USER_MIMETYPES_50_FILE)) {
391 0 : rv = file->AppendNative(NS_LITERAL_CSTRING("mimeTypes.rdf"));
392 0 : EnsureProfileFileExists(file);
393 0 : ensureFilePermissions = true;
394 : }
395 0 : else if (!strcmp(aProperty, NS_APP_STORAGE_50_FILE)) {
396 0 : rv = file->AppendNative(NS_LITERAL_CSTRING("storage.sdb"));
397 : }
398 0 : else if (!strcmp(aProperty, NS_APP_DOWNLOADS_50_FILE)) {
399 0 : rv = file->AppendNative(NS_LITERAL_CSTRING("downloads.rdf"));
400 : }
401 0 : else if (!strcmp(aProperty, NS_APP_PREFS_OVERRIDE_DIR)) {
402 0 : rv = mProfileDir->Clone(getter_AddRefs(file));
403 0 : rv |= file->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
404 0 : rv |= EnsureDirectoryExists(file);
405 : }
406 : }
407 0 : if (NS_FAILED(rv) || !file)
408 0 : return NS_ERROR_FAILURE;
409 :
410 0 : if (ensureFilePermissions) {
411 : bool fileToEnsureExists;
412 : bool isWritable;
413 0 : if (NS_SUCCEEDED(file->Exists(&fileToEnsureExists)) && fileToEnsureExists
414 0 : && NS_SUCCEEDED(file->IsWritable(&isWritable)) && !isWritable) {
415 : PRUint32 permissions;
416 0 : if (NS_SUCCEEDED(file->GetPermissions(&permissions))) {
417 0 : rv = file->SetPermissions(permissions | 0600);
418 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "failed to ensure file permissions");
419 : }
420 : }
421 : }
422 :
423 0 : NS_ADDREF(*aFile = file);
424 0 : return NS_OK;
425 : }
426 :
427 : static void
428 0 : LoadAppDirIntoArray(nsIFile* aXULAppDir,
429 : const char *const *aAppendList,
430 : nsCOMArray<nsIFile>& aDirectories)
431 : {
432 0 : if (!aXULAppDir)
433 0 : return;
434 :
435 0 : nsCOMPtr<nsIFile> subdir;
436 0 : aXULAppDir->Clone(getter_AddRefs(subdir));
437 0 : if (!subdir)
438 : return;
439 :
440 0 : for (; *aAppendList; ++aAppendList)
441 0 : subdir->AppendNative(nsDependentCString(*aAppendList));
442 :
443 : bool exists;
444 0 : if (NS_SUCCEEDED(subdir->Exists(&exists)) && exists)
445 0 : aDirectories.AppendObject(subdir);
446 : }
447 :
448 : static void
449 0 : LoadDirsIntoArray(nsCOMArray<nsIFile>& aSourceDirs,
450 : const char *const* aAppendList,
451 : nsCOMArray<nsIFile>& aDirectories)
452 : {
453 0 : nsCOMPtr<nsIFile> appended;
454 : bool exists;
455 :
456 0 : for (PRInt32 i = 0; i < aSourceDirs.Count(); ++i) {
457 0 : aSourceDirs[i]->Clone(getter_AddRefs(appended));
458 0 : if (!appended)
459 0 : continue;
460 :
461 0 : nsCAutoString leaf;
462 0 : appended->GetNativeLeafName(leaf);
463 0 : if (!Substring(leaf, leaf.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi"))) {
464 0 : for (const char *const *a = aAppendList; *a; ++a)
465 0 : appended->AppendNative(nsDependentCString(*a));
466 : }
467 :
468 0 : if (NS_SUCCEEDED(appended->Exists(&exists)) && exists)
469 0 : aDirectories.AppendObject(appended);
470 : }
471 0 : }
472 :
473 : NS_IMETHODIMP
474 0 : nsXREDirProvider::GetFiles(const char* aProperty, nsISimpleEnumerator** aResult)
475 : {
476 : nsresult rv;
477 :
478 0 : nsCOMPtr<nsISimpleEnumerator> appEnum;
479 : nsCOMPtr<nsIDirectoryServiceProvider2>
480 0 : appP2(do_QueryInterface(mAppProvider));
481 0 : if (appP2) {
482 0 : rv = appP2->GetFiles(aProperty, getter_AddRefs(appEnum));
483 0 : if (NS_FAILED(rv)) {
484 0 : appEnum = nsnull;
485 : }
486 0 : else if (rv != NS_SUCCESS_AGGREGATE_RESULT) {
487 0 : NS_ADDREF(*aResult = appEnum);
488 0 : return NS_OK;
489 : }
490 : }
491 :
492 0 : nsCOMPtr<nsISimpleEnumerator> xreEnum;
493 0 : rv = GetFilesInternal(aProperty, getter_AddRefs(xreEnum));
494 0 : if (NS_FAILED(rv)) {
495 0 : if (appEnum) {
496 0 : NS_ADDREF(*aResult = appEnum);
497 0 : return NS_SUCCESS_AGGREGATE_RESULT;
498 : }
499 :
500 0 : return rv;
501 : }
502 :
503 0 : rv = NS_NewUnionEnumerator(aResult, appEnum, xreEnum);
504 0 : if (NS_FAILED(rv))
505 0 : return rv;
506 :
507 0 : return NS_SUCCESS_AGGREGATE_RESULT;
508 : }
509 :
510 : static void
511 0 : LoadExtensionDirectories(nsINIParser &parser,
512 : const char *aSection,
513 : nsCOMArray<nsIFile> &aDirectories,
514 : NSLocationType aType)
515 : {
516 : nsresult rv;
517 0 : PRInt32 i = 0;
518 0 : do {
519 0 : nsCAutoString buf("Extension");
520 0 : buf.AppendInt(i++);
521 :
522 0 : nsCAutoString path;
523 0 : rv = parser.GetString(aSection, buf.get(), path);
524 0 : if (NS_FAILED(rv))
525 : return;
526 :
527 0 : nsCOMPtr<nsILocalFile> dir = do_CreateInstance("@mozilla.org/file/local;1", &rv);
528 0 : if (NS_FAILED(rv))
529 0 : continue;
530 :
531 0 : rv = dir->SetPersistentDescriptor(path);
532 0 : if (NS_FAILED(rv))
533 0 : continue;
534 :
535 0 : aDirectories.AppendObject(dir);
536 0 : if (Substring(path, path.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi"))) {
537 0 : XRE_AddJarManifestLocation(aType, dir);
538 : }
539 : else {
540 : nsCOMPtr<nsILocalFile> manifest =
541 0 : CloneAndAppend(dir, "chrome.manifest");
542 0 : XRE_AddManifestLocation(aType, manifest);
543 : }
544 : }
545 : while (true);
546 : }
547 :
548 : void
549 0 : nsXREDirProvider::LoadExtensionBundleDirectories()
550 : {
551 0 : if (mProfileDir && !gSafeMode) {
552 0 : nsCOMPtr<nsIFile> extensionsINI;
553 0 : mProfileDir->Clone(getter_AddRefs(extensionsINI));
554 0 : if (!extensionsINI)
555 : return;
556 :
557 0 : extensionsINI->AppendNative(NS_LITERAL_CSTRING("extensions.ini"));
558 :
559 : nsCOMPtr<nsILocalFile> extensionsINILF =
560 0 : do_QueryInterface(extensionsINI);
561 0 : if (!extensionsINILF)
562 : return;
563 :
564 0 : nsINIParser parser;
565 0 : nsresult rv = parser.Init(extensionsINILF);
566 0 : if (NS_FAILED(rv))
567 : return;
568 :
569 : LoadExtensionDirectories(parser, "ExtensionDirs", mExtensionDirectories,
570 0 : NS_COMPONENT_LOCATION);
571 : LoadExtensionDirectories(parser, "ThemeDirs", mThemeDirectories,
572 0 : NS_SKIN_LOCATION);
573 : }
574 : }
575 :
576 : void
577 23 : nsXREDirProvider::LoadAppBundleDirs()
578 : {
579 46 : nsCOMPtr<nsIFile> dir;
580 23 : nsresult rv = mXULAppDir->Clone(getter_AddRefs(dir));
581 23 : if (NS_FAILED(rv))
582 : return;
583 :
584 23 : dir->AppendNative(NS_LITERAL_CSTRING("distribution"));
585 23 : dir->AppendNative(NS_LITERAL_CSTRING("bundles"));
586 :
587 46 : nsCOMPtr<nsISimpleEnumerator> e;
588 23 : rv = dir->GetDirectoryEntries(getter_AddRefs(e));
589 23 : if (NS_FAILED(rv))
590 : return;
591 :
592 0 : nsCOMPtr<nsIDirectoryEnumerator> files = do_QueryInterface(e);
593 0 : if (!files)
594 : return;
595 :
596 0 : nsCOMPtr<nsIFile> subdir;
597 0 : while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(subdir))) && subdir) {
598 0 : mAppBundleDirectories.AppendObject(subdir);
599 :
600 : nsCOMPtr<nsILocalFile> manifest =
601 0 : CloneAndAppend(subdir, "chrome.manifest");
602 0 : XRE_AddManifestLocation(NS_COMPONENT_LOCATION, manifest);
603 : }
604 : }
605 :
606 : static const char *const kAppendPrefDir[] = { "defaults", "preferences", nsnull };
607 :
608 : #ifdef DEBUG_bsmedberg
609 : static void
610 : DumpFileArray(const char *key,
611 : nsCOMArray<nsIFile> dirs)
612 : {
613 : fprintf(stderr, "nsXREDirProvider::GetFilesInternal(%s)\n", key);
614 :
615 : nsCAutoString path;
616 : for (PRInt32 i = 0; i < dirs.Count(); ++i) {
617 : dirs[i]->GetNativePath(path);
618 : fprintf(stderr, " %s\n", path.get());
619 : }
620 : }
621 : #endif // DEBUG_bsmedberg
622 :
623 : nsresult
624 0 : nsXREDirProvider::GetFilesInternal(const char* aProperty,
625 : nsISimpleEnumerator** aResult)
626 : {
627 0 : nsresult rv = NS_OK;
628 0 : *aResult = nsnull;
629 :
630 0 : if (!strcmp(aProperty, XRE_EXTENSIONS_DIR_LIST)) {
631 0 : nsCOMArray<nsIFile> directories;
632 :
633 : static const char *const kAppendNothing[] = { nsnull };
634 :
635 : LoadDirsIntoArray(mAppBundleDirectories,
636 0 : kAppendNothing, directories);
637 : LoadDirsIntoArray(mExtensionDirectories,
638 0 : kAppendNothing, directories);
639 :
640 0 : rv = NS_NewArrayEnumerator(aResult, directories);
641 : }
642 0 : else if (!strcmp(aProperty, NS_APP_PREFS_DEFAULTS_DIR_LIST)) {
643 0 : nsCOMArray<nsIFile> directories;
644 :
645 0 : LoadAppDirIntoArray(mXULAppDir, kAppendPrefDir, directories);
646 : LoadDirsIntoArray(mAppBundleDirectories,
647 0 : kAppendPrefDir, directories);
648 :
649 0 : rv = NS_NewArrayEnumerator(aResult, directories);
650 : }
651 0 : else if (!strcmp(aProperty, NS_EXT_PREFS_DEFAULTS_DIR_LIST)) {
652 0 : nsCOMArray<nsIFile> directories;
653 :
654 : LoadDirsIntoArray(mExtensionDirectories,
655 0 : kAppendPrefDir, directories);
656 :
657 0 : if (mProfileDir) {
658 0 : nsCOMPtr<nsIFile> overrideFile;
659 0 : mProfileDir->Clone(getter_AddRefs(overrideFile));
660 0 : overrideFile->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
661 :
662 : bool exists;
663 0 : if (NS_SUCCEEDED(overrideFile->Exists(&exists)) && exists)
664 0 : directories.AppendObject(overrideFile);
665 : }
666 :
667 0 : rv = NS_NewArrayEnumerator(aResult, directories);
668 : }
669 0 : else if (!strcmp(aProperty, NS_APP_CHROME_DIR_LIST)) {
670 : // NS_APP_CHROME_DIR_LIST is only used to get default (native) icons
671 : // for OS window decoration.
672 :
673 : static const char *const kAppendChromeDir[] = { "chrome", nsnull };
674 0 : nsCOMArray<nsIFile> directories;
675 : LoadAppDirIntoArray(mXULAppDir,
676 : kAppendChromeDir,
677 0 : directories);
678 : LoadDirsIntoArray(mAppBundleDirectories,
679 : kAppendChromeDir,
680 0 : directories);
681 : LoadDirsIntoArray(mExtensionDirectories,
682 : kAppendChromeDir,
683 0 : directories);
684 :
685 0 : rv = NS_NewArrayEnumerator(aResult, directories);
686 : }
687 0 : else if (!strcmp(aProperty, NS_APP_PLUGINS_DIR_LIST)) {
688 : static const char *const kAppendPlugins[] = { "plugins", nsnull };
689 0 : nsCOMArray<nsIFile> directories;
690 :
691 : // The root dirserviceprovider does quite a bit for us: we're mainly
692 : // interested in xulapp and extension-provided plugins.
693 : LoadDirsIntoArray(mAppBundleDirectories,
694 : kAppendPlugins,
695 0 : directories);
696 : LoadDirsIntoArray(mExtensionDirectories,
697 : kAppendPlugins,
698 0 : directories);
699 :
700 0 : if (mProfileDir) {
701 0 : nsCOMArray<nsIFile> profileDir;
702 0 : profileDir.AppendObject(mProfileDir);
703 : LoadDirsIntoArray(profileDir,
704 : kAppendPlugins,
705 0 : directories);
706 : }
707 :
708 0 : rv = NS_NewArrayEnumerator(aResult, directories);
709 0 : NS_ENSURE_SUCCESS(rv, rv);
710 :
711 0 : rv = NS_SUCCESS_AGGREGATE_RESULT;
712 : }
713 : else
714 0 : rv = NS_ERROR_FAILURE;
715 :
716 0 : return rv;
717 : }
718 :
719 : NS_IMETHODIMP
720 0 : nsXREDirProvider::GetDirectory(nsIFile* *aResult)
721 : {
722 0 : NS_ENSURE_TRUE(mProfileDir, NS_ERROR_NOT_INITIALIZED);
723 :
724 0 : return mProfileDir->Clone(aResult);
725 : }
726 :
727 : NS_IMETHODIMP
728 0 : nsXREDirProvider::DoStartup()
729 : {
730 0 : if (!mProfileNotified) {
731 : nsCOMPtr<nsIObserverService> obsSvc =
732 0 : mozilla::services::GetObserverService();
733 0 : if (!obsSvc) return NS_ERROR_FAILURE;
734 :
735 0 : mProfileNotified = true;
736 :
737 : /*
738 : Setup prefs before profile-do-change to be able to use them to track
739 : crashes and because we want to begin crash tracking before other code run
740 : from this notification since they may cause crashes.
741 : */
742 0 : nsresult rv = mozilla::Preferences::ResetAndReadUserPrefs();
743 0 : if (NS_FAILED(rv)) NS_WARNING("Failed to setup pref service.");
744 :
745 0 : bool safeModeNecessary = false;
746 0 : nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
747 0 : if (appStartup) {
748 0 : rv = appStartup->TrackStartupCrashBegin(&safeModeNecessary);
749 0 : if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE)
750 0 : NS_WARNING("Error while beginning startup crash tracking");
751 :
752 0 : if (!gSafeMode && safeModeNecessary) {
753 0 : appStartup->RestartInSafeMode(nsIAppStartup::eForceQuit);
754 0 : return NS_OK;
755 : }
756 : }
757 :
758 : static const PRUnichar kStartup[] = {'s','t','a','r','t','u','p','\0'};
759 0 : obsSvc->NotifyObservers(nsnull, "profile-do-change", kStartup);
760 : // Init the Extension Manager
761 0 : nsCOMPtr<nsIObserver> em = do_GetService("@mozilla.org/addons/integration;1");
762 0 : if (em) {
763 0 : em->Observe(nsnull, "addons-startup", nsnull);
764 : } else {
765 0 : NS_WARNING("Failed to create Addons Manager.");
766 : }
767 :
768 0 : LoadExtensionBundleDirectories();
769 :
770 0 : obsSvc->NotifyObservers(nsnull, "load-extension-defaults", nsnull);
771 0 : obsSvc->NotifyObservers(nsnull, "profile-after-change", kStartup);
772 :
773 : // Any component that has registered for the profile-after-change category
774 : // should also be created at this time.
775 : (void)NS_CreateServicesFromCategory("profile-after-change", nsnull,
776 0 : "profile-after-change");
777 :
778 0 : if (gSafeMode && safeModeNecessary) {
779 : static const PRUnichar kCrashed[] = {'c','r','a','s','h','e','d','\0'};
780 0 : obsSvc->NotifyObservers(nsnull, "safemode-forced", kCrashed);
781 : }
782 :
783 : // 1 = Regular mode, 2 = Safe mode, 3 = Safe mode forced
784 0 : int mode = 1;
785 0 : if (gSafeMode) {
786 0 : if (safeModeNecessary)
787 0 : mode = 3;
788 : else
789 0 : mode = 2;
790 : }
791 0 : mozilla::Telemetry::Accumulate(mozilla::Telemetry::SAFE_MODE_USAGE, mode);
792 :
793 0 : obsSvc->NotifyObservers(nsnull, "profile-initial-state", nsnull);
794 : }
795 0 : return NS_OK;
796 : }
797 :
798 : class ProfileChangeStatusImpl : public nsIProfileChangeStatus
799 : {
800 : public:
801 : NS_DECL_ISUPPORTS
802 : NS_DECL_NSIPROFILECHANGESTATUS
803 0 : ProfileChangeStatusImpl() { }
804 : private:
805 0 : ~ProfileChangeStatusImpl() { }
806 : };
807 :
808 0 : NS_IMPL_ISUPPORTS1(ProfileChangeStatusImpl, nsIProfileChangeStatus)
809 :
810 : NS_IMETHODIMP
811 0 : ProfileChangeStatusImpl::VetoChange()
812 : {
813 0 : NS_ERROR("Can't veto change!");
814 0 : return NS_ERROR_FAILURE;
815 : }
816 :
817 : NS_IMETHODIMP
818 0 : ProfileChangeStatusImpl::ChangeFailed()
819 : {
820 0 : NS_ERROR("Profile change cancellation.");
821 0 : return NS_ERROR_FAILURE;
822 : }
823 :
824 : void
825 0 : nsXREDirProvider::DoShutdown()
826 : {
827 0 : if (mProfileNotified) {
828 : nsCOMPtr<nsIObserverService> obsSvc =
829 0 : mozilla::services::GetObserverService();
830 0 : NS_ASSERTION(obsSvc, "No observer service?");
831 0 : if (obsSvc) {
832 0 : nsCOMPtr<nsIProfileChangeStatus> cs = new ProfileChangeStatusImpl();
833 : static const PRUnichar kShutdownPersist[] =
834 : {'s','h','u','t','d','o','w','n','-','p','e','r','s','i','s','t','\0'};
835 0 : obsSvc->NotifyObservers(cs, "profile-change-net-teardown", kShutdownPersist);
836 0 : obsSvc->NotifyObservers(cs, "profile-change-teardown", kShutdownPersist);
837 :
838 : // Phase 2c: Now that things are torn down, force JS GC so that things which depend on
839 : // resources which are about to go away in "profile-before-change" are destroyed first.
840 : nsCOMPtr<nsIThreadJSContextStack> stack
841 0 : (do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
842 0 : if (stack)
843 : {
844 0 : JSContext *cx = nsnull;
845 0 : stack->GetSafeJSContext(&cx);
846 0 : if (cx)
847 0 : ::JS_GC(cx);
848 : }
849 :
850 : // Phase 3: Notify observers of a profile change
851 0 : obsSvc->NotifyObservers(cs, "profile-before-change", kShutdownPersist);
852 : }
853 0 : mProfileNotified = false;
854 : }
855 0 : }
856 :
857 : #ifdef XP_WIN
858 : static nsresult
859 : GetShellFolderPath(int folder, nsAString& _retval)
860 : {
861 : PRUnichar* buf;
862 : PRUint32 bufLength = _retval.GetMutableData(&buf, MAXPATHLEN + 3);
863 : NS_ENSURE_TRUE(bufLength >= (MAXPATHLEN + 3), NS_ERROR_OUT_OF_MEMORY);
864 :
865 : nsresult rv = NS_OK;
866 :
867 : LPITEMIDLIST pItemIDList = NULL;
868 :
869 : if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, folder, &pItemIDList)) &&
870 : SHGetPathFromIDListW(pItemIDList, buf)) {
871 : // We're going to use wcslen (wcsnlen not available in msvc7.1) so make
872 : // sure to null terminate.
873 : buf[bufLength - 1] = L'\0';
874 : _retval.SetLength(wcslen(buf));
875 : } else {
876 : _retval.SetLength(0);
877 : rv = NS_ERROR_NOT_AVAILABLE;
878 : }
879 :
880 : CoTaskMemFree(pItemIDList);
881 :
882 : return rv;
883 : }
884 :
885 : /**
886 : * Provides a fallback for getting the path to APPDATA or LOCALAPPDATA by
887 : * querying the registry when the call to SHGetSpecialFolderLocation or
888 : * SHGetPathFromIDListW is unable to provide these paths (Bug 513958).
889 : */
890 : static nsresult
891 : GetRegWindowsAppDataFolder(bool aLocal, nsAString& _retval)
892 : {
893 : HKEY key;
894 : NS_NAMED_LITERAL_STRING(keyName,
895 : "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
896 : DWORD res = ::RegOpenKeyExW(HKEY_CURRENT_USER, keyName.get(), 0, KEY_READ,
897 : &key);
898 : if (res != ERROR_SUCCESS) {
899 : _retval.SetLength(0);
900 : return NS_ERROR_NOT_AVAILABLE;
901 : }
902 :
903 : DWORD type, size;
904 : res = RegQueryValueExW(key, (aLocal ? L"Local AppData" : L"AppData"), NULL,
905 : &type, NULL, &size);
906 : // The call to RegQueryValueExW must succeed, the type must be REG_SZ, the
907 : // buffer size must not equal 0, and the buffer size be a multiple of 2.
908 : if (res != ERROR_SUCCESS || type != REG_SZ || size == 0 || size % 2 != 0) {
909 : ::RegCloseKey(key);
910 : _retval.SetLength(0);
911 : return NS_ERROR_NOT_AVAILABLE;
912 : }
913 :
914 : // |size| includes room for the terminating null character
915 : DWORD resultLen = size / 2 - 1;
916 :
917 : _retval.SetLength(resultLen);
918 : nsAString::iterator begin;
919 : _retval.BeginWriting(begin);
920 : if (begin.size_forward() != resultLen) {
921 : ::RegCloseKey(key);
922 : _retval.SetLength(0);
923 : return NS_ERROR_NOT_AVAILABLE;
924 : }
925 :
926 : res = RegQueryValueExW(key, (aLocal ? L"Local AppData" : L"AppData"), NULL,
927 : NULL, (LPBYTE) begin.get(), &size);
928 : ::RegCloseKey(key);
929 : if (res != ERROR_SUCCESS) {
930 : _retval.SetLength(0);
931 : return NS_ERROR_NOT_AVAILABLE;
932 : }
933 :
934 : return NS_OK;
935 : }
936 :
937 : nsresult
938 : nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
939 : {
940 : nsCOMPtr<nsIFile> appDir = GetAppDir();
941 :
942 : nsAutoString appPath;
943 : nsresult rv = appDir->GetPath(appPath);
944 : NS_ENSURE_SUCCESS(rv, rv);
945 :
946 : // AppDir may be a short path. Convert to long path to make sure
947 : // the consistency of the update folder location
948 : nsString longPath;
949 : PRUnichar* buf;
950 :
951 : PRUint32 bufLength = longPath.GetMutableData(&buf, MAXPATHLEN);
952 : NS_ENSURE_TRUE(bufLength >= MAXPATHLEN, NS_ERROR_OUT_OF_MEMORY);
953 :
954 : DWORD len = GetLongPathNameW(appPath.get(), buf, bufLength);
955 :
956 : // Failing GetLongPathName() is not fatal.
957 : if (len <= 0 || len >= bufLength)
958 : longPath.Assign(appPath);
959 : else
960 : longPath.SetLength(len);
961 :
962 : // Use <UserLocalDataDir>\updates\<relative path to app dir from
963 : // Program Files> if app dir is under Program Files to avoid the
964 : // folder virtualization mess on Windows Vista
965 : nsAutoString programFiles;
966 : rv = GetShellFolderPath(CSIDL_PROGRAM_FILES, programFiles);
967 : NS_ENSURE_SUCCESS(rv, rv);
968 :
969 : programFiles.AppendLiteral("\\");
970 : PRUint32 programFilesLen = programFiles.Length();
971 :
972 : if (longPath.Length() < programFilesLen)
973 : return NS_ERROR_FAILURE;
974 :
975 : if (_wcsnicmp(programFiles.get(), longPath.get(), programFilesLen) != 0)
976 : return NS_ERROR_FAILURE;
977 :
978 : nsCOMPtr<nsILocalFile> updRoot;
979 : rv = GetUserLocalDataDirectory(getter_AddRefs(updRoot));
980 : NS_ENSURE_SUCCESS(rv, rv);
981 :
982 : rv = updRoot->AppendRelativePath(Substring(longPath, programFilesLen));
983 : NS_ENSURE_SUCCESS(rv, rv);
984 :
985 : NS_ADDREF(*aResult = updRoot);
986 : return NS_OK;
987 : }
988 : #endif
989 :
990 : nsresult
991 0 : nsXREDirProvider::GetProfileStartupDir(nsIFile* *aResult)
992 : {
993 0 : if (mProfileDir)
994 0 : return mProfileDir->Clone(aResult);
995 :
996 0 : if (mAppProvider) {
997 0 : nsCOMPtr<nsIFile> needsclone;
998 : bool dummy;
999 0 : nsresult rv = mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP,
1000 : &dummy,
1001 0 : getter_AddRefs(needsclone));
1002 0 : if (NS_SUCCEEDED(rv))
1003 0 : return needsclone->Clone(aResult);
1004 : }
1005 :
1006 0 : return NS_ERROR_FAILURE;
1007 : }
1008 :
1009 : nsresult
1010 0 : nsXREDirProvider::GetProfileDir(nsIFile* *aResult)
1011 : {
1012 0 : if (mProfileDir) {
1013 0 : if (!mProfileNotified)
1014 0 : return NS_ERROR_FAILURE;
1015 :
1016 0 : return mProfileDir->Clone(aResult);
1017 : }
1018 :
1019 0 : if (mAppProvider) {
1020 0 : nsCOMPtr<nsIFile> needsclone;
1021 : bool dummy;
1022 0 : nsresult rv = mAppProvider->GetFile(NS_APP_USER_PROFILE_50_DIR,
1023 : &dummy,
1024 0 : getter_AddRefs(needsclone));
1025 0 : if (NS_SUCCEEDED(rv))
1026 0 : return needsclone->Clone(aResult);
1027 : }
1028 :
1029 0 : return NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aResult);
1030 : }
1031 :
1032 : nsresult
1033 22 : nsXREDirProvider::GetUserDataDirectoryHome(nsILocalFile** aFile, bool aLocal)
1034 : {
1035 : // Copied from nsAppFileLocationProvider (more or less)
1036 : nsresult rv;
1037 44 : nsCOMPtr<nsILocalFile> localDir;
1038 :
1039 : #if defined(XP_MACOSX)
1040 : FSRef fsRef;
1041 : OSType folderType;
1042 : if (aLocal) {
1043 : folderType = kCachedDataFolderType;
1044 : } else {
1045 : #ifdef MOZ_THUNDERBIRD
1046 : folderType = kDomainLibraryFolderType;
1047 : #else
1048 : folderType = kApplicationSupportFolderType;
1049 : #endif
1050 : }
1051 : OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
1052 : NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
1053 :
1054 : rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localDir));
1055 : NS_ENSURE_SUCCESS(rv, rv);
1056 :
1057 : nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir);
1058 : NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED);
1059 :
1060 : rv = dirFileMac->InitWithFSRef(&fsRef);
1061 : NS_ENSURE_SUCCESS(rv, rv);
1062 :
1063 : localDir = do_QueryInterface(dirFileMac, &rv);
1064 : #elif defined(XP_WIN)
1065 : nsString path;
1066 : if (aLocal) {
1067 : rv = GetShellFolderPath(CSIDL_LOCAL_APPDATA, path);
1068 : if (NS_FAILED(rv))
1069 : rv = GetRegWindowsAppDataFolder(aLocal, path);
1070 : }
1071 : if (!aLocal || NS_FAILED(rv)) {
1072 : rv = GetShellFolderPath(CSIDL_APPDATA, path);
1073 : if (NS_FAILED(rv)) {
1074 : if (!aLocal)
1075 : rv = GetRegWindowsAppDataFolder(aLocal, path);
1076 : }
1077 : }
1078 : NS_ENSURE_SUCCESS(rv, rv);
1079 :
1080 : rv = NS_NewLocalFile(path, true, getter_AddRefs(localDir));
1081 : #elif defined(XP_OS2)
1082 : #if 0 /* For OS/2 we want to always use MOZILLA_HOME */
1083 : // we want an environment variable of the form
1084 : // FIREFOX_HOME, etc
1085 : if (!gAppData)
1086 : return NS_ERROR_FAILURE;
1087 : nsDependentCString envVar(nsDependentCString(gAppData->name));
1088 : envVar.Append("_HOME");
1089 : char *pHome = getenv(envVar.get());
1090 : #endif
1091 : char *pHome = getenv("MOZILLA_HOME");
1092 : if (pHome && *pHome) {
1093 : rv = NS_NewNativeLocalFile(nsDependentCString(pHome), true,
1094 : getter_AddRefs(localDir));
1095 : } else {
1096 : PPIB ppib;
1097 : PTIB ptib;
1098 : char appDir[CCHMAXPATH];
1099 :
1100 : DosGetInfoBlocks(&ptib, &ppib);
1101 : DosQueryModuleName(ppib->pib_hmte, CCHMAXPATH, appDir);
1102 : *strrchr(appDir, '\\') = '\0';
1103 : rv = NS_NewNativeLocalFile(nsDependentCString(appDir), true, getter_AddRefs(localDir));
1104 : }
1105 : #elif defined(MOZ_WIDGET_GONK)
1106 : rv = NS_NewNativeLocalFile(NS_LITERAL_CSTRING("/data/b2g"), PR_TRUE,
1107 : getter_AddRefs(localDir));
1108 : #elif defined(XP_UNIX)
1109 22 : const char* homeDir = getenv("HOME");
1110 22 : if (!homeDir || !*homeDir)
1111 0 : return NS_ERROR_FAILURE;
1112 :
1113 22 : rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
1114 44 : getter_AddRefs(localDir));
1115 : #else
1116 : #error "Don't know how to get product dir on your platform"
1117 : #endif
1118 :
1119 22 : NS_IF_ADDREF(*aFile = localDir);
1120 22 : return rv;
1121 : }
1122 :
1123 : nsresult
1124 0 : nsXREDirProvider::GetSysUserExtensionsDirectory(nsILocalFile** aFile)
1125 : {
1126 0 : nsCOMPtr<nsILocalFile> localDir;
1127 0 : nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), false);
1128 0 : NS_ENSURE_SUCCESS(rv, rv);
1129 :
1130 0 : rv = AppendSysUserExtensionPath(localDir);
1131 0 : NS_ENSURE_SUCCESS(rv, rv);
1132 :
1133 0 : rv = EnsureDirectoryExists(localDir);
1134 0 : NS_ENSURE_SUCCESS(rv, rv);
1135 :
1136 0 : NS_ADDREF(*aFile = localDir);
1137 0 : return NS_OK;
1138 : }
1139 :
1140 : #if defined(XP_UNIX) || defined(XP_MACOSX)
1141 : nsresult
1142 0 : nsXREDirProvider::GetSystemExtensionsDirectory(nsILocalFile** aFile)
1143 : {
1144 : nsresult rv;
1145 0 : nsCOMPtr<nsILocalFile> localDir;
1146 : #if defined(XP_MACOSX)
1147 : FSRef fsRef;
1148 : OSErr err = ::FSFindFolder(kOnSystemDisk, kApplicationSupportFolderType, kCreateFolder, &fsRef);
1149 : NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
1150 :
1151 : rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localDir));
1152 : NS_ENSURE_SUCCESS(rv, rv);
1153 :
1154 : nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir);
1155 : NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED);
1156 :
1157 : rv = dirFileMac->InitWithFSRef(&fsRef);
1158 : NS_ENSURE_SUCCESS(rv, rv);
1159 :
1160 : localDir = do_QueryInterface(dirFileMac, &rv);
1161 :
1162 : static const char* const sXR = "Mozilla";
1163 : rv = localDir->AppendNative(nsDependentCString(sXR));
1164 : NS_ENSURE_SUCCESS(rv, rv);
1165 :
1166 : static const char* const sExtensions = "Extensions";
1167 : rv = localDir->AppendNative(nsDependentCString(sExtensions));
1168 : NS_ENSURE_SUCCESS(rv, rv);
1169 : #elif defined(XP_UNIX)
1170 : static const char *const sysSExtDir =
1171 : #ifdef HAVE_USR_LIB64_DIR
1172 : "/usr/lib64/mozilla/extensions";
1173 : #else
1174 : "/usr/lib/mozilla/extensions";
1175 : #endif
1176 :
1177 0 : rv = NS_NewNativeLocalFile(nsDependentCString(sysSExtDir), false,
1178 0 : getter_AddRefs(localDir));
1179 0 : NS_ENSURE_SUCCESS(rv, rv);
1180 : #endif
1181 :
1182 0 : NS_ADDREF(*aFile = localDir);
1183 0 : return NS_OK;
1184 : }
1185 : #endif
1186 :
1187 : nsresult
1188 22 : nsXREDirProvider::GetUserDataDirectory(nsILocalFile** aFile, bool aLocal)
1189 : {
1190 44 : nsCOMPtr<nsILocalFile> localDir;
1191 22 : nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), aLocal);
1192 22 : NS_ENSURE_SUCCESS(rv, rv);
1193 :
1194 22 : rv = AppendProfilePath(localDir);
1195 22 : NS_ENSURE_SUCCESS(rv, rv);
1196 :
1197 : #ifdef DEBUG_jungshik
1198 : nsCAutoString cwd;
1199 : localDir->GetNativePath(cwd);
1200 : printf("nsXREDirProvider::GetUserDataDirectory: %s\n", cwd.get());
1201 : #endif
1202 22 : rv = EnsureDirectoryExists(localDir);
1203 22 : NS_ENSURE_SUCCESS(rv, rv);
1204 :
1205 22 : NS_ADDREF(*aFile = localDir);
1206 22 : return NS_OK;
1207 : }
1208 :
1209 : nsresult
1210 22 : nsXREDirProvider::EnsureDirectoryExists(nsIFile* aDirectory)
1211 : {
1212 : bool exists;
1213 22 : nsresult rv = aDirectory->Exists(&exists);
1214 22 : NS_ENSURE_SUCCESS(rv, rv);
1215 : #ifdef DEBUG_jungshik
1216 : if (!exists) {
1217 : nsCAutoString cwd;
1218 : aDirectory->GetNativePath(cwd);
1219 : printf("nsXREDirProvider::EnsureDirectoryExists: %s does not\n", cwd.get());
1220 : }
1221 : #endif
1222 22 : if (!exists)
1223 0 : rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0700);
1224 : #ifdef DEBUG_jungshik
1225 : if (NS_FAILED(rv))
1226 : NS_WARNING("nsXREDirProvider::EnsureDirectoryExists: create failed");
1227 : #endif
1228 :
1229 22 : return rv;
1230 : }
1231 :
1232 : void
1233 0 : nsXREDirProvider::EnsureProfileFileExists(nsIFile *aFile)
1234 : {
1235 : nsresult rv;
1236 : bool exists;
1237 :
1238 0 : rv = aFile->Exists(&exists);
1239 0 : if (NS_FAILED(rv) || exists) return;
1240 :
1241 0 : nsCAutoString leafName;
1242 0 : rv = aFile->GetNativeLeafName(leafName);
1243 0 : if (NS_FAILED(rv)) return;
1244 :
1245 0 : nsCOMPtr<nsIFile> defaultsFile;
1246 0 : rv = GetProfileDefaultsDir(getter_AddRefs(defaultsFile));
1247 0 : if (NS_FAILED(rv)) return;
1248 :
1249 0 : rv = defaultsFile->AppendNative(leafName);
1250 0 : if (NS_FAILED(rv)) return;
1251 :
1252 0 : defaultsFile->CopyToNative(mProfileDir, EmptyCString());
1253 : }
1254 :
1255 : nsresult
1256 0 : nsXREDirProvider::GetProfileDefaultsDir(nsIFile* *aResult)
1257 : {
1258 0 : NS_ASSERTION(mGREDir, "nsXREDirProvider not initialized.");
1259 0 : NS_PRECONDITION(aResult, "Null out-param");
1260 :
1261 : nsresult rv;
1262 0 : nsCOMPtr<nsIFile> defaultsDir;
1263 :
1264 0 : rv = GetAppDir()->Clone(getter_AddRefs(defaultsDir));
1265 0 : NS_ENSURE_SUCCESS(rv, rv);
1266 :
1267 0 : rv = defaultsDir->AppendNative(NS_LITERAL_CSTRING("defaults"));
1268 0 : NS_ENSURE_SUCCESS(rv, rv);
1269 :
1270 0 : rv = defaultsDir->AppendNative(NS_LITERAL_CSTRING("profile"));
1271 0 : NS_ENSURE_SUCCESS(rv, rv);
1272 :
1273 0 : NS_ADDREF(*aResult = defaultsDir);
1274 0 : return NS_OK;
1275 : }
1276 :
1277 : nsresult
1278 0 : nsXREDirProvider::AppendSysUserExtensionPath(nsIFile* aFile)
1279 : {
1280 0 : NS_ASSERTION(aFile, "Null pointer!");
1281 :
1282 : nsresult rv;
1283 :
1284 : #if defined (XP_MACOSX) || defined(XP_WIN) || defined(XP_OS2)
1285 :
1286 : static const char* const sXR = "Mozilla";
1287 : rv = aFile->AppendNative(nsDependentCString(sXR));
1288 : NS_ENSURE_SUCCESS(rv, rv);
1289 :
1290 : static const char* const sExtensions = "Extensions";
1291 : rv = aFile->AppendNative(nsDependentCString(sExtensions));
1292 : NS_ENSURE_SUCCESS(rv, rv);
1293 :
1294 : #elif defined(XP_UNIX)
1295 :
1296 : static const char* const sXR = ".mozilla";
1297 0 : rv = aFile->AppendNative(nsDependentCString(sXR));
1298 0 : NS_ENSURE_SUCCESS(rv, rv);
1299 :
1300 : static const char* const sExtensions = "extensions";
1301 0 : rv = aFile->AppendNative(nsDependentCString(sExtensions));
1302 0 : NS_ENSURE_SUCCESS(rv, rv);
1303 :
1304 : #else
1305 : #error "Don't know how to get XRE user extension path on your platform"
1306 : #endif
1307 0 : return NS_OK;
1308 : }
1309 :
1310 :
1311 : nsresult
1312 22 : nsXREDirProvider::AppendProfilePath(nsIFile* aFile)
1313 : {
1314 22 : NS_ASSERTION(aFile, "Null pointer!");
1315 :
1316 : nsresult rv;
1317 :
1318 22 : if (!gAppData)
1319 0 : return NS_ERROR_FAILURE;
1320 :
1321 : #if defined (XP_MACOSX)
1322 : if (gAppData->profile) {
1323 : rv = AppendProfileString(aFile, gAppData->profile);
1324 : }
1325 : else {
1326 : // Note that MacOS ignores the vendor when creating the profile hierarchy -
1327 : // all application preferences directories live alongside one another in
1328 : // ~/Library/Application Support/
1329 : rv = aFile->AppendNative(nsDependentCString(gAppData->name));
1330 : }
1331 : NS_ENSURE_SUCCESS(rv, rv);
1332 :
1333 : #elif defined(XP_WIN) || defined(XP_OS2)
1334 : if (gAppData->profile) {
1335 : rv = AppendProfileString(aFile, gAppData->profile);
1336 : }
1337 : else {
1338 : if (gAppData->vendor) {
1339 : rv = aFile->AppendNative(nsDependentCString(gAppData->vendor));
1340 : NS_ENSURE_SUCCESS(rv, rv);
1341 : }
1342 : rv = aFile->AppendNative(nsDependentCString(gAppData->name));
1343 : }
1344 : NS_ENSURE_SUCCESS(rv, rv);
1345 :
1346 : #elif defined(ANDROID)
1347 : // The directory used for storing profiles
1348 : // The parent of this directory is set in GetUserDataDirectoryHome
1349 : // XXX: handle gAppData->profile properly
1350 : rv = aFile->AppendNative(nsDependentCString("mozilla"));
1351 : NS_ENSURE_SUCCESS(rv, rv);
1352 : #elif defined(XP_UNIX)
1353 : // Make it hidden (i.e. using the ".")
1354 44 : nsCAutoString folder(".");
1355 :
1356 22 : if (gAppData->profile) {
1357 : // Skip any leading path characters
1358 0 : const char* profileStart = gAppData->profile;
1359 0 : while (*profileStart == '/' || *profileStart == '\\')
1360 0 : profileStart++;
1361 :
1362 : // On the off chance that someone wanted their folder to be hidden don't
1363 : // let it become ".."
1364 0 : if (*profileStart == '.')
1365 0 : profileStart++;
1366 :
1367 0 : folder.Append(profileStart);
1368 0 : ToLowerCase(folder);
1369 :
1370 0 : rv = AppendProfileString(aFile, folder.BeginReading());
1371 : }
1372 : else {
1373 22 : if (gAppData->vendor) {
1374 22 : folder.Append(gAppData->vendor);
1375 22 : ToLowerCase(folder);
1376 :
1377 22 : rv = aFile->AppendNative(folder);
1378 22 : NS_ENSURE_SUCCESS(rv, rv);
1379 :
1380 22 : folder.Truncate();
1381 : }
1382 :
1383 22 : folder.Append(gAppData->name);
1384 22 : ToLowerCase(folder);
1385 :
1386 22 : rv = aFile->AppendNative(folder);
1387 : }
1388 22 : NS_ENSURE_SUCCESS(rv, rv);
1389 :
1390 : #else
1391 : #error "Don't know how to get profile path on your platform"
1392 : #endif
1393 22 : return NS_OK;
1394 : }
1395 :
1396 : nsresult
1397 0 : nsXREDirProvider::AppendProfileString(nsIFile* aFile, const char* aPath)
1398 : {
1399 0 : NS_ASSERTION(aFile, "Null file!");
1400 0 : NS_ASSERTION(aPath, "Null path!");
1401 :
1402 0 : nsCAutoString pathDup(aPath);
1403 :
1404 0 : char* path = pathDup.BeginWriting();
1405 :
1406 : nsresult rv;
1407 : char* subdir;
1408 0 : while ((subdir = NS_strtok("/\\", &path))) {
1409 0 : rv = aFile->AppendNative(nsDependentCString(subdir));
1410 0 : NS_ENSURE_SUCCESS(rv, rv);
1411 : }
1412 :
1413 0 : return NS_OK;
1414 : }
|