1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/common/chrome_paths.h"
7 #include "base/file_util.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/mac/bundle_locations.h"
11 #include "base/path_service.h"
12 #include "base/strings/string_util.h"
13 #include "base/sys_info.h"
14 #include "base/threading/thread_restrictions.h"
15 #include "base/version.h"
16 #include "chrome/common/chrome_constants.h"
17 #include "chrome/common/chrome_paths_internal.h"
18 #include "chrome/common/widevine_cdm_constants.h"
19 #include "ui/base/ui_base_paths.h"
21 #if defined(OS_ANDROID)
22 #include "base/android/path_utils.h"
25 #if defined(OS_MACOSX)
26 #include "base/mac/foundation_util.h"
29 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
33 // File name of the internal Flash plugin on different platforms.
34 const base::FilePath::CharType kInternalFlashPluginFileName
[] =
35 #if defined(OS_MACOSX)
36 FILE_PATH_LITERAL("Flash Player Plugin for Chrome.plugin");
38 FILE_PATH_LITERAL("gcswf32.dll");
39 #else // OS_LINUX, etc.
40 FILE_PATH_LITERAL("libgcflashplayer.so");
43 // The Pepper Flash plugins are in a directory with this name.
44 const base::FilePath::CharType kPepperFlashBaseDirectory
[] =
45 FILE_PATH_LITERAL("PepperFlash");
48 const base::FilePath::CharType kPepperFlashDebuggerBaseDirectory
[] =
49 FILE_PATH_LITERAL("Macromed\\Flash");
52 // File name of the internal PDF plugin on different platforms.
53 const base::FilePath::CharType kInternalPDFPluginFileName
[] =
55 FILE_PATH_LITERAL("pdf.dll");
56 #elif defined(OS_MACOSX)
57 FILE_PATH_LITERAL("PDF.plugin");
58 #else // Linux and Chrome OS
59 FILE_PATH_LITERAL("libpdf.so");
62 // File name of the internal NaCl plugin on different platforms.
63 const base::FilePath::CharType kInternalNaClPluginFileName
[] =
65 FILE_PATH_LITERAL("ppGoogleNaClPluginChrome.dll");
66 #elif defined(OS_MACOSX)
67 // TODO(noelallen) Please verify this extention name is correct.
68 FILE_PATH_LITERAL("ppGoogleNaClPluginChrome.plugin");
69 #else // Linux and Chrome OS
70 FILE_PATH_LITERAL("libppGoogleNaClPluginChrome.so");
73 const base::FilePath::CharType kEffectsPluginFileName
[] =
75 FILE_PATH_LITERAL("pepper/libppeffects.dll");
76 #elif defined(OS_MACOSX)
77 FILE_PATH_LITERAL("pepper/libppeffects.plugin");
78 #else // Linux and Chrome OS
79 FILE_PATH_LITERAL("pepper/libppeffects.so");
82 #if defined(OS_POSIX) && !defined(OS_MACOSX)
84 const base::FilePath::CharType kO1DPluginFileName
[] =
85 FILE_PATH_LITERAL("pepper/libppo1d.so");
87 const base::FilePath::CharType kGTalkPluginFileName
[] =
88 FILE_PATH_LITERAL("pepper/libppgoogletalk.so");
90 #endif // defined(OS_POSIX) && !defined(OS_MACOSX)
93 // The path to the external extension <id>.json files.
94 // /usr/share seems like a good choice, see: http://www.pathname.com/fhs/
95 const base::FilePath::CharType kFilepathSinglePrefExtensions
[] =
96 #if defined(GOOGLE_CHROME_BUILD)
97 FILE_PATH_LITERAL("/usr/share/google-chrome/extensions");
99 FILE_PATH_LITERAL("/usr/share/chromium/extensions");
100 #endif // defined(GOOGLE_CHROME_BUILD)
101 #endif // defined(OS_LINUX)
103 static base::LazyInstance
<base::FilePath
>
104 g_invalid_specified_user_data_dir
= LAZY_INSTANCE_INITIALIZER
;
106 // Gets the path for internal plugins.
107 bool GetInternalPluginsDirectory(base::FilePath
* result
) {
108 #if defined(OS_MACOSX) && !defined(OS_IOS)
109 // If called from Chrome, get internal plugins from a subdirectory of the
111 if (base::mac::AmIBundled()) {
112 *result
= chrome::GetFrameworkBundlePath();
113 DCHECK(!result
->empty());
114 *result
= result
->Append("Internet Plug-Ins");
117 // In tests, just look in the module directory (below).
120 // The rest of the world expects plugins in the module directory.
121 return PathService::Get(base::DIR_MODULE
, result
);
128 bool PathProvider(int key
, base::FilePath
* result
) {
129 // Some keys are just aliases...
131 case chrome::DIR_APP
:
132 return PathService::Get(base::DIR_MODULE
, result
);
133 case chrome::DIR_LOGS
:
135 // Release builds write to the data dir
136 return PathService::Get(chrome::DIR_USER_DATA
, result
);
138 // Debug builds write next to the binary (in the build tree)
139 #if defined(OS_MACOSX)
140 if (!PathService::Get(base::DIR_EXE
, result
))
142 if (base::mac::AmIBundled()) {
143 // If we're called from chrome, dump it beside the app (outside the
144 // app bundle), if we're called from a unittest, we'll already
145 // outside the bundle so use the exe dir.
146 // exe_dir gave us .../Chromium.app/Contents/MacOS/Chromium.
147 *result
= result
->DirName();
148 *result
= result
->DirName();
149 *result
= result
->DirName();
153 return PathService::Get(base::DIR_EXE
, result
);
154 #endif // defined(OS_MACOSX)
156 case chrome::FILE_RESOURCE_MODULE
:
157 return PathService::Get(base::FILE_MODULE
, result
);
160 // Assume that we will not need to create the directory if it does not exist.
161 // This flag can be set to true for the cases where we want to create it.
162 bool create_dir
= false;
166 case chrome::DIR_USER_DATA
:
167 if (!GetDefaultUserDataDirectory(&cur
)) {
173 case chrome::DIR_USER_DOCUMENTS
:
174 if (!GetUserDocumentsDirectory(&cur
))
178 case chrome::DIR_USER_MUSIC
:
179 if (!GetUserMusicDirectory(&cur
))
182 case chrome::DIR_USER_PICTURES
:
183 if (!GetUserPicturesDirectory(&cur
))
186 case chrome::DIR_USER_VIDEOS
:
187 if (!GetUserVideosDirectory(&cur
))
190 case chrome::DIR_DEFAULT_DOWNLOADS_SAFE
:
191 #if defined(OS_WIN) || defined(OS_LINUX)
192 if (!GetUserDownloadsDirectorySafe(&cur
))
196 // Fall through for all other platforms.
198 case chrome::DIR_DEFAULT_DOWNLOADS
:
199 #if defined(OS_ANDROID)
200 if (!base::android::GetDownloadsDirectory(&cur
))
203 if (!GetUserDownloadsDirectory(&cur
))
205 // Do not create the download directory here, we have done it twice now
206 // and annoyed a lot of users.
209 case chrome::DIR_CRASH_DUMPS
:
210 #if defined(OS_CHROMEOS)
211 // ChromeOS uses a separate directory. See http://crosbug.com/25089
212 cur
= base::FilePath("/var/log/chrome");
213 #elif defined(OS_ANDROID)
214 if (!base::android::GetCacheDirectory(&cur
))
217 // The crash reports are always stored relative to the default user data
218 // directory. This avoids the problem of having to re-initialize the
219 // exception handler after parsing command line options, which may
220 // override the location of the app's profile directory.
221 if (!GetDefaultUserDataDirectory(&cur
))
224 cur
= cur
.Append(FILE_PATH_LITERAL("Crash Reports"));
227 case chrome::DIR_RESOURCES
:
228 #if defined(OS_MACOSX)
229 cur
= base::mac::FrameworkBundlePath();
230 cur
= cur
.Append(FILE_PATH_LITERAL("Resources"));
232 if (!PathService::Get(chrome::DIR_APP
, &cur
))
234 cur
= cur
.Append(FILE_PATH_LITERAL("resources"));
237 case chrome::DIR_INSPECTOR
:
238 if (!PathService::Get(chrome::DIR_RESOURCES
, &cur
))
240 cur
= cur
.Append(FILE_PATH_LITERAL("inspector"));
242 case chrome::DIR_APP_DICTIONARIES
:
243 #if defined(OS_POSIX)
244 // We can't write into the EXE dir on Linux, so keep dictionaries
245 // alongside the safe browsing database in the user data dir.
246 // And we don't want to write into the bundle on the Mac, so push
247 // it to the user data dir there also.
248 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
251 if (!PathService::Get(base::DIR_EXE
, &cur
))
254 cur
= cur
.Append(FILE_PATH_LITERAL("Dictionaries"));
257 case chrome::DIR_INTERNAL_PLUGINS
:
258 if (!GetInternalPluginsDirectory(&cur
))
261 case chrome::DIR_PEPPER_FLASH_PLUGIN
:
262 if (!GetInternalPluginsDirectory(&cur
))
264 cur
= cur
.Append(kPepperFlashBaseDirectory
);
266 case chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN
:
267 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
269 cur
= cur
.Append(kPepperFlashBaseDirectory
);
271 case chrome::DIR_PEPPER_FLASH_DEBUGGER_PLUGIN
:
273 if (!PathService::Get(base::DIR_SYSTEM
, &cur
))
275 cur
= cur
.Append(kPepperFlashDebuggerBaseDirectory
);
276 #elif defined(OS_MACOSX)
277 // TODO(luken): finalize Mac OS directory paths, current consensus is
278 // around /Library/Internet Plug-Ins/PepperFlashPlayer/
284 case chrome::FILE_LOCAL_STATE
:
285 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
287 cur
= cur
.Append(chrome::kLocalStateFilename
);
289 case chrome::FILE_RECORDED_SCRIPT
:
290 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
292 cur
= cur
.Append(FILE_PATH_LITERAL("script.log"));
294 case chrome::FILE_FLASH_PLUGIN
:
295 if (!GetInternalPluginsDirectory(&cur
))
297 cur
= cur
.Append(kInternalFlashPluginFileName
);
299 case chrome::FILE_PEPPER_FLASH_PLUGIN
:
300 if (!PathService::Get(chrome::DIR_PEPPER_FLASH_PLUGIN
, &cur
))
302 cur
= cur
.Append(chrome::kPepperFlashPluginFilename
);
304 case chrome::FILE_PDF_PLUGIN
:
305 if (!GetInternalPluginsDirectory(&cur
))
307 cur
= cur
.Append(kInternalPDFPluginFileName
);
309 case chrome::FILE_EFFECTS_PLUGIN
:
310 if (!GetInternalPluginsDirectory(&cur
))
312 cur
= cur
.Append(kEffectsPluginFileName
);
314 case chrome::FILE_NACL_PLUGIN
:
315 if (!GetInternalPluginsDirectory(&cur
))
317 cur
= cur
.Append(kInternalNaClPluginFileName
);
319 // PNaCl is currenly installable via the component updater or by being
320 // simply built-in. DIR_PNACL_BASE is used as the base directory for
321 // installation via component updater. DIR_PNACL_COMPONENT will be
322 // the final location of pnacl, which is a subdir of DIR_PNACL_BASE.
323 case chrome::DIR_PNACL_BASE
:
324 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
326 cur
= cur
.Append(FILE_PATH_LITERAL("pnacl"));
328 // Where PNaCl files are ultimately located. The default finds the files
329 // inside the InternalPluginsDirectory / build directory, as if it
330 // was shipped along with chrome. The value can be overridden
331 // if it is installed via component updater.
332 case chrome::DIR_PNACL_COMPONENT
:
333 #if defined(OS_MACOSX)
334 // PNaCl really belongs in the InternalPluginsDirectory but actually
335 // copying it there would result in the files also being shipped, which
336 // we don't want yet. So for now, just find them in the directory where
338 if (!PathService::Get(base::DIR_EXE
, &cur
))
340 if (base::mac::AmIBundled()) {
341 // If we're called from chrome, it's beside the app (outside the
342 // app bundle), if we're called from a unittest, we'll already be
343 // outside the bundle so use the exe dir.
344 // exe_dir gave us .../Chromium.app/Contents/MacOS/Chromium.
350 if (!GetInternalPluginsDirectory(&cur
))
353 cur
= cur
.Append(FILE_PATH_LITERAL("pnacl"));
355 #if defined(OS_POSIX) && !defined(OS_MACOSX)
356 case chrome::FILE_O1D_PLUGIN
:
357 if (!PathService::Get(base::DIR_MODULE
, &cur
))
359 cur
= cur
.Append(kO1DPluginFileName
);
361 case chrome::FILE_GTALK_PLUGIN
:
362 if (!PathService::Get(base::DIR_MODULE
, &cur
))
364 cur
= cur
.Append(kGTalkPluginFileName
);
367 #if defined(CLD2_IS_COMPONENT)
368 case chrome::DIR_COMPONENT_CLD2
:
369 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
371 cur
= cur
.Append(FILE_PATH_LITERAL("CLD"));
373 #endif // defined(CLD2_IS_COMPONENT)
374 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
375 #if defined(WIDEVINE_CDM_IS_COMPONENT)
376 case chrome::DIR_COMPONENT_WIDEVINE_CDM
:
377 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
379 cur
= cur
.Append(kWidevineCdmBaseDirectory
);
381 #endif // defined(WIDEVINE_CDM_IS_COMPONENT)
382 // TODO(xhwang): FILE_WIDEVINE_CDM_ADAPTER has different meanings.
383 // In the component case, this is the source adapter. Otherwise, it is the
384 // actual Pepper module that gets loaded.
385 case chrome::FILE_WIDEVINE_CDM_ADAPTER
:
386 if (!GetInternalPluginsDirectory(&cur
))
388 cur
= cur
.AppendASCII(kWidevineCdmAdapterFileName
);
390 #endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
391 case chrome::FILE_RESOURCES_PACK
:
392 #if defined(OS_MACOSX) && !defined(OS_IOS)
393 if (base::mac::AmIBundled()) {
394 cur
= base::mac::FrameworkBundlePath();
395 cur
= cur
.Append(FILE_PATH_LITERAL("Resources"))
396 .Append(FILE_PATH_LITERAL("resources.pak"));
399 #elif defined(OS_ANDROID)
400 if (!PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID
, &cur
))
403 // If we're not bundled on mac or Android, resources.pak should be next
404 // to the binary (e.g., for unit tests).
405 if (!PathService::Get(base::DIR_MODULE
, &cur
))
408 cur
= cur
.Append(FILE_PATH_LITERAL("resources.pak"));
410 case chrome::DIR_RESOURCES_EXTENSION
:
411 if (!PathService::Get(base::DIR_MODULE
, &cur
))
413 cur
= cur
.Append(FILE_PATH_LITERAL("resources"))
414 .Append(FILE_PATH_LITERAL("extension"));
416 #if defined(OS_CHROMEOS)
417 case chrome::DIR_CHROMEOS_WALLPAPERS
:
418 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
420 cur
= cur
.Append(FILE_PATH_LITERAL("wallpapers"));
422 case chrome::DIR_CHROMEOS_WALLPAPER_THUMBNAILS
:
423 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
425 cur
= cur
.Append(FILE_PATH_LITERAL("wallpaper_thumbnails"));
427 case chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS
:
428 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
430 cur
= cur
.Append(FILE_PATH_LITERAL("custom_wallpapers"));
433 #if defined(OS_LINUX) && defined(ENABLE_MANAGED_USERS)
434 case chrome::DIR_MANAGED_USERS_DEFAULT_APPS
:
435 if (!PathService::Get(chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS
, &cur
))
437 cur
= cur
.Append(FILE_PATH_LITERAL("managed_users"));
440 // The following are only valid in the development environment, and
441 // will fail if executed from an installed executable (because the
442 // generated path won't exist).
443 case chrome::DIR_GEN_TEST_DATA
:
444 if (!PathService::Get(base::DIR_MODULE
, &cur
))
446 cur
= cur
.Append(FILE_PATH_LITERAL("test_data"));
447 if (!base::PathExists(cur
)) // We don't want to create this.
450 case chrome::DIR_TEST_DATA
:
451 if (!PathService::Get(base::DIR_SOURCE_ROOT
, &cur
))
453 cur
= cur
.Append(FILE_PATH_LITERAL("chrome"));
454 cur
= cur
.Append(FILE_PATH_LITERAL("test"));
455 cur
= cur
.Append(FILE_PATH_LITERAL("data"));
456 if (!base::PathExists(cur
)) // We don't want to create this.
459 case chrome::DIR_TEST_TOOLS
:
460 if (!PathService::Get(base::DIR_SOURCE_ROOT
, &cur
))
462 cur
= cur
.Append(FILE_PATH_LITERAL("chrome"));
463 cur
= cur
.Append(FILE_PATH_LITERAL("tools"));
464 cur
= cur
.Append(FILE_PATH_LITERAL("test"));
465 if (!base::PathExists(cur
)) // We don't want to create this
468 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
469 case chrome::DIR_POLICY_FILES
: {
470 #if defined(GOOGLE_CHROME_BUILD)
471 cur
= base::FilePath(FILE_PATH_LITERAL("/etc/opt/chrome/policies"));
473 cur
= base::FilePath(FILE_PATH_LITERAL("/etc/chromium/policies"));
478 #if defined(OS_MACOSX) && !defined(OS_IOS)
479 case chrome::DIR_MANAGED_PREFS
: {
480 if (!GetLocalLibraryDirectory(&cur
))
482 cur
= cur
.Append(FILE_PATH_LITERAL("Managed Preferences"));
483 char* login
= getlogin();
486 cur
= cur
.AppendASCII(login
);
487 if (!base::PathExists(cur
)) // We don't want to create this.
491 case chrome::DIR_USER_LIBRARY
: {
492 if (!GetUserLibraryDirectory(&cur
))
494 if (!base::PathExists(cur
)) // We don't want to create this.
498 case chrome::DIR_USER_APPLICATIONS
: {
499 if (!GetUserApplicationsDirectory(&cur
))
501 if (!base::PathExists(cur
)) // We don't want to create this.
506 #if defined(OS_CHROMEOS) || (defined(OS_MACOSX) && !defined(OS_IOS))
507 case chrome::DIR_USER_EXTERNAL_EXTENSIONS
: {
508 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
510 cur
= cur
.Append(FILE_PATH_LITERAL("External Extensions"));
514 #if defined(OS_LINUX)
515 case chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS
: {
516 cur
= base::FilePath(kFilepathSinglePrefExtensions
);
520 case chrome::DIR_EXTERNAL_EXTENSIONS
:
521 #if defined(OS_MACOSX) && !defined(OS_IOS)
522 if (!chrome::GetGlobalApplicationSupportDirectory(&cur
))
525 cur
= cur
.Append(FILE_PATH_LITERAL("Google"))
526 .Append(FILE_PATH_LITERAL("Chrome"))
527 .Append(FILE_PATH_LITERAL("External Extensions"));
530 if (!PathService::Get(base::DIR_MODULE
, &cur
))
533 cur
= cur
.Append(FILE_PATH_LITERAL("extensions"));
538 case chrome::DIR_DEFAULT_APPS
:
539 #if defined(OS_MACOSX)
540 cur
= base::mac::FrameworkBundlePath();
541 cur
= cur
.Append(FILE_PATH_LITERAL("Default Apps"));
543 if (!PathService::Get(chrome::DIR_APP
, &cur
))
545 cur
= cur
.Append(FILE_PATH_LITERAL("default_apps"));
549 #if defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS))
550 case chrome::DIR_NATIVE_MESSAGING
:
551 #if defined(OS_MACOSX)
552 #if defined(GOOGLE_CHROME_BUILD)
553 cur
= base::FilePath(FILE_PATH_LITERAL(
554 "/Library/Google/Chrome/NativeMessagingHosts"));
556 cur
= base::FilePath(FILE_PATH_LITERAL(
557 "/Library/Application Support/Chromium/NativeMessagingHosts"));
559 #else // defined(OS_MACOSX)
560 #if defined(GOOGLE_CHROME_BUILD)
561 cur
= base::FilePath(FILE_PATH_LITERAL(
562 "/etc/opt/chrome/native-messaging-hosts"));
564 cur
= base::FilePath(FILE_PATH_LITERAL(
565 "/etc/chromium/native-messaging-hosts"));
567 #endif // !defined(OS_MACOSX)
570 case chrome::DIR_USER_NATIVE_MESSAGING
:
571 if (!PathService::Get(chrome::DIR_USER_DATA
, &cur
))
573 cur
= cur
.Append(FILE_PATH_LITERAL("NativeMessagingHosts"));
575 #endif // defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS))
581 // TODO(bauerb): http://crbug.com/259796
582 base::ThreadRestrictions::ScopedAllowIO allow_io
;
583 if (create_dir
&& !base::PathExists(cur
) &&
584 !base::CreateDirectory(cur
))
591 // This cannot be done as a static initializer sadly since Visual Studio will
592 // eliminate this object file if there is no direct entry point into it.
593 void RegisterPathProvider() {
594 PathService::RegisterProvider(PathProvider
, PATH_START
, PATH_END
);
597 void SetInvalidSpecifiedUserDataDir(const base::FilePath
& user_data_dir
) {
598 g_invalid_specified_user_data_dir
.Get() = user_data_dir
;
601 const base::FilePath
& GetInvalidSpecifiedUserDataDir() {
602 return g_invalid_specified_user_data_dir
.Get();
605 } // namespace chrome