/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 ®Path, 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 | } |