Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/toolkit/xre/nsXREDirProvider.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "nsAppRunner.h"
7
#include "nsToolkitCompsCID.h"
8
#include "nsXREDirProvider.h"
9
10
#include "jsapi.h"
11
#include "xpcpublic.h"
12
13
#include "nsIAppStartup.h"
14
#include "nsIDirectoryEnumerator.h"
15
#include "nsIFile.h"
16
#include "nsIObserver.h"
17
#include "nsIObserverService.h"
18
#include "nsISimpleEnumerator.h"
19
#include "nsIToolkitChromeRegistry.h"
20
#include "nsIToolkitProfileService.h"
21
#include "nsIXULRuntime.h"
22
23
#include "nsAppDirectoryServiceDefs.h"
24
#include "nsDirectoryServiceDefs.h"
25
#include "nsDirectoryServiceUtils.h"
26
#include "nsXULAppAPI.h"
27
#include "nsCategoryManagerUtils.h"
28
29
#include "nsDependentString.h"
30
#include "nsCOMArray.h"
31
#include "nsArrayEnumerator.h"
32
#include "nsEnumeratorUtils.h"
33
#include "nsReadableUtils.h"
34
35
#include "SpecialSystemDirectory.h"
36
37
#include "mozilla/dom/ScriptSettings.h"
38
39
#include "mozilla/AutoRestore.h"
40
#include "mozilla/Services.h"
41
#include "mozilla/Omnijar.h"
42
#include "mozilla/Preferences.h"
43
#include "mozilla/Telemetry.h"
44
45
#include <stdlib.h>
46
#include "city.h"
47
48
#ifdef XP_WIN
49
#include <windows.h>
50
#include <shlobj.h>
51
#endif
52
#ifdef XP_MACOSX
53
#include "nsILocalFileMac.h"
54
// for chflags()
55
#include <sys/stat.h>
56
#include <unistd.h>
57
#endif
58
#ifdef XP_UNIX
59
#include <ctype.h>
60
#endif
61
#ifdef XP_IOS
62
#include "UIKitDirProvider.h"
63
#endif
64
65
#if defined(MOZ_CONTENT_SANDBOX)
66
#include "mozilla/SandboxSettings.h"
67
#include "nsIUUIDGenerator.h"
68
#include "mozilla/Unused.h"
69
#if defined(XP_WIN)
70
#include "WinUtils.h"
71
#endif
72
#endif
73
74
#if defined(XP_MACOSX)
75
#define APP_REGISTRY_NAME "Application Registry"
76
#elif defined(XP_WIN)
77
#define APP_REGISTRY_NAME "registry.dat"
78
#else
79
#define APP_REGISTRY_NAME "appreg"
80
#endif
81
82
#define PREF_OVERRIDE_DIRNAME "preferences"
83
84
#if defined(MOZ_CONTENT_SANDBOX)
85
static already_AddRefed<nsIFile> GetContentProcessSandboxTempDir();
86
static nsresult DeleteDirIfExists(nsIFile *dir);
87
static bool IsContentSandboxDisabled();
88
static const char* GetContentProcessTempBaseDirKey();
89
static already_AddRefed<nsIFile> CreateContentProcessSandboxTempDir();
90
#endif
91
92
nsXREDirProvider* gDirServiceProvider = nullptr;
93
nsIFile* gDataDirHomeLocal = nullptr;
94
nsIFile* gDataDirHome = nullptr;
95
96
// These are required to allow nsXREDirProvider to be usable in xpcshell tests.
97
// where gAppData is null.
98
static const char*
99
0
GetAppProfile() {
100
0
  if (gAppData) {
101
0
    return gAppData->profile;
102
0
  }
103
0
  return nullptr;
104
0
}
105
106
static const char*
107
0
GetAppName() {
108
0
  if (gAppData) {
109
0
    return gAppData->name;
110
0
  }
111
0
  return nullptr;
112
0
}
113
114
static const char*
115
0
GetAppVendor() {
116
0
  if (gAppData) {
117
0
    return gAppData->vendor;
118
0
  }
119
0
  return nullptr;
120
0
}
121
122
nsXREDirProvider::nsXREDirProvider() :
123
  mProfileNotified(false)
124
3
{
125
3
  gDirServiceProvider = this;
126
3
}
127
128
nsXREDirProvider::~nsXREDirProvider()
129
0
{
130
0
  gDirServiceProvider = nullptr;
131
0
  gDataDirHomeLocal = nullptr;
132
0
  gDataDirHome = nullptr;
133
0
}
134
135
already_AddRefed<nsXREDirProvider>
136
nsXREDirProvider::GetSingleton()
137
0
{
138
0
  if (!gDirServiceProvider) {
139
0
    new nsXREDirProvider(); // This sets gDirServiceProvider
140
0
  }
141
0
  return do_AddRef(gDirServiceProvider);
142
0
}
143
144
nsresult
145
nsXREDirProvider::Initialize(nsIFile *aXULAppDir,
146
                             nsIFile *aGREDir,
147
                             nsIDirectoryServiceProvider* aAppProvider)
148
3
{
149
3
  NS_ENSURE_ARG(aXULAppDir);
150
3
  NS_ENSURE_ARG(aGREDir);
151
3
152
3
  mAppProvider = aAppProvider;
153
3
  mXULAppDir = aXULAppDir;
154
3
  mGREDir = aGREDir;
155
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
156
  // The GRE directory can be used in sandbox rules, so we need to make sure
157
  // it doesn't contain any junction points or symlinks or the sandbox will
158
  // reject those rules.
159
  if (!mozilla::widget::WinUtils::ResolveJunctionPointsAndSymLinks(mGREDir)) {
160
    NS_WARNING("Failed to resolve GRE Dir.");
161
  }
162
  // If the mXULAppDir is different it lives below the mGREDir. To avoid
163
  // confusion resolve that as well even though we don't need it for sandbox
164
  // rules. Some tests rely on this for example.
165
  if (!mozilla::widget::WinUtils::ResolveJunctionPointsAndSymLinks(mXULAppDir)) {
166
    NS_WARNING("Failed to resolve XUL App Dir.");
167
  }
168
#endif
169
  mGREDir->Clone(getter_AddRefs(mGREBinDir));
170
#ifdef XP_MACOSX
171
  mGREBinDir->SetNativeLeafName(NS_LITERAL_CSTRING("MacOS"));
172
#endif
173
174
3
  if (!mProfileDir) {
175
3
    nsCOMPtr<nsIDirectoryServiceProvider> app(do_QueryInterface(mAppProvider));
176
3
    if (app) {
177
0
      bool per = false;
178
0
      app->GetFile(NS_APP_USER_PROFILE_50_DIR, &per, getter_AddRefs(mProfileDir));
179
0
      NS_ASSERTION(per, "NS_APP_USER_PROFILE_50_DIR must be persistent!");
180
0
      NS_ASSERTION(mProfileDir, "NS_APP_USER_PROFILE_50_DIR not defined! This shouldn't happen!");
181
0
    }
182
3
  }
183
3
184
3
  return NS_OK;
185
3
}
186
187
nsresult
188
nsXREDirProvider::SetProfile(nsIFile* aDir, nsIFile* aLocalDir)
189
0
{
190
0
  NS_ASSERTION(aDir && aLocalDir, "We don't support no-profile apps yet!");
191
0
192
0
  nsresult rv;
193
0
194
0
  rv = EnsureDirectoryExists(aDir);
195
0
  if (NS_FAILED(rv))
196
0
    return rv;
197
0
198
0
  rv = EnsureDirectoryExists(aLocalDir);
199
0
  if (NS_FAILED(rv))
200
0
    return rv;
201
0
202
#ifdef XP_MACOSX
203
  bool same;
204
  if (NS_SUCCEEDED(aDir->Equals(aLocalDir, &same)) && !same) {
205
    // Ensure that the cache directory is not indexed by Spotlight
206
    // (bug 718910).  At least on OS X, the cache directory (under
207
    // ~/Library/Caches/) is always the "local" user profile
208
    // directory.  This is confusing, since *both* user profile
209
    // directories are "local" (they both exist under the user's
210
    // home directory).  But this usage dates back at least as far
211
    // as the patch for bug 291033, where "local" seems to mean
212
    // "suitable for temporary storage".  Don't hide the cache
213
    // directory if by some chance it and the "non-local" profile
214
    // directory are the same -- there are bad side effects from
215
    // hiding a profile directory under /Library/Application Support/
216
    // (see bug 801883).
217
    nsAutoCString cacheDir;
218
    if (NS_SUCCEEDED(aLocalDir->GetNativePath(cacheDir))) {
219
      if (chflags(cacheDir.get(), UF_HIDDEN)) {
220
        NS_WARNING("Failed to set Cache directory to HIDDEN.");
221
      }
222
    }
223
  }
224
#endif
225
226
0
  mProfileDir = aDir;
227
0
  mProfileLocalDir = aLocalDir;
228
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
229
  // The profile directory can be used in sandbox rules, so we need to make sure
230
  // it doesn't contain any junction points or symlinks or the sandbox will
231
  // reject those rules.
232
  if (!mozilla::widget::WinUtils::ResolveJunctionPointsAndSymLinks(mProfileDir)) {
233
    NS_WARNING("Failed to resolve Profile Dir.");
234
  }
235
#endif
236
  return NS_OK;
237
0
}
238
239
NS_IMPL_QUERY_INTERFACE(nsXREDirProvider,
240
                        nsIDirectoryServiceProvider,
241
                        nsIDirectoryServiceProvider2,
242
                        nsIXREDirProvider,
243
                        nsIProfileStartup)
244
245
NS_IMETHODIMP_(MozExternalRefCountType)
246
nsXREDirProvider::AddRef()
247
0
{
248
0
  return 1;
249
0
}
250
251
NS_IMETHODIMP_(MozExternalRefCountType)
252
nsXREDirProvider::Release()
253
0
{
254
0
  return 0;
255
0
}
256
257
nsresult
258
nsXREDirProvider::GetUserProfilesRootDir(nsIFile** aResult)
259
0
{
260
0
  nsCOMPtr<nsIFile> file;
261
0
  nsresult rv = GetUserDataDirectory(getter_AddRefs(file), false);
262
0
263
0
  if (NS_SUCCEEDED(rv)) {
264
#if !defined(XP_UNIX) || defined(XP_MACOSX)
265
    rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
266
#endif
267
    // We must create the profile directory here if it does not exist.
268
0
    nsresult tmp = EnsureDirectoryExists(file);
269
0
    if (NS_FAILED(tmp)) {
270
0
      rv = tmp;
271
0
    }
272
0
  }
273
0
  file.swap(*aResult);
274
0
  return rv;
275
0
}
276
277
nsresult
278
nsXREDirProvider::GetUserProfilesLocalDir(nsIFile** aResult)
279
0
{
280
0
  nsCOMPtr<nsIFile> file;
281
0
  nsresult rv = GetUserDataDirectory(getter_AddRefs(file), true);
282
0
283
0
  if (NS_SUCCEEDED(rv)) {
284
#if !defined(XP_UNIX) || defined(XP_MACOSX)
285
    rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
286
#endif
287
    // We must create the profile directory here if it does not exist.
288
0
    nsresult tmp = EnsureDirectoryExists(file);
289
0
    if (NS_FAILED(tmp)) {
290
0
      rv = tmp;
291
0
    }
292
0
  }
293
0
  file.swap(*aResult);
294
0
  return NS_OK;
295
0
}
296
297
#if defined(XP_UNIX) || defined(XP_MACOSX)
298
/**
299
 * Get the directory that is the parent of the system-wide directories
300
 * for extensions and native manifests.
301
 *
302
 * On OSX this is /Library/Application Support/Mozilla
303
 * On Linux this is /usr/{lib,lib64}/mozilla
304
 *   (for 32- and 64-bit systems respsectively)
305
 */
306
static nsresult
307
GetSystemParentDirectory(nsIFile** aFile)
308
0
{
309
0
  nsresult rv;
310
0
  nsCOMPtr<nsIFile> localDir;
311
#if defined(XP_MACOSX)
312
  rv = GetOSXFolderType(kOnSystemDisk, kApplicationSupportFolderType, getter_AddRefs(localDir));
313
  if (NS_SUCCEEDED(rv)) {
314
    rv = localDir->AppendNative(NS_LITERAL_CSTRING("Mozilla"));
315
  }
316
#else
317
0
  NS_NAMED_LITERAL_CSTRING(dirname,
318
#ifdef HAVE_USR_LIB64_DIR
319
                           "/usr/lib64/mozilla"
320
#elif defined(__OpenBSD__) || defined(__FreeBSD__)
321
                           "/usr/local/lib/mozilla"
322
#else
323
                           "/usr/lib/mozilla"
324
0
#endif
325
0
                           );
326
0
  rv = NS_NewNativeLocalFile(dirname, false, getter_AddRefs(localDir));
327
0
#endif
328
0
329
0
  if (NS_SUCCEEDED(rv)) {
330
0
    localDir.forget(aFile);
331
0
  }
332
0
  return rv;
333
0
}
334
#endif
335
336
NS_IMETHODIMP
337
nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent,
338
                          nsIFile** aFile)
339
0
{
340
0
  nsresult rv;
341
0
342
0
  bool gettingProfile = false;
343
0
344
0
  if (!strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR)) {
345
0
    // If XRE_NotifyProfile hasn't been called, don't fall through to
346
0
    // mAppProvider on the profile keys.
347
0
    if (!mProfileNotified)
348
0
      return NS_ERROR_FAILURE;
349
0
350
0
    if (mProfileLocalDir)
351
0
      return mProfileLocalDir->Clone(aFile);
352
0
353
0
    if (mAppProvider)
354
0
      return mAppProvider->GetFile(aProperty, aPersistent, aFile);
355
0
356
0
    // This falls through to the case below
357
0
    gettingProfile = true;
358
0
  }
359
0
  if (!strcmp(aProperty, NS_APP_USER_PROFILE_50_DIR) || gettingProfile) {
360
0
    if (!mProfileNotified)
361
0
      return NS_ERROR_FAILURE;
362
0
363
0
    if (mProfileDir)
364
0
      return mProfileDir->Clone(aFile);
365
0
366
0
    if (mAppProvider)
367
0
      return mAppProvider->GetFile(aProperty, aPersistent, aFile);
368
0
369
0
    // If we don't succeed here, bail early so that we aren't reentrant
370
0
    // through the "GetProfileDir" call below.
371
0
    return NS_ERROR_FAILURE;
372
0
  }
373
0
374
0
  if (mAppProvider) {
375
0
    rv = mAppProvider->GetFile(aProperty, aPersistent, aFile);
376
0
    if (NS_SUCCEEDED(rv) && *aFile)
377
0
      return rv;
378
0
  }
379
0
380
0
  *aPersistent = true;
381
0
382
0
  if (!strcmp(aProperty, NS_GRE_DIR)) {
383
0
    return mGREDir->Clone(aFile);
384
0
  }
385
0
  else if (!strcmp(aProperty, NS_GRE_BIN_DIR)) {
386
0
    return mGREBinDir->Clone(aFile);
387
0
  }
388
0
  else if (!strcmp(aProperty, NS_OS_CURRENT_PROCESS_DIR) ||
389
0
           !strcmp(aProperty, NS_APP_INSTALL_CLEANUP_DIR)) {
390
0
    return GetAppDir()->Clone(aFile);
391
0
  }
392
0
393
0
  rv = NS_ERROR_FAILURE;
394
0
  nsCOMPtr<nsIFile> file;
395
0
396
0
  if (!strcmp(aProperty, NS_APP_PREF_DEFAULTS_50_DIR))
397
0
  {
398
0
    // return the GRE default prefs directory here, and the app default prefs
399
0
    // directory (if applicable) in NS_APP_PREFS_DEFAULTS_DIR_LIST.
400
0
    rv = mGREDir->Clone(getter_AddRefs(file));
401
0
    if (NS_SUCCEEDED(rv)) {
402
0
      rv = file->AppendNative(NS_LITERAL_CSTRING("defaults"));
403
0
      if (NS_SUCCEEDED(rv))
404
0
        rv = file->AppendNative(NS_LITERAL_CSTRING("pref"));
405
0
    }
406
0
  }
407
0
  else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_DIR) ||
408
0
           !strcmp(aProperty, XRE_USER_APP_DATA_DIR)) {
409
0
    rv = GetUserAppDataDirectory(getter_AddRefs(file));
410
0
  }
411
0
#if defined(XP_UNIX) || defined(XP_MACOSX)
412
0
  else if (!strcmp(aProperty, XRE_SYS_NATIVE_MANIFESTS)) {
413
0
    nsCOMPtr<nsIFile> localDir;
414
0
415
0
    rv = ::GetSystemParentDirectory(getter_AddRefs(localDir));
416
0
    if (NS_SUCCEEDED(rv)) {
417
0
      localDir.swap(file);
418
0
    }
419
0
  }
420
0
  else if (!strcmp(aProperty, XRE_USER_NATIVE_MANIFESTS)) {
421
0
    nsCOMPtr<nsIFile> localDir;
422
0
    rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), false);
423
0
    if (NS_SUCCEEDED(rv)) {
424
#if defined(XP_MACOSX)
425
      rv = localDir->AppendNative(NS_LITERAL_CSTRING("Mozilla"));
426
#else
427
0
      rv = localDir->AppendNative(NS_LITERAL_CSTRING(".mozilla"));
428
0
#endif
429
0
    }
430
0
    if (NS_SUCCEEDED(rv)) {
431
0
      localDir.swap(file);
432
0
    }
433
0
  }
434
0
#endif
435
0
  else if (!strcmp(aProperty, XRE_UPDATE_ROOT_DIR)) {
436
0
    rv = GetUpdateRootDir(getter_AddRefs(file));
437
0
  }
438
0
  else if (!strcmp(aProperty, NS_APP_APPLICATION_REGISTRY_FILE)) {
439
0
    rv = GetUserAppDataDirectory(getter_AddRefs(file));
440
0
    if (NS_SUCCEEDED(rv))
441
0
      rv = file->AppendNative(NS_LITERAL_CSTRING(APP_REGISTRY_NAME));
442
0
  }
443
0
  else if (!strcmp(aProperty, NS_APP_USER_PROFILES_ROOT_DIR)) {
444
0
    rv = GetUserProfilesRootDir(getter_AddRefs(file));
445
0
  }
446
0
  else if (!strcmp(aProperty, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR)) {
447
0
    rv = GetUserProfilesLocalDir(getter_AddRefs(file));
448
0
  }
449
0
  else if (!strcmp(aProperty, XRE_EXECUTABLE_FILE)) {
450
0
    nsCOMPtr<nsIFile> lf;
451
0
    rv = XRE_GetBinaryPath(getter_AddRefs(lf));
452
0
    if (NS_SUCCEEDED(rv))
453
0
      file = lf;
454
0
  }
455
0
456
0
  else if (!strcmp(aProperty, NS_APP_PROFILE_DIR_STARTUP) && mProfileDir) {
457
0
    return mProfileDir->Clone(aFile);
458
0
  }
459
0
  else if (!strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP)) {
460
0
    if (mProfileLocalDir)
461
0
      return mProfileLocalDir->Clone(aFile);
462
0
463
0
    if (mProfileDir)
464
0
      return mProfileDir->Clone(aFile);
465
0
466
0
    if (mAppProvider)
467
0
      return mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP, aPersistent,
468
0
                                   aFile);
469
0
  }
470
0
#if defined(XP_UNIX) || defined(XP_MACOSX)
471
0
  else if (!strcmp(aProperty, XRE_SYS_LOCAL_EXTENSION_PARENT_DIR)) {
472
0
#ifdef ENABLE_SYSTEM_EXTENSION_DIRS
473
0
    return GetSystemExtensionsDirectory(aFile);
474
#else
475
    return NS_ERROR_FAILURE;
476
#endif
477
  }
478
0
#endif
479
0
#if defined(XP_UNIX) && !defined(XP_MACOSX)
480
0
  else if (!strcmp(aProperty, XRE_SYS_SHARE_EXTENSION_PARENT_DIR)) {
481
0
#ifdef ENABLE_SYSTEM_EXTENSION_DIRS
482
#if defined(__OpenBSD__) || defined(__FreeBSD__)
483
    static const char *const sysLExtDir = "/usr/local/share/mozilla/extensions";
484
#else
485
    static const char *const sysLExtDir = "/usr/share/mozilla/extensions";
486
0
#endif
487
0
    return NS_NewNativeLocalFile(nsDependentCString(sysLExtDir),
488
0
                                 false, aFile);
489
#else
490
    return NS_ERROR_FAILURE;
491
#endif
492
  }
493
0
#endif
494
0
  else if (!strcmp(aProperty, XRE_USER_SYS_EXTENSION_DIR)) {
495
0
#ifdef ENABLE_SYSTEM_EXTENSION_DIRS
496
0
    return GetSysUserExtensionsDirectory(aFile);
497
#else
498
    return NS_ERROR_FAILURE;
499
#endif
500
  }
501
0
  else if (!strcmp(aProperty, XRE_USER_SYS_EXTENSION_DEV_DIR)) {
502
0
    return GetSysUserExtensionsDevDirectory(aFile);
503
0
  }
504
0
  else if (!strcmp(aProperty, XRE_APP_DISTRIBUTION_DIR)) {
505
0
    bool persistent = false;
506
0
    rv = GetFile(NS_GRE_DIR, &persistent, getter_AddRefs(file));
507
0
    if (NS_SUCCEEDED(rv))
508
0
      rv = file->AppendNative(NS_LITERAL_CSTRING("distribution"));
509
0
  }
510
0
  else if (!strcmp(aProperty, XRE_APP_FEATURES_DIR)) {
511
0
    rv = GetAppDir()->Clone(getter_AddRefs(file));
512
0
    if (NS_SUCCEEDED(rv))
513
0
      rv = file->AppendNative(NS_LITERAL_CSTRING("features"));
514
0
  }
515
0
  else if (!strcmp(aProperty, XRE_ADDON_APP_DIR)) {
516
0
    nsCOMPtr<nsIDirectoryServiceProvider> dirsvc(do_GetService("@mozilla.org/file/directory_service;1", &rv));
517
0
    if (NS_FAILED(rv))
518
0
      return rv;
519
0
    bool unused;
520
0
    rv = dirsvc->GetFile("XCurProcD", &unused, getter_AddRefs(file));
521
0
  }
522
0
#if defined(MOZ_CONTENT_SANDBOX)
523
0
  else if (!strcmp(aProperty, NS_APP_CONTENT_PROCESS_TEMP_DIR)) {
524
0
    if (!mContentTempDir && NS_FAILED((rv = LoadContentProcessTempDir()))) {
525
0
      return rv;
526
0
    }
527
0
    rv = mContentTempDir->Clone(getter_AddRefs(file));
528
0
  }
529
0
#endif // defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
530
0
  else if (NS_SUCCEEDED(GetProfileStartupDir(getter_AddRefs(file)))) {
531
0
    // We need to allow component, xpt, and chrome registration to
532
0
    // occur prior to the profile-after-change notification.
533
0
    if (!strcmp(aProperty, NS_APP_USER_CHROME_DIR)) {
534
0
      rv = file->AppendNative(NS_LITERAL_CSTRING("chrome"));
535
0
    }
536
0
  }
537
0
538
0
  if (NS_SUCCEEDED(rv) && file) {
539
0
    file.forget(aFile);
540
0
    return NS_OK;
541
0
  }
542
0
543
0
  bool ensureFilePermissions = false;
544
0
545
0
  if (NS_SUCCEEDED(GetProfileDir(getter_AddRefs(file)))) {
546
0
    if (!strcmp(aProperty, NS_APP_PREFS_50_DIR)) {
547
0
      rv = NS_OK;
548
0
    }
549
0
    else if (!strcmp(aProperty, NS_APP_PREFS_50_FILE)) {
550
0
      rv = file->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
551
0
    }
552
0
    else if (!strcmp(aProperty, NS_APP_PREFS_OVERRIDE_DIR)) {
553
0
      rv = mProfileDir->Clone(getter_AddRefs(file));
554
0
      nsresult tmp = file->AppendNative(NS_LITERAL_CSTRING(PREF_OVERRIDE_DIRNAME));
555
0
      if (NS_FAILED(tmp)) {
556
0
        rv = tmp;
557
0
      }
558
0
      tmp = EnsureDirectoryExists(file);
559
0
      if (NS_FAILED(tmp)) {
560
0
        rv = tmp;
561
0
      }
562
0
    }
563
0
  }
564
0
  if (NS_FAILED(rv) || !file)
565
0
    return NS_ERROR_FAILURE;
566
0
567
0
  if (ensureFilePermissions) {
568
0
    bool fileToEnsureExists;
569
0
    bool isWritable;
570
0
    if (NS_SUCCEEDED(file->Exists(&fileToEnsureExists)) && fileToEnsureExists
571
0
        && NS_SUCCEEDED(file->IsWritable(&isWritable)) && !isWritable) {
572
0
      uint32_t permissions;
573
0
      if (NS_SUCCEEDED(file->GetPermissions(&permissions))) {
574
0
        rv = file->SetPermissions(permissions | 0600);
575
0
        NS_ASSERTION(NS_SUCCEEDED(rv), "failed to ensure file permissions");
576
0
      }
577
0
    }
578
0
  }
579
0
580
0
  file.forget(aFile);
581
0
  return NS_OK;
582
0
}
583
584
static void
585
LoadDirIntoArray(nsIFile* dir,
586
                 const char *const *aAppendList,
587
                 nsCOMArray<nsIFile>& aDirectories)
588
0
{
589
0
  if (!dir)
590
0
    return;
591
0
592
0
  nsCOMPtr<nsIFile> subdir;
593
0
  dir->Clone(getter_AddRefs(subdir));
594
0
  if (!subdir)
595
0
    return;
596
0
597
0
  for (const char *const *a = aAppendList; *a; ++a) {
598
0
    subdir->AppendNative(nsDependentCString(*a));
599
0
  }
600
0
601
0
  bool exists;
602
0
  if (NS_SUCCEEDED(subdir->Exists(&exists)) && exists) {
603
0
    aDirectories.AppendObject(subdir);
604
0
  }
605
0
}
606
607
static void
608
LoadDirsIntoArray(const nsCOMArray<nsIFile>& aSourceDirs,
609
                  const char *const* aAppendList,
610
                  nsCOMArray<nsIFile>& aDirectories)
611
0
{
612
0
  nsCOMPtr<nsIFile> appended;
613
0
  bool exists;
614
0
615
0
  for (int32_t i = 0; i < aSourceDirs.Count(); ++i) {
616
0
    aSourceDirs[i]->Clone(getter_AddRefs(appended));
617
0
    if (!appended)
618
0
      continue;
619
0
620
0
    nsAutoCString leaf;
621
0
    appended->GetNativeLeafName(leaf);
622
0
    if (!Substring(leaf, leaf.Length() - 4).EqualsLiteral(".xpi")) {
623
0
      LoadDirIntoArray(appended,
624
0
                       aAppendList,
625
0
                       aDirectories);
626
0
    }
627
0
    else if (NS_SUCCEEDED(appended->Exists(&exists)) && exists)
628
0
      aDirectories.AppendObject(appended);
629
0
  }
630
0
}
631
632
NS_IMETHODIMP
633
nsXREDirProvider::GetFiles(const char* aProperty, nsISimpleEnumerator** aResult)
634
0
{
635
0
  nsresult rv;
636
0
637
0
  nsCOMPtr<nsISimpleEnumerator> appEnum;
638
0
  nsCOMPtr<nsIDirectoryServiceProvider2>
639
0
    appP2(do_QueryInterface(mAppProvider));
640
0
  if (appP2) {
641
0
    rv = appP2->GetFiles(aProperty, getter_AddRefs(appEnum));
642
0
    if (NS_FAILED(rv)) {
643
0
      appEnum = nullptr;
644
0
    }
645
0
    else if (rv != NS_SUCCESS_AGGREGATE_RESULT) {
646
0
      appEnum.forget(aResult);
647
0
      return NS_OK;
648
0
    }
649
0
  }
650
0
651
0
  nsCOMPtr<nsISimpleEnumerator> xreEnum;
652
0
  rv = GetFilesInternal(aProperty, getter_AddRefs(xreEnum));
653
0
  if (NS_FAILED(rv)) {
654
0
    if (appEnum) {
655
0
      appEnum.forget(aResult);
656
0
      return NS_SUCCESS_AGGREGATE_RESULT;
657
0
    }
658
0
659
0
    return rv;
660
0
  }
661
0
662
0
  rv = NS_NewUnionEnumerator(aResult, appEnum, xreEnum);
663
0
  if (NS_FAILED(rv))
664
0
    return rv;
665
0
666
0
  return NS_SUCCESS_AGGREGATE_RESULT;
667
0
}
668
669
#if defined(MOZ_CONTENT_SANDBOX)
670
671
static const char*
672
GetContentProcessTempBaseDirKey()
673
0
{
674
#if defined(XP_WIN)
675
  return NS_WIN_LOW_INTEGRITY_TEMP_BASE;
676
#else
677
0
  return NS_OS_TEMP_DIR;
678
0
#endif
679
0
}
680
681
//
682
// Sets mContentTempDir so that it refers to the appropriate temp dir.
683
// If the sandbox is enabled, NS_APP_CONTENT_PROCESS_TEMP_DIR, otherwise
684
// NS_OS_TEMP_DIR is used.
685
//
686
nsresult
687
nsXREDirProvider::LoadContentProcessTempDir()
688
0
{
689
0
  // The parent is responsible for creating the sandbox temp dir.
690
0
  if (XRE_IsParentProcess()) {
691
0
    mContentProcessSandboxTempDir = CreateContentProcessSandboxTempDir();
692
0
    mContentTempDir = mContentProcessSandboxTempDir;
693
0
  } else {
694
0
    mContentTempDir = GetContentProcessSandboxTempDir();
695
0
  }
696
0
697
0
  if (!mContentTempDir) {
698
0
    nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
699
0
                                         getter_AddRefs(mContentTempDir));
700
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
701
0
      return rv;
702
0
    }
703
0
  }
704
0
705
#if defined(XP_WIN)
706
  // The content temp dir can be used in sandbox rules, so we need to make sure
707
  // it doesn't contain any junction points or symlinks or the sandbox will
708
  // reject those rules.
709
  if (!mozilla::widget::WinUtils::ResolveJunctionPointsAndSymLinks(mContentTempDir)) {
710
    NS_WARNING("Failed to resolve Content Temp Dir.");
711
  }
712
#endif
713
714
0
  return NS_OK;
715
0
}
716
717
static bool
718
IsContentSandboxDisabled()
719
0
{
720
0
  return !BrowserTabsRemoteAutostart() || (!IsContentSandboxEnabled());
721
0
}
722
723
//
724
// If a content process sandbox temp dir is to be used, returns an nsIFile
725
// for the directory. Returns null if the content sandbox is disabled or
726
// an error occurs.
727
//
728
static already_AddRefed<nsIFile>
729
GetContentProcessSandboxTempDir()
730
0
{
731
0
  if (IsContentSandboxDisabled()) {
732
0
    return nullptr;
733
0
  }
734
0
735
0
  nsCOMPtr<nsIFile> localFile;
736
0
737
0
  nsresult rv = NS_GetSpecialDirectory(GetContentProcessTempBaseDirKey(),
738
0
                                       getter_AddRefs(localFile));
739
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
740
0
    return nullptr;
741
0
  }
742
0
743
0
  nsAutoString tempDirSuffix;
744
0
  rv = Preferences::GetString("security.sandbox.content.tempDirSuffix",
745
0
                              tempDirSuffix);
746
0
  if (NS_WARN_IF(NS_FAILED(rv)) || tempDirSuffix.IsEmpty()) {
747
0
    return nullptr;
748
0
  }
749
0
750
0
  rv = localFile->Append(NS_LITERAL_STRING("Temp-") + tempDirSuffix);
751
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
752
0
    return nullptr;
753
0
  }
754
0
755
0
  return localFile.forget();
756
0
}
757
758
//
759
// Create a temporary directory for use from sandboxed content processes.
760
// Only called in the parent. The path is derived from a UUID stored in a
761
// pref which is available to content processes. Returns null if the
762
// content sandbox is disabled or if an error occurs.
763
//
764
static already_AddRefed<nsIFile>
765
CreateContentProcessSandboxTempDir()
766
0
{
767
0
  if (IsContentSandboxDisabled()) {
768
0
    return nullptr;
769
0
  }
770
0
771
0
  // Get (and create if blank) temp directory suffix pref.
772
0
  nsresult rv;
773
0
  nsAutoString tempDirSuffix;
774
0
  Preferences::GetString("security.sandbox.content.tempDirSuffix",
775
0
                         tempDirSuffix);
776
0
  if (tempDirSuffix.IsEmpty()) {
777
0
    nsCOMPtr<nsIUUIDGenerator> uuidgen =
778
0
      do_GetService("@mozilla.org/uuid-generator;1", &rv);
779
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
780
0
      return nullptr;
781
0
    }
782
0
783
0
    nsID uuid;
784
0
    rv = uuidgen->GenerateUUIDInPlace(&uuid);
785
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
786
0
      return nullptr;
787
0
    }
788
0
789
0
    char uuidChars[NSID_LENGTH];
790
0
    uuid.ToProvidedString(uuidChars);
791
0
    tempDirSuffix.AssignASCII(uuidChars, NSID_LENGTH);
792
0
#ifdef XP_UNIX
793
0
    // Braces in a path are somewhat annoying to deal with
794
0
    // and pretty alien on Unix
795
0
    tempDirSuffix.StripChars(u"{}");
796
0
#endif
797
0
798
0
    // Save the pref
799
0
    rv = Preferences::SetString("security.sandbox.content.tempDirSuffix",
800
0
                                tempDirSuffix);
801
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
802
0
      // If we fail to save the pref we don't want to create the temp dir,
803
0
      // because we won't be able to clean it up later.
804
0
      return nullptr;
805
0
    }
806
0
807
0
    nsCOMPtr<nsIPrefService> prefsvc = Preferences::GetService();
808
0
    if (!prefsvc || NS_FAILED((rv = prefsvc->SavePrefFile(nullptr)))) {
809
0
      // Again, if we fail to save the pref file we might not be able to clean
810
0
      // up the temp directory, so don't create one.  Note that in the case
811
0
      // the preference values allows an off main thread save, the successful
812
0
      // return from the call doesn't mean we actually saved the file.  See
813
0
      // bug 1364496 for details.
814
0
      NS_WARNING("Failed to save pref file, cannot create temp dir.");
815
0
      return nullptr;
816
0
    }
817
0
  }
818
0
819
0
  nsCOMPtr<nsIFile> sandboxTempDir = GetContentProcessSandboxTempDir();
820
0
  if (!sandboxTempDir) {
821
0
    NS_WARNING("Failed to determine sandbox temp dir path.");
822
0
    return nullptr;
823
0
  }
824
0
825
0
  // Remove the directory. It may exist due to a previous crash.
826
0
  if (NS_FAILED(DeleteDirIfExists(sandboxTempDir))) {
827
0
    NS_WARNING("Failed to reset sandbox temp dir.");
828
0
    return nullptr;
829
0
  }
830
0
831
0
  // Create the directory
832
0
  rv = sandboxTempDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
833
0
  if (NS_FAILED(rv)) {
834
0
    NS_WARNING("Failed to create sandbox temp dir.");
835
0
    return nullptr;
836
0
  }
837
0
838
0
  return sandboxTempDir.forget();
839
0
}
840
841
static nsresult
842
DeleteDirIfExists(nsIFile* dir)
843
0
{
844
0
  if (dir) {
845
0
    // Don't return an error if the directory doesn't exist.
846
0
    // Windows Remove() returns NS_ERROR_FILE_NOT_FOUND while
847
0
    // OS X returns NS_ERROR_FILE_TARGET_DOES_NOT_EXIST.
848
0
    nsresult rv = dir->Remove(/* aRecursive */ true);
849
0
    if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND &&
850
0
        rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
851
0
      return rv;
852
0
    }
853
0
  }
854
0
  return NS_OK;
855
0
}
856
857
#endif // defined(MOZ_CONTENT_SANDBOX)
858
859
static const char *const kAppendPrefDir[] = { "defaults", "preferences", nullptr };
860
861
#ifdef DEBUG_bsmedberg
862
static void
863
DumpFileArray(const char *key,
864
              nsCOMArray<nsIFile> dirs)
865
{
866
  fprintf(stderr, "nsXREDirProvider::GetFilesInternal(%s)\n", key);
867
868
  nsAutoCString path;
869
  for (int32_t i = 0; i < dirs.Count(); ++i) {
870
    dirs[i]->GetNativePath(path);
871
    fprintf(stderr, "  %s\n", path.get());
872
  }
873
}
874
#endif // DEBUG_bsmedberg
875
876
nsresult
877
nsXREDirProvider::GetFilesInternal(const char* aProperty,
878
                                   nsISimpleEnumerator** aResult)
879
0
{
880
0
  nsresult rv = NS_OK;
881
0
  *aResult = nullptr;
882
0
883
0
  if (!strcmp(aProperty, XRE_EXTENSIONS_DIR_LIST)) {
884
0
    nsCOMArray<nsIFile> directories;
885
0
886
0
    static const char *const kAppendNothing[] = { nullptr };
887
0
888
0
    LoadDirsIntoArray(mAppBundleDirectories,
889
0
                      kAppendNothing, directories);
890
0
891
0
    rv = NS_NewArrayEnumerator(aResult, directories, NS_GET_IID(nsIFile));
892
0
  }
893
0
  else if (!strcmp(aProperty, NS_APP_PREFS_DEFAULTS_DIR_LIST)) {
894
0
    nsCOMArray<nsIFile> directories;
895
0
896
0
    LoadDirIntoArray(mXULAppDir, kAppendPrefDir, directories);
897
0
    LoadDirsIntoArray(mAppBundleDirectories,
898
0
                      kAppendPrefDir, directories);
899
0
900
0
    rv = NS_NewArrayEnumerator(aResult, directories, NS_GET_IID(nsIFile));
901
0
  }
902
0
  else if (!strcmp(aProperty, NS_APP_CHROME_DIR_LIST)) {
903
0
    // NS_APP_CHROME_DIR_LIST is only used to get default (native) icons
904
0
    // for OS window decoration.
905
0
906
0
    static const char *const kAppendChromeDir[] = { "chrome", nullptr };
907
0
    nsCOMArray<nsIFile> directories;
908
0
    LoadDirIntoArray(mXULAppDir,
909
0
                     kAppendChromeDir,
910
0
                     directories);
911
0
    LoadDirsIntoArray(mAppBundleDirectories,
912
0
                      kAppendChromeDir,
913
0
                      directories);
914
0
915
0
    rv = NS_NewArrayEnumerator(aResult, directories, NS_GET_IID(nsIFile));
916
0
  }
917
0
  else if (!strcmp(aProperty, NS_APP_PLUGINS_DIR_LIST)) {
918
0
    nsCOMArray<nsIFile> directories;
919
0
920
0
    if (mozilla::Preferences::GetBool("plugins.load_appdir_plugins", false)) {
921
0
      nsCOMPtr<nsIFile> appdir;
922
0
      rv = XRE_GetBinaryPath(getter_AddRefs(appdir));
923
0
      if (NS_SUCCEEDED(rv)) {
924
0
        appdir->SetNativeLeafName(NS_LITERAL_CSTRING("plugins"));
925
0
        directories.AppendObject(appdir);
926
0
      }
927
0
    }
928
0
929
0
    static const char *const kAppendPlugins[] = { "plugins", nullptr };
930
0
931
0
    // The root dirserviceprovider does quite a bit for us: we're mainly
932
0
    // interested in xulapp and extension-provided plugins.
933
0
    LoadDirsIntoArray(mAppBundleDirectories,
934
0
                      kAppendPlugins,
935
0
                      directories);
936
0
937
0
    if (mProfileDir) {
938
0
      nsCOMArray<nsIFile> profileDir;
939
0
      profileDir.AppendObject(mProfileDir);
940
0
      LoadDirsIntoArray(profileDir,
941
0
                        kAppendPlugins,
942
0
                        directories);
943
0
    }
944
0
945
0
    rv = NS_NewArrayEnumerator(aResult, directories, NS_GET_IID(nsIFile));
946
0
    NS_ENSURE_SUCCESS(rv, rv);
947
0
948
0
    rv = NS_SUCCESS_AGGREGATE_RESULT;
949
0
  }
950
0
  else
951
0
    rv = NS_ERROR_FAILURE;
952
0
953
0
  return rv;
954
0
}
955
956
NS_IMETHODIMP
957
nsXREDirProvider::GetDirectory(nsIFile* *aResult)
958
0
{
959
0
  NS_ENSURE_TRUE(mProfileDir, NS_ERROR_NOT_INITIALIZED);
960
0
961
0
  return mProfileDir->Clone(aResult);
962
0
}
963
964
void
965
nsXREDirProvider::InitializeUserPrefs()
966
0
{
967
0
  if (!mPrefsInitialized) {
968
0
    // Temporarily set mProfileNotified to true so that the preference service
969
0
    // can access the profile directory during initialization. Afterwards, clear
970
0
    // it so that no other code can inadvertently access it until we get to
971
0
    // profile-do-change.
972
0
    AutoRestore<bool> ar(mProfileNotified);
973
0
    mProfileNotified = true;
974
0
975
0
    mozilla::Preferences::InitializeUserPrefs();
976
0
    mPrefsInitialized = true;
977
0
  }
978
0
}
979
980
NS_IMETHODIMP
981
nsXREDirProvider::DoStartup()
982
0
{
983
0
  nsresult rv;
984
0
985
0
  if (!mProfileNotified) {
986
0
    nsCOMPtr<nsIObserverService> obsSvc =
987
0
      mozilla::services::GetObserverService();
988
0
    if (!obsSvc) return NS_ERROR_FAILURE;
989
0
990
0
    mProfileNotified = true;
991
0
992
0
    /*
993
0
       Make sure we've setup prefs before profile-do-change to be able to use
994
0
       them to track crashes and because we want to begin crash tracking before
995
0
       other code run from this notification since they may cause crashes.
996
0
    */
997
0
    MOZ_ASSERT(mPrefsInitialized);
998
0
999
0
    bool safeModeNecessary = false;
1000
0
    nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
1001
0
    if (appStartup) {
1002
0
      rv = appStartup->TrackStartupCrashBegin(&safeModeNecessary);
1003
0
      if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE)
1004
0
        NS_WARNING("Error while beginning startup crash tracking");
1005
0
1006
0
      if (!gSafeMode && safeModeNecessary) {
1007
0
        appStartup->RestartInSafeMode(nsIAppStartup::eForceQuit);
1008
0
        return NS_OK;
1009
0
      }
1010
0
    }
1011
0
1012
0
    static const char16_t kStartup[] = {'s','t','a','r','t','u','p','\0'};
1013
0
    obsSvc->NotifyObservers(nullptr, "profile-do-change", kStartup);
1014
0
1015
0
    // Initialize the Enterprise Policies service in the parent process
1016
0
    // In the content process it's loaded on demand when needed
1017
0
    if (XRE_IsParentProcess()) {
1018
0
      nsCOMPtr<nsIObserver> policies(do_GetService("@mozilla.org/browser/enterprisepolicies;1"));
1019
0
      if (policies) {
1020
0
        policies->Observe(nullptr, "policies-startup", nullptr);
1021
0
      }
1022
0
    }
1023
0
1024
0
    // Init the Extension Manager
1025
0
    nsCOMPtr<nsIObserver> em = do_GetService("@mozilla.org/addons/integration;1");
1026
0
    if (em) {
1027
0
      em->Observe(nullptr, "addons-startup", nullptr);
1028
0
    } else {
1029
0
      NS_WARNING("Failed to create Addons Manager.");
1030
0
    }
1031
0
1032
0
    obsSvc->NotifyObservers(nullptr, "profile-after-change", kStartup);
1033
0
1034
0
    // Any component that has registered for the profile-after-change category
1035
0
    // should also be created at this time.
1036
0
    (void)NS_CreateServicesFromCategory("profile-after-change", nullptr,
1037
0
                                        "profile-after-change");
1038
0
1039
0
    if (gSafeMode && safeModeNecessary) {
1040
0
      static const char16_t kCrashed[] = {'c','r','a','s','h','e','d','\0'};
1041
0
      obsSvc->NotifyObservers(nullptr, "safemode-forced", kCrashed);
1042
0
    }
1043
0
1044
0
    // 1 = Regular mode, 2 = Safe mode, 3 = Safe mode forced
1045
0
    int mode = 1;
1046
0
    if (gSafeMode) {
1047
0
      if (safeModeNecessary)
1048
0
        mode = 3;
1049
0
      else
1050
0
        mode = 2;
1051
0
    }
1052
0
    mozilla::Telemetry::Accumulate(mozilla::Telemetry::SAFE_MODE_USAGE, mode);
1053
0
1054
0
    // Telemetry about number of profiles.
1055
0
    nsCOMPtr<nsIToolkitProfileService> profileService =
1056
0
      do_GetService("@mozilla.org/toolkit/profile-service;1");
1057
0
    if (profileService) {
1058
0
      uint32_t count = 0;
1059
0
      rv = profileService->GetProfileCount(&count);
1060
0
      if (NS_WARN_IF(NS_FAILED(rv))) {
1061
0
        return rv;
1062
0
      }
1063
0
1064
0
      mozilla::Telemetry::Accumulate(mozilla::Telemetry::NUMBER_OF_PROFILES,
1065
0
                                     count);
1066
0
    }
1067
0
1068
0
    obsSvc->NotifyObservers(nullptr, "profile-initial-state", nullptr);
1069
0
1070
0
#if defined(MOZ_CONTENT_SANDBOX)
1071
0
    // Makes sure the content temp dir has been loaded if it hasn't been
1072
0
    // already. In the parent this ensures it has been created before we attempt
1073
0
    // to start any content processes.
1074
0
    if (!mContentTempDir) {
1075
0
      mozilla::Unused << NS_WARN_IF(NS_FAILED(LoadContentProcessTempDir()));
1076
0
    }
1077
0
#endif
1078
0
  }
1079
0
  return NS_OK;
1080
0
}
1081
1082
void
1083
nsXREDirProvider::DoShutdown()
1084
0
{
1085
0
  AUTO_PROFILER_LABEL("nsXREDirProvider::DoShutdown", OTHER);
1086
0
1087
0
  if (mProfileNotified) {
1088
0
    nsCOMPtr<nsIObserverService> obsSvc =
1089
0
      mozilla::services::GetObserverService();
1090
0
    NS_ASSERTION(obsSvc, "No observer service?");
1091
0
    if (obsSvc) {
1092
0
      static const char16_t kShutdownPersist[] = u"shutdown-persist";
1093
0
      obsSvc->NotifyObservers(nullptr, "profile-change-net-teardown", kShutdownPersist);
1094
0
      obsSvc->NotifyObservers(nullptr, "profile-change-teardown", kShutdownPersist);
1095
0
1096
#ifdef DEBUG
1097
      // Not having this causes large intermittent leaks. See bug 1340425.
1098
      if (JSContext* cx = dom::danger::GetJSContext()) {
1099
        JS_GC(cx);
1100
      }
1101
#endif
1102
1103
0
      obsSvc->NotifyObservers(nullptr, "profile-before-change", kShutdownPersist);
1104
0
      obsSvc->NotifyObservers(nullptr, "profile-before-change-qm", kShutdownPersist);
1105
0
      obsSvc->NotifyObservers(nullptr, "profile-before-change-telemetry", kShutdownPersist);
1106
0
    }
1107
0
    mProfileNotified = false;
1108
0
  }
1109
0
1110
0
#if defined(MOZ_CONTENT_SANDBOX)
1111
0
  if (XRE_IsParentProcess()) {
1112
0
    Unused << DeleteDirIfExists(mContentProcessSandboxTempDir);
1113
0
  }
1114
0
#endif
1115
0
}
1116
1117
#ifdef XP_WIN
1118
static nsresult
1119
GetShellFolderPath(KNOWNFOLDERID folder, nsAString& _retval)
1120
{
1121
  DWORD flags = KF_FLAG_SIMPLE_IDLIST | KF_FLAG_DONT_VERIFY | KF_FLAG_NO_ALIAS;
1122
  PWSTR path = nullptr;
1123
1124
  if (!SUCCEEDED(SHGetKnownFolderPath(folder, flags, NULL, &path))) {
1125
    return NS_ERROR_NOT_AVAILABLE;
1126
  }
1127
1128
  _retval = nsDependentString(path);
1129
  CoTaskMemFree(path);
1130
  return NS_OK;
1131
}
1132
1133
/**
1134
 * Provides a fallback for getting the path to APPDATA or LOCALAPPDATA by
1135
 * querying the registry when the call to SHGetSpecialFolderLocation or
1136
 * SHGetPathFromIDListW is unable to provide these paths (Bug 513958).
1137
 */
1138
static nsresult
1139
GetRegWindowsAppDataFolder(bool aLocal, nsAString& _retval)
1140
{
1141
  HKEY key;
1142
  LPCWSTR keyName =
1143
    L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
1144
  DWORD res = ::RegOpenKeyExW(HKEY_CURRENT_USER, keyName, 0, KEY_READ,
1145
                              &key);
1146
  if (res != ERROR_SUCCESS) {
1147
    _retval.SetLength(0);
1148
    return NS_ERROR_NOT_AVAILABLE;
1149
  }
1150
1151
  DWORD type, size;
1152
  res = RegQueryValueExW(key, (aLocal ? L"Local AppData" : L"AppData"),
1153
                         nullptr, &type, nullptr, &size);
1154
  // The call to RegQueryValueExW must succeed, the type must be REG_SZ, the
1155
  // buffer size must not equal 0, and the buffer size be a multiple of 2.
1156
  if (res != ERROR_SUCCESS || type != REG_SZ || size == 0 || size % 2 != 0) {
1157
    ::RegCloseKey(key);
1158
    _retval.SetLength(0);
1159
    return NS_ERROR_NOT_AVAILABLE;
1160
  }
1161
1162
  // |size| may or may not include room for the terminating null character
1163
  DWORD resultLen = size / 2;
1164
1165
  if (!_retval.SetLength(resultLen, mozilla::fallible)) {
1166
    ::RegCloseKey(key);
1167
    _retval.SetLength(0);
1168
    return NS_ERROR_NOT_AVAILABLE;
1169
  }
1170
1171
  auto begin = _retval.BeginWriting();
1172
1173
  res = RegQueryValueExW(key, (aLocal ? L"Local AppData" : L"AppData"),
1174
                         nullptr, nullptr, (LPBYTE) begin, &size);
1175
  ::RegCloseKey(key);
1176
  if (res != ERROR_SUCCESS) {
1177
    _retval.SetLength(0);
1178
    return NS_ERROR_NOT_AVAILABLE;
1179
  }
1180
1181
  if (!_retval.CharAt(resultLen - 1)) {
1182
    // It was already null terminated.
1183
    _retval.Truncate(resultLen - 1);
1184
  }
1185
1186
  return NS_OK;
1187
}
1188
1189
static bool
1190
GetCachedHash(HKEY rootKey, const nsAString &regPath, const nsAString &path,
1191
              nsAString &cachedHash)
1192
{
1193
  HKEY baseKey;
1194
  if (RegOpenKeyExW(rootKey, reinterpret_cast<const wchar_t*>(regPath.BeginReading()), 0, KEY_READ, &baseKey) !=
1195
      ERROR_SUCCESS) {
1196
    return false;
1197
  }
1198
1199
  wchar_t cachedHashRaw[512];
1200
  DWORD bufferSize = sizeof(cachedHashRaw);
1201
  LONG result = RegQueryValueExW(baseKey, reinterpret_cast<const wchar_t*>(path.BeginReading()), 0, nullptr,
1202
                                 (LPBYTE)cachedHashRaw, &bufferSize);
1203
  RegCloseKey(baseKey);
1204
  if (result == ERROR_SUCCESS) {
1205
    cachedHash.Assign(cachedHashRaw);
1206
  }
1207
  return ERROR_SUCCESS == result;
1208
}
1209
1210
#endif
1211
1212
// Temporary for nsIXREDirProvider until compatibility mode goes away.
1213
nsresult
1214
nsXREDirProvider::GetInstallHash(nsAString & aPathHash)
1215
0
{
1216
0
  return GetInstallHash(aPathHash, false);
1217
0
}
1218
1219
// Compatibility Mode (aUseCompatibilityMode) outputs hashes that are what this
1220
// function has historically returned. The new default is to output hashes that
1221
// are consistent with those generated by the installer.
1222
nsresult
1223
nsXREDirProvider::GetInstallHash(nsAString & aPathHash, bool aUseCompatibilityMode)
1224
0
{
1225
0
  nsCOMPtr<nsIFile> updRoot;
1226
0
  nsCOMPtr<nsIFile> appFile;
1227
0
  bool per = false;
1228
0
  nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(appFile));
1229
0
  NS_ENSURE_SUCCESS(rv, rv);
1230
0
  rv = appFile->GetParent(getter_AddRefs(updRoot));
1231
0
  NS_ENSURE_SUCCESS(rv, rv);
1232
0
1233
0
  nsAutoString appDirPath;
1234
0
  rv = updRoot->GetPath(appDirPath);
1235
0
  NS_ENSURE_SUCCESS(rv, rv);
1236
0
1237
0
  aPathHash.Truncate();
1238
0
1239
#ifdef XP_WIN
1240
  // Figure out where we should check for a cached hash value. If the
1241
  // application doesn't have the nsXREAppData vendor value defined check
1242
  // under SOFTWARE\Mozilla.
1243
  bool hasVendor = GetAppVendor() && strlen(GetAppVendor()) != 0;
1244
  wchar_t regPath[1024] = { L'\0' };
1245
  swprintf_s(regPath, mozilla::ArrayLength(regPath), L"SOFTWARE\\%S\\%S\\TaskBarIDs",
1246
              (hasVendor ? GetAppVendor() : "Mozilla"), MOZ_APP_BASENAME);
1247
1248
  // If we pre-computed the hash, grab it from the registry.
1249
  if (GetCachedHash(HKEY_LOCAL_MACHINE, nsDependentString(regPath), appDirPath,
1250
                    aPathHash)) {
1251
    return NS_OK;
1252
  }
1253
1254
  if (GetCachedHash(HKEY_CURRENT_USER, nsDependentString(regPath), appDirPath,
1255
                    aPathHash)) {
1256
    return NS_OK;
1257
  }
1258
#endif
1259
1260
0
  // This should only happen when the installer isn't used (e.g. zip builds).
1261
0
  void* buffer = appDirPath.BeginWriting();
1262
0
  uint32_t length = appDirPath.Length() * sizeof(nsAutoString::char_type);
1263
0
  uint64_t hash = CityHash64(static_cast<const char*>(buffer), length);
1264
0
  if (aUseCompatibilityMode) {
1265
0
    aPathHash.AppendInt((int)(hash >> 32), 16);
1266
0
    aPathHash.AppendInt((int)hash, 16);
1267
0
    // The installer implementation writes the registry values that were checked
1268
0
    // in the previous block for this value in uppercase and since it is an
1269
0
    // option to have a case sensitive file system on Windows this value must
1270
0
    // also be in uppercase.
1271
0
    ToUpperCase(aPathHash);
1272
0
  } else {
1273
0
    aPathHash.AppendPrintf("%" PRIX64, hash);
1274
0
  }
1275
0
1276
0
  return NS_OK;
1277
0
}
1278
1279
nsresult
1280
nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
1281
0
{
1282
0
  nsCOMPtr<nsIFile> updRoot;
1283
0
  nsCOMPtr<nsIFile> appFile;
1284
0
  bool per = false;
1285
0
  nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(appFile));
1286
0
  NS_ENSURE_SUCCESS(rv, rv);
1287
0
  rv = appFile->GetParent(getter_AddRefs(updRoot));
1288
0
  NS_ENSURE_SUCCESS(rv, rv);
1289
0
1290
#ifdef XP_MACOSX
1291
  nsCOMPtr<nsIFile> appRootDirFile;
1292
  nsCOMPtr<nsIFile> localDir;
1293
  nsAutoString appDirPath;
1294
  if (NS_FAILED(appFile->GetParent(getter_AddRefs(appRootDirFile))) ||
1295
      NS_FAILED(appRootDirFile->GetPath(appDirPath)) ||
1296
      NS_FAILED(GetUserDataDirectoryHome(getter_AddRefs(localDir), true))) {
1297
    return NS_ERROR_FAILURE;
1298
  }
1299
1300
  int32_t dotIndex = appDirPath.RFind(".app");
1301
  if (dotIndex == kNotFound) {
1302
    dotIndex = appDirPath.Length();
1303
  }
1304
  appDirPath = Substring(appDirPath, 1, dotIndex - 1);
1305
1306
  bool hasVendor = GetAppVendor() && strlen(GetAppVendor()) != 0;
1307
  if (hasVendor || GetAppName()) {
1308
    if (NS_FAILED(localDir->AppendNative(nsDependentCString(hasVendor ?
1309
                                         GetAppVendor() :
1310
                                         GetAppName())))) {
1311
      return NS_ERROR_FAILURE;
1312
    }
1313
  } else if (NS_FAILED(localDir->AppendNative(NS_LITERAL_CSTRING("Mozilla")))) {
1314
    return NS_ERROR_FAILURE;
1315
  }
1316
1317
  if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("updates"))) ||
1318
      NS_FAILED(localDir->AppendRelativePath(appDirPath))) {
1319
    return NS_ERROR_FAILURE;
1320
  }
1321
1322
  localDir.forget(aResult);
1323
  return NS_OK;
1324
1325
#elif XP_WIN
1326
  nsAutoString pathHash;
1327
  rv = GetInstallHash(pathHash, true);
1328
  NS_ENSURE_SUCCESS(rv, rv);
1329
1330
  // As a last ditch effort, get the local app data directory and if a vendor
1331
  // name exists append it. If only a product name exists, append it. If neither
1332
  // exist fallback to old handling. We don't use the product name on purpose
1333
  // because we want a shared update directory for different apps run from the
1334
  // same path.
1335
  nsCOMPtr<nsIFile> localDir;
1336
  bool hasVendor = GetAppVendor() && strlen(GetAppVendor()) != 0;
1337
  if ((hasVendor || GetAppName()) &&
1338
      NS_SUCCEEDED(GetUserDataDirectoryHome(getter_AddRefs(localDir), true)) &&
1339
      NS_SUCCEEDED(localDir->AppendNative(nsDependentCString(hasVendor ?
1340
                                          GetAppVendor() : GetAppName()))) &&
1341
      NS_SUCCEEDED(localDir->Append(NS_LITERAL_STRING("updates"))) &&
1342
      NS_SUCCEEDED(localDir->Append(pathHash))) {
1343
    localDir.forget(aResult);
1344
    return NS_OK;
1345
  }
1346
1347
  nsAutoString appPath;
1348
  rv = updRoot->GetPath(appPath);
1349
  NS_ENSURE_SUCCESS(rv, rv);
1350
1351
  // AppDir may be a short path. Convert to long path to make sure
1352
  // the consistency of the update folder location
1353
  nsString longPath;
1354
  wchar_t* buf;
1355
1356
  uint32_t bufLength = longPath.GetMutableData(&buf, MAXPATHLEN);
1357
  NS_ENSURE_TRUE(bufLength >= MAXPATHLEN, NS_ERROR_OUT_OF_MEMORY);
1358
1359
  DWORD len = GetLongPathNameW(appPath.get(), buf, bufLength);
1360
1361
  // Failing GetLongPathName() is not fatal.
1362
  if (len <= 0 || len >= bufLength)
1363
    longPath.Assign(appPath);
1364
  else
1365
    longPath.SetLength(len);
1366
1367
  // Use <UserLocalDataDir>\updates\<relative path to app dir from
1368
  // Program Files> if app dir is under Program Files to avoid the
1369
  // folder virtualization mess on Windows Vista
1370
  nsAutoString programFiles;
1371
  rv = GetShellFolderPath(FOLDERID_ProgramFiles, programFiles);
1372
  NS_ENSURE_SUCCESS(rv, rv);
1373
1374
  programFiles.Append('\\');
1375
  uint32_t programFilesLen = programFiles.Length();
1376
1377
  nsAutoString programName;
1378
  if (_wcsnicmp(programFiles.get(), longPath.get(), programFilesLen) == 0) {
1379
    programName = Substring(longPath, programFilesLen);
1380
  } else {
1381
    // We need the update root directory to live outside of the installation
1382
    // directory, because otherwise the updater writing the log file can cause
1383
    // the directory to be locked, which prevents it from being replaced after
1384
    // background updates.
1385
    programName.AssignASCII(MOZ_APP_NAME);
1386
  }
1387
1388
  rv = GetUserLocalDataDirectory(getter_AddRefs(updRoot));
1389
  NS_ENSURE_SUCCESS(rv, rv);
1390
1391
  rv = updRoot->AppendRelativePath(programName);
1392
  NS_ENSURE_SUCCESS(rv, rv);
1393
1394
#endif // XP_WIN
1395
0
  updRoot.forget(aResult);
1396
0
  return NS_OK;
1397
0
}
1398
1399
nsresult
1400
nsXREDirProvider::GetProfileStartupDir(nsIFile* *aResult)
1401
0
{
1402
0
  if (mProfileDir)
1403
0
    return mProfileDir->Clone(aResult);
1404
0
1405
0
  if (mAppProvider) {
1406
0
    nsCOMPtr<nsIFile> needsclone;
1407
0
    bool dummy;
1408
0
    nsresult rv = mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP,
1409
0
                                        &dummy,
1410
0
                                        getter_AddRefs(needsclone));
1411
0
    if (NS_SUCCEEDED(rv))
1412
0
      return needsclone->Clone(aResult);
1413
0
  }
1414
0
1415
0
  return NS_ERROR_FAILURE;
1416
0
}
1417
1418
nsresult
1419
nsXREDirProvider::GetProfileDir(nsIFile* *aResult)
1420
0
{
1421
0
  if (mProfileDir) {
1422
0
    if (!mProfileNotified)
1423
0
      return NS_ERROR_FAILURE;
1424
0
1425
0
    return mProfileDir->Clone(aResult);
1426
0
  }
1427
0
1428
0
  if (mAppProvider) {
1429
0
    nsCOMPtr<nsIFile> needsclone;
1430
0
    bool dummy;
1431
0
    nsresult rv = mAppProvider->GetFile(NS_APP_USER_PROFILE_50_DIR,
1432
0
                                        &dummy,
1433
0
                                        getter_AddRefs(needsclone));
1434
0
    if (NS_SUCCEEDED(rv))
1435
0
      return needsclone->Clone(aResult);
1436
0
  }
1437
0
1438
0
  return NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aResult);
1439
0
}
1440
1441
NS_IMETHODIMP
1442
nsXREDirProvider::SetUserDataDirectory(nsIFile *aFile, bool aLocal)
1443
0
{
1444
0
  if (aLocal) {
1445
0
    NS_IF_RELEASE(gDataDirHomeLocal);
1446
0
    NS_IF_ADDREF(gDataDirHomeLocal = aFile);
1447
0
  } else {
1448
0
    NS_IF_RELEASE(gDataDirHome);
1449
0
    NS_IF_ADDREF(gDataDirHome = aFile);
1450
0
  }
1451
0
1452
0
  return NS_OK;
1453
0
}
1454
1455
nsresult
1456
nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal)
1457
0
{
1458
0
  // Copied from nsAppFileLocationProvider (more or less)
1459
0
  nsresult rv;
1460
0
  nsCOMPtr<nsIFile> localDir;
1461
0
1462
0
  if (aLocal && gDataDirHomeLocal) {
1463
0
    return gDataDirHomeLocal->Clone(aFile);
1464
0
  }
1465
0
  if (!aLocal && gDataDirHome) {
1466
0
    return gDataDirHome->Clone(aFile);
1467
0
  }
1468
0
1469
#if defined(XP_MACOSX)
1470
  FSRef fsRef;
1471
  OSType folderType;
1472
  if (aLocal) {
1473
    folderType = kCachedDataFolderType;
1474
  } else {
1475
#ifdef MOZ_THUNDERBIRD
1476
    folderType = kDomainLibraryFolderType;
1477
#else
1478
    folderType = kApplicationSupportFolderType;
1479
#endif
1480
  }
1481
  OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
1482
  NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
1483
1484
  rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localDir));
1485
  NS_ENSURE_SUCCESS(rv, rv);
1486
1487
  nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir);
1488
  NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED);
1489
1490
  rv = dirFileMac->InitWithFSRef(&fsRef);
1491
  NS_ENSURE_SUCCESS(rv, rv);
1492
1493
  localDir = do_QueryInterface(dirFileMac, &rv);
1494
#elif defined(XP_IOS)
1495
  nsAutoCString userDir;
1496
  if (GetUIKitDirectory(aLocal, userDir)) {
1497
    rv = NS_NewNativeLocalFile(userDir, true, getter_AddRefs(localDir));
1498
  } else {
1499
    rv = NS_ERROR_FAILURE;
1500
  }
1501
  NS_ENSURE_SUCCESS(rv, rv);
1502
#elif defined(XP_WIN)
1503
  nsString path;
1504
  if (aLocal) {
1505
    rv = GetShellFolderPath(FOLDERID_LocalAppData, path);
1506
    if (NS_FAILED(rv))
1507
      rv = GetRegWindowsAppDataFolder(aLocal, path);
1508
  }
1509
  if (!aLocal || NS_FAILED(rv)) {
1510
    rv = GetShellFolderPath(FOLDERID_RoamingAppData, path);
1511
    if (NS_FAILED(rv)) {
1512
      if (!aLocal)
1513
        rv = GetRegWindowsAppDataFolder(aLocal, path);
1514
    }
1515
  }
1516
  NS_ENSURE_SUCCESS(rv, rv);
1517
1518
  rv = NS_NewLocalFile(path, true, getter_AddRefs(localDir));
1519
#elif defined(XP_UNIX)
1520
0
  const char* homeDir = getenv("HOME");
1521
0
  if (!homeDir || !*homeDir)
1522
0
    return NS_ERROR_FAILURE;
1523
0
1524
#ifdef ANDROID /* We want (ProfD == ProfLD) on Android. */
1525
  aLocal = false;
1526
#endif
1527
1528
0
  if (aLocal) {
1529
0
    // If $XDG_CACHE_HOME is defined use it, otherwise use $HOME/.cache.
1530
0
    const char* cacheHome = getenv("XDG_CACHE_HOME");
1531
0
    if (cacheHome && *cacheHome) {
1532
0
      rv = NS_NewNativeLocalFile(nsDependentCString(cacheHome), true,
1533
0
                                 getter_AddRefs(localDir));
1534
0
    } else {
1535
0
      rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
1536
0
                                 getter_AddRefs(localDir));
1537
0
      if (NS_SUCCEEDED(rv))
1538
0
        rv = localDir->AppendNative(NS_LITERAL_CSTRING(".cache"));
1539
0
    }
1540
0
  } else {
1541
0
    rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
1542
0
                               getter_AddRefs(localDir));
1543
0
  }
1544
#else
1545
#error "Don't know how to get product dir on your platform"
1546
#endif
1547
1548
0
  NS_IF_ADDREF(*aFile = localDir);
1549
0
  return rv;
1550
0
}
1551
1552
nsresult
1553
nsXREDirProvider::GetSysUserExtensionsDirectory(nsIFile** aFile)
1554
0
{
1555
0
  nsCOMPtr<nsIFile> localDir;
1556
0
  nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), false);
1557
0
  NS_ENSURE_SUCCESS(rv, rv);
1558
0
1559
0
  rv = AppendSysUserExtensionPath(localDir);
1560
0
  NS_ENSURE_SUCCESS(rv, rv);
1561
0
1562
0
  rv = EnsureDirectoryExists(localDir);
1563
0
  NS_ENSURE_SUCCESS(rv, rv);
1564
0
1565
0
  localDir.forget(aFile);
1566
0
  return NS_OK;
1567
0
}
1568
1569
nsresult
1570
nsXREDirProvider::GetSysUserExtensionsDevDirectory(nsIFile** aFile)
1571
0
{
1572
0
  nsCOMPtr<nsIFile> localDir;
1573
0
  nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), false);
1574
0
  NS_ENSURE_SUCCESS(rv, rv);
1575
0
1576
0
  rv = AppendSysUserExtensionsDevPath(localDir);
1577
0
  NS_ENSURE_SUCCESS(rv, rv);
1578
0
1579
0
  rv = EnsureDirectoryExists(localDir);
1580
0
  NS_ENSURE_SUCCESS(rv, rv);
1581
0
1582
0
  localDir.forget(aFile);
1583
0
  return NS_OK;
1584
0
}
1585
1586
#if defined(XP_UNIX) || defined(XP_MACOSX)
1587
nsresult
1588
nsXREDirProvider::GetSystemExtensionsDirectory(nsIFile** aFile)
1589
0
{
1590
0
  nsresult rv;
1591
0
  nsCOMPtr<nsIFile> localDir;
1592
0
1593
0
  rv = GetSystemParentDirectory(getter_AddRefs(localDir));
1594
0
  if (NS_SUCCEEDED(rv)) {
1595
0
    NS_NAMED_LITERAL_CSTRING(sExtensions,
1596
#if defined(XP_MACOSX)
1597
                             "Extensions"
1598
#else
1599
                             "extensions"
1600
0
#endif
1601
0
                             );
1602
0
1603
0
    rv = localDir->AppendNative(sExtensions);
1604
0
    if (NS_SUCCEEDED(rv)) {
1605
0
      localDir.forget(aFile);
1606
0
    }
1607
0
  }
1608
0
  return rv;
1609
0
}
1610
#endif
1611
1612
nsresult
1613
nsXREDirProvider::GetUserDataDirectory(nsIFile** aFile, bool aLocal)
1614
0
{
1615
0
  nsCOMPtr<nsIFile> localDir;
1616
0
  nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), aLocal);
1617
0
  NS_ENSURE_SUCCESS(rv, rv);
1618
0
1619
0
  rv = AppendProfilePath(localDir, aLocal);
1620
0
  NS_ENSURE_SUCCESS(rv, rv);
1621
0
1622
#ifdef DEBUG_jungshik
1623
  nsAutoCString cwd;
1624
  localDir->GetNativePath(cwd);
1625
  printf("nsXREDirProvider::GetUserDataDirectory: %s\n", cwd.get());
1626
#endif
1627
0
  rv = EnsureDirectoryExists(localDir);
1628
0
  NS_ENSURE_SUCCESS(rv, rv);
1629
0
1630
0
  localDir.forget(aFile);
1631
0
  return NS_OK;
1632
0
}
1633
1634
nsresult
1635
nsXREDirProvider::EnsureDirectoryExists(nsIFile* aDirectory)
1636
0
{
1637
0
  bool exists;
1638
0
  nsresult rv = aDirectory->Exists(&exists);
1639
0
  NS_ENSURE_SUCCESS(rv, rv);
1640
#ifdef DEBUG_jungshik
1641
  if (!exists) {
1642
    nsAutoCString cwd;
1643
    aDirectory->GetNativePath(cwd);
1644
    printf("nsXREDirProvider::EnsureDirectoryExists: %s does not\n", cwd.get());
1645
  }
1646
#endif
1647
0
  if (!exists)
1648
0
    rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0700);
1649
#ifdef DEBUG_jungshik
1650
  if (NS_FAILED(rv))
1651
    NS_WARNING("nsXREDirProvider::EnsureDirectoryExists: create failed");
1652
#endif
1653
1654
0
  return rv;
1655
0
}
1656
1657
nsresult
1658
nsXREDirProvider::AppendSysUserExtensionPath(nsIFile* aFile)
1659
0
{
1660
0
  NS_ASSERTION(aFile, "Null pointer!");
1661
0
1662
0
  nsresult rv;
1663
0
1664
#if defined (XP_MACOSX) || defined(XP_WIN)
1665
1666
  static const char* const sXR = "Mozilla";
1667
  rv = aFile->AppendNative(nsDependentCString(sXR));
1668
  NS_ENSURE_SUCCESS(rv, rv);
1669
1670
  static const char* const sExtensions = "Extensions";
1671
  rv = aFile->AppendNative(nsDependentCString(sExtensions));
1672
  NS_ENSURE_SUCCESS(rv, rv);
1673
1674
#elif defined(XP_UNIX)
1675
1676
0
  static const char* const sXR = ".mozilla";
1677
0
  rv = aFile->AppendNative(nsDependentCString(sXR));
1678
0
  NS_ENSURE_SUCCESS(rv, rv);
1679
0
1680
0
  static const char* const sExtensions = "extensions";
1681
0
  rv = aFile->AppendNative(nsDependentCString(sExtensions));
1682
0
  NS_ENSURE_SUCCESS(rv, rv);
1683
0
1684
#else
1685
#error "Don't know how to get XRE user extension path on your platform"
1686
#endif
1687
0
  return NS_OK;
1688
0
}
1689
1690
nsresult
1691
nsXREDirProvider::AppendSysUserExtensionsDevPath(nsIFile* aFile)
1692
0
{
1693
0
  MOZ_ASSERT(aFile);
1694
0
1695
0
  nsresult rv;
1696
0
1697
#if defined (XP_MACOSX) || defined(XP_WIN)
1698
1699
  static const char* const sXR = "Mozilla";
1700
  rv = aFile->AppendNative(nsDependentCString(sXR));
1701
  NS_ENSURE_SUCCESS(rv, rv);
1702
1703
  static const char* const sExtensions = "SystemExtensionsDev";
1704
  rv = aFile->AppendNative(nsDependentCString(sExtensions));
1705
  NS_ENSURE_SUCCESS(rv, rv);
1706
1707
#elif defined(XP_UNIX)
1708
1709
0
  static const char* const sXR = ".mozilla";
1710
0
  rv = aFile->AppendNative(nsDependentCString(sXR));
1711
0
  NS_ENSURE_SUCCESS(rv, rv);
1712
0
1713
0
  static const char* const sExtensions = "systemextensionsdev";
1714
0
  rv = aFile->AppendNative(nsDependentCString(sExtensions));
1715
0
  NS_ENSURE_SUCCESS(rv, rv);
1716
0
1717
#else
1718
#error "Don't know how to get XRE system extension dev path on your platform"
1719
#endif
1720
0
  return NS_OK;
1721
0
}
1722
1723
1724
nsresult
1725
nsXREDirProvider::AppendProfilePath(nsIFile* aFile, bool aLocal)
1726
0
{
1727
0
  NS_ASSERTION(aFile, "Null pointer!");
1728
0
1729
0
  nsAutoCString profile;
1730
0
  nsAutoCString appName;
1731
0
  nsAutoCString vendor;
1732
0
  if (GetAppProfile()) {
1733
0
    profile = GetAppProfile();
1734
0
  } else {
1735
0
    appName = GetAppName();
1736
0
    vendor = GetAppVendor();
1737
0
  }
1738
0
1739
0
  nsresult rv;
1740
0
1741
#if defined (XP_MACOSX)
1742
  if (!profile.IsEmpty()) {
1743
    rv = AppendProfileString(aFile, profile.get());
1744
  }
1745
  else {
1746
    // Note that MacOS ignores the vendor when creating the profile hierarchy -
1747
    // all application preferences directories live alongside one another in
1748
    // ~/Library/Application Support/
1749
    rv = aFile->AppendNative(appName);
1750
  }
1751
  NS_ENSURE_SUCCESS(rv, rv);
1752
1753
#elif defined(XP_WIN)
1754
  if (!profile.IsEmpty()) {
1755
    rv = AppendProfileString(aFile, profile.get());
1756
  }
1757
  else {
1758
    if (!vendor.IsEmpty()) {
1759
      rv = aFile->AppendNative(vendor);
1760
      NS_ENSURE_SUCCESS(rv, rv);
1761
    }
1762
    rv = aFile->AppendNative(appName);
1763
  }
1764
  NS_ENSURE_SUCCESS(rv, rv);
1765
1766
#elif defined(ANDROID)
1767
  // The directory used for storing profiles
1768
  // The parent of this directory is set in GetUserDataDirectoryHome
1769
  // XXX: handle gAppData->profile properly
1770
  // XXXsmaug ...and the rest of the profile creation!
1771
  rv = aFile->AppendNative(nsDependentCString("mozilla"));
1772
  NS_ENSURE_SUCCESS(rv, rv);
1773
#elif defined(XP_UNIX)
1774
  nsAutoCString folder;
1775
0
  // Make it hidden (by starting with "."), except when local (the
1776
0
  // profile is already under ~/.cache or XDG_CACHE_HOME).
1777
0
  if (!aLocal)
1778
0
    folder.Assign('.');
1779
0
1780
0
  if (!profile.IsEmpty()) {
1781
0
    // Skip any leading path characters
1782
0
    const char* profileStart = profile.get();
1783
0
    while (*profileStart == '/' || *profileStart == '\\')
1784
0
      profileStart++;
1785
0
1786
0
    // On the off chance that someone wanted their folder to be hidden don't
1787
0
    // let it become ".."
1788
0
    if (*profileStart == '.' && !aLocal)
1789
0
      profileStart++;
1790
0
1791
0
    folder.Append(profileStart);
1792
0
    ToLowerCase(folder);
1793
0
1794
0
    rv = AppendProfileString(aFile, folder.BeginReading());
1795
0
  }
1796
0
  else {
1797
0
    if (!vendor.IsEmpty()) {
1798
0
      folder.Append(vendor);
1799
0
      ToLowerCase(folder);
1800
0
1801
0
      rv = aFile->AppendNative(folder);
1802
0
      NS_ENSURE_SUCCESS(rv, rv);
1803
0
1804
0
      folder.Truncate();
1805
0
    }
1806
0
1807
0
    folder.Append(appName);
1808
0
    ToLowerCase(folder);
1809
0
1810
0
    rv = aFile->AppendNative(folder);
1811
0
  }
1812
0
  NS_ENSURE_SUCCESS(rv, rv);
1813
0
1814
#else
1815
#error "Don't know how to get profile path on your platform"
1816
#endif
1817
0
  return NS_OK;
1818
0
}
1819
1820
nsresult
1821
nsXREDirProvider::AppendProfileString(nsIFile* aFile, const char* aPath)
1822
0
{
1823
0
  NS_ASSERTION(aFile, "Null file!");
1824
0
  NS_ASSERTION(aPath, "Null path!");
1825
0
1826
0
  nsAutoCString pathDup(aPath);
1827
0
1828
0
  char* path = pathDup.BeginWriting();
1829
0
1830
0
  nsresult rv;
1831
0
  char* subdir;
1832
0
  while ((subdir = NS_strtok("/\\", &path))) {
1833
0
    rv = aFile->AppendNative(nsDependentCString(subdir));
1834
0
    NS_ENSURE_SUCCESS(rv, rv);
1835
0
  }
1836
0
1837
0
  return NS_OK;
1838
0
}