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