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. 4 5#include "chrome/common/chrome_paths.h" 6 7#include "base/file_util.h" 8#include "base/logging.h" 9#include "base/mac/bundle_locations.h" 10#include "base/path_service.h" 11#include "base/strings/string_util.h" 12#include "base/sys_info.h" 13#include "base/threading/thread_restrictions.h" 14#include "base/version.h" 15#include "chrome/common/chrome_constants.h" 16#include "chrome/common/chrome_paths_internal.h" 17#include "chrome/common/widevine_cdm_constants.h" 18#include "ui/base/ui_base_paths.h" 19 20#if defined(OS_ANDROID) 21#include "base/android/path_utils.h" 22#endif 23 24#if defined(OS_MACOSX) 25#include "base/mac/foundation_util.h" 26#endif 27 28#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. 29 30namespace { 31 32// File name of the internal Flash plugin on different platforms. 33const base::FilePath::CharType kInternalFlashPluginFileName[] = 34#if defined(OS_MACOSX) 35 FILE_PATH_LITERAL("Flash Player Plugin for Chrome.plugin"); 36#elif defined(OS_WIN) 37 FILE_PATH_LITERAL("gcswf32.dll"); 38#else // OS_LINUX, etc. 39 FILE_PATH_LITERAL("libgcflashplayer.so"); 40#endif 41 42// The Pepper Flash plugins are in a directory with this name. 43const base::FilePath::CharType kPepperFlashBaseDirectory[] = 44 FILE_PATH_LITERAL("PepperFlash"); 45 46// File name of the internal PDF plugin on different platforms. 47const base::FilePath::CharType kInternalPDFPluginFileName[] = 48#if defined(OS_WIN) 49 FILE_PATH_LITERAL("pdf.dll"); 50#elif defined(OS_MACOSX) 51 FILE_PATH_LITERAL("PDF.plugin"); 52#else // Linux and Chrome OS 53 FILE_PATH_LITERAL("libpdf.so"); 54#endif 55 56// File name of the internal NaCl plugin on different platforms. 57const base::FilePath::CharType kInternalNaClPluginFileName[] = 58#if defined(OS_WIN) 59 FILE_PATH_LITERAL("ppGoogleNaClPluginChrome.dll"); 60#elif defined(OS_MACOSX) 61 // TODO(noelallen) Please verify this extention name is correct. 62 FILE_PATH_LITERAL("ppGoogleNaClPluginChrome.plugin"); 63#else // Linux and Chrome OS 64 FILE_PATH_LITERAL("libppGoogleNaClPluginChrome.so"); 65#endif 66 67const base::FilePath::CharType kEffectsPluginFileName[] = 68#if defined(OS_WIN) 69 FILE_PATH_LITERAL("pepper/libppeffects.dll"); 70#elif defined(OS_MACOSX) 71 FILE_PATH_LITERAL("pepper/libppeffects.plugin"); 72#else // Linux and Chrome OS 73 FILE_PATH_LITERAL("pepper/libppeffects.so"); 74#endif 75 76#if defined(OS_POSIX) && !defined(OS_MACOSX) 77 78const base::FilePath::CharType kO1DPluginFileName[] = 79 FILE_PATH_LITERAL("pepper/libppo1d.so"); 80 81const base::FilePath::CharType kGTalkPluginFileName[] = 82 FILE_PATH_LITERAL("pepper/libppgoogletalk.so"); 83 84#endif // defined(OS_POSIX) && !defined(OS_MACOSX) 85 86#if defined(OS_LINUX) 87// The path to the external extension <id>.json files. 88// /usr/share seems like a good choice, see: http://www.pathname.com/fhs/ 89const base::FilePath::CharType kFilepathSinglePrefExtensions[] = 90#if defined(GOOGLE_CHROME_BUILD) 91 FILE_PATH_LITERAL("/usr/share/google-chrome/extensions"); 92#else 93 FILE_PATH_LITERAL("/usr/share/chromium/extensions"); 94#endif // defined(GOOGLE_CHROME_BUILD) 95#endif // defined(OS_LINUX) 96 97} // namespace 98 99namespace chrome { 100 101// Gets the path for internal plugins. 102bool GetInternalPluginsDirectory(base::FilePath* result) { 103#if defined(OS_MACOSX) && !defined(OS_IOS) 104 // If called from Chrome, get internal plugins from a subdirectory of the 105 // framework. 106 if (base::mac::AmIBundled()) { 107 *result = chrome::GetFrameworkBundlePath(); 108 DCHECK(!result->empty()); 109 *result = result->Append("Internet Plug-Ins"); 110 return true; 111 } 112 // In tests, just look in the module directory (below). 113#endif 114 115 // The rest of the world expects plugins in the module directory. 116 return PathService::Get(base::DIR_MODULE, result); 117} 118 119bool PathProvider(int key, base::FilePath* result) { 120 // Some keys are just aliases... 121 switch (key) { 122 case chrome::DIR_APP: 123 return PathService::Get(base::DIR_MODULE, result); 124 case chrome::DIR_LOGS: 125#ifdef NDEBUG 126 // Release builds write to the data dir 127 return PathService::Get(chrome::DIR_USER_DATA, result); 128#else 129 // Debug builds write next to the binary (in the build tree) 130#if defined(OS_MACOSX) 131 if (!PathService::Get(base::DIR_EXE, result)) 132 return false; 133 if (base::mac::AmIBundled()) { 134 // If we're called from chrome, dump it beside the app (outside the 135 // app bundle), if we're called from a unittest, we'll already 136 // outside the bundle so use the exe dir. 137 // exe_dir gave us .../Chromium.app/Contents/MacOS/Chromium. 138 *result = result->DirName(); 139 *result = result->DirName(); 140 *result = result->DirName(); 141 } 142 return true; 143#else 144 return PathService::Get(base::DIR_EXE, result); 145#endif // defined(OS_MACOSX) 146#endif // NDEBUG 147 case chrome::FILE_RESOURCE_MODULE: 148 return PathService::Get(base::FILE_MODULE, result); 149 } 150 151 // Assume that we will not need to create the directory if it does not exist. 152 // This flag can be set to true for the cases where we want to create it. 153 bool create_dir = false; 154 155 base::FilePath cur; 156 switch (key) { 157 case chrome::DIR_USER_DATA: 158 if (!GetDefaultUserDataDirectory(&cur)) { 159 NOTREACHED(); 160 return false; 161 } 162 create_dir = true; 163 break; 164 case chrome::DIR_USER_DOCUMENTS: 165 if (!GetUserDocumentsDirectory(&cur)) 166 return false; 167 create_dir = true; 168 break; 169 case chrome::DIR_USER_MUSIC: 170 if (!GetUserMusicDirectory(&cur)) 171 return false; 172 break; 173 case chrome::DIR_USER_PICTURES: 174 if (!GetUserPicturesDirectory(&cur)) 175 return false; 176 break; 177 case chrome::DIR_USER_VIDEOS: 178 if (!GetUserVideosDirectory(&cur)) 179 return false; 180 break; 181 case chrome::DIR_DEFAULT_DOWNLOADS_SAFE: 182#if defined(OS_WIN) || defined(OS_LINUX) 183 if (!GetUserDownloadsDirectorySafe(&cur)) 184 return false; 185 break; 186#else 187 // Fall through for all other platforms. 188#endif 189 case chrome::DIR_DEFAULT_DOWNLOADS: 190#if defined(OS_ANDROID) 191 if (!base::android::GetDownloadsDirectory(&cur)) 192 return false; 193#else 194 if (!GetUserDownloadsDirectory(&cur)) 195 return false; 196 // Do not create the download directory here, we have done it twice now 197 // and annoyed a lot of users. 198#endif 199 break; 200 case chrome::DIR_CRASH_DUMPS: 201#if defined(OS_CHROMEOS) 202 // ChromeOS uses a separate directory. See http://crosbug.com/25089 203 cur = base::FilePath("/var/log/chrome"); 204#elif defined(OS_ANDROID) 205 if (!base::android::GetCacheDirectory(&cur)) 206 return false; 207#else 208 // The crash reports are always stored relative to the default user data 209 // directory. This avoids the problem of having to re-initialize the 210 // exception handler after parsing command line options, which may 211 // override the location of the app's profile directory. 212 if (!GetDefaultUserDataDirectory(&cur)) 213 return false; 214#endif 215 cur = cur.Append(FILE_PATH_LITERAL("Crash Reports")); 216 create_dir = true; 217 break; 218 case chrome::DIR_RESOURCES: 219#if defined(OS_MACOSX) 220 cur = base::mac::FrameworkBundlePath(); 221 cur = cur.Append(FILE_PATH_LITERAL("Resources")); 222#else 223 if (!PathService::Get(chrome::DIR_APP, &cur)) 224 return false; 225 cur = cur.Append(FILE_PATH_LITERAL("resources")); 226#endif 227 break; 228 case chrome::DIR_INSPECTOR: 229 if (!PathService::Get(chrome::DIR_RESOURCES, &cur)) 230 return false; 231 cur = cur.Append(FILE_PATH_LITERAL("inspector")); 232 break; 233 case chrome::DIR_APP_DICTIONARIES: 234#if defined(OS_POSIX) 235 // We can't write into the EXE dir on Linux, so keep dictionaries 236 // alongside the safe browsing database in the user data dir. 237 // And we don't want to write into the bundle on the Mac, so push 238 // it to the user data dir there also. 239 if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) 240 return false; 241#else 242 if (!PathService::Get(base::DIR_EXE, &cur)) 243 return false; 244#endif 245 cur = cur.Append(FILE_PATH_LITERAL("Dictionaries")); 246 create_dir = true; 247 break; 248 case chrome::DIR_INTERNAL_PLUGINS: 249 if (!GetInternalPluginsDirectory(&cur)) 250 return false; 251 break; 252 case chrome::DIR_PEPPER_FLASH_PLUGIN: 253 if (!GetInternalPluginsDirectory(&cur)) 254 return false; 255 cur = cur.Append(kPepperFlashBaseDirectory); 256 break; 257 case chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN: 258 if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) 259 return false; 260 cur = cur.Append(kPepperFlashBaseDirectory); 261 break; 262 case chrome::FILE_LOCAL_STATE: 263 if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) 264 return false; 265 cur = cur.Append(chrome::kLocalStateFilename); 266 break; 267 case chrome::FILE_RECORDED_SCRIPT: 268 if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) 269 return false; 270 cur = cur.Append(FILE_PATH_LITERAL("script.log")); 271 break; 272 case chrome::FILE_FLASH_PLUGIN: 273 if (!GetInternalPluginsDirectory(&cur)) 274 return false; 275 cur = cur.Append(kInternalFlashPluginFileName); 276 break; 277 case chrome::FILE_PEPPER_FLASH_PLUGIN: 278 if (!PathService::Get(chrome::DIR_PEPPER_FLASH_PLUGIN, &cur)) 279 return false; 280 cur = cur.Append(chrome::kPepperFlashPluginFilename); 281 break; 282 case chrome::FILE_PDF_PLUGIN: 283 if (!GetInternalPluginsDirectory(&cur)) 284 return false; 285 cur = cur.Append(kInternalPDFPluginFileName); 286 break; 287 case chrome::FILE_EFFECTS_PLUGIN: 288 if (!GetInternalPluginsDirectory(&cur)) 289 return false; 290 cur = cur.Append(kEffectsPluginFileName); 291 break; 292 case chrome::FILE_NACL_PLUGIN: 293 if (!GetInternalPluginsDirectory(&cur)) 294 return false; 295 cur = cur.Append(kInternalNaClPluginFileName); 296 break; 297 // PNaCl is currenly installable via the component updater or by being 298 // simply built-in. DIR_PNACL_BASE is used as the base directory for 299 // installation via component updater. DIR_PNACL_COMPONENT will be 300 // the final location of pnacl, which is a subdir of DIR_PNACL_BASE. 301 case chrome::DIR_PNACL_BASE: 302 if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) 303 return false; 304 cur = cur.Append(FILE_PATH_LITERAL("pnacl")); 305 break; 306 // Where PNaCl files are ultimately located. The default finds the files 307 // inside the InternalPluginsDirectory / build directory, as if it 308 // was shipped along with chrome. The value can be overridden 309 // if it is installed via component updater. 310 case chrome::DIR_PNACL_COMPONENT: 311#if defined(OS_MACOSX) 312 // PNaCl really belongs in the InternalPluginsDirectory but actually 313 // copying it there would result in the files also being shipped, which 314 // we don't want yet. So for now, just find them in the directory where 315 // they get built. 316 if (!PathService::Get(base::DIR_EXE, &cur)) 317 return false; 318 if (base::mac::AmIBundled()) { 319 // If we're called from chrome, it's beside the app (outside the 320 // app bundle), if we're called from a unittest, we'll already be 321 // outside the bundle so use the exe dir. 322 // exe_dir gave us .../Chromium.app/Contents/MacOS/Chromium. 323 cur = cur.DirName(); 324 cur = cur.DirName(); 325 cur = cur.DirName(); 326 } 327#else 328 if (!GetInternalPluginsDirectory(&cur)) 329 return false; 330#endif 331 cur = cur.Append(FILE_PATH_LITERAL("pnacl")); 332 break; 333#if defined(OS_POSIX) && !defined(OS_MACOSX) 334 case chrome::FILE_O1D_PLUGIN: 335 if (!PathService::Get(base::DIR_MODULE, &cur)) 336 return false; 337 cur = cur.Append(kO1DPluginFileName); 338 break; 339 case chrome::FILE_GTALK_PLUGIN: 340 if (!PathService::Get(base::DIR_MODULE, &cur)) 341 return false; 342 cur = cur.Append(kGTalkPluginFileName); 343 break; 344#endif 345#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) 346#if defined(WIDEVINE_CDM_IS_COMPONENT) 347 case chrome::DIR_COMPONENT_WIDEVINE_CDM: 348 if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) 349 return false; 350 cur = cur.Append(kWidevineCdmBaseDirectory); 351 break; 352#endif // defined(WIDEVINE_CDM_IS_COMPONENT) 353 // TODO(xhwang): FILE_WIDEVINE_CDM_ADAPTER has different meanings. 354 // In the component case, this is the source adapter. Otherwise, it is the 355 // actual Pepper module that gets loaded. 356 case chrome::FILE_WIDEVINE_CDM_ADAPTER: 357 if (!GetInternalPluginsDirectory(&cur)) 358 return false; 359 cur = cur.AppendASCII(kWidevineCdmAdapterFileName); 360 break; 361#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) 362 case chrome::FILE_RESOURCES_PACK: 363#if defined(OS_MACOSX) && !defined(OS_IOS) 364 if (base::mac::AmIBundled()) { 365 cur = base::mac::FrameworkBundlePath(); 366 cur = cur.Append(FILE_PATH_LITERAL("Resources")) 367 .Append(FILE_PATH_LITERAL("resources.pak")); 368 break; 369 } 370#elif defined(OS_ANDROID) 371 if (!PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &cur)) 372 return false; 373#else 374 // If we're not bundled on mac or Android, resources.pak should be next 375 // to the binary (e.g., for unit tests). 376 if (!PathService::Get(base::DIR_MODULE, &cur)) 377 return false; 378#endif 379 cur = cur.Append(FILE_PATH_LITERAL("resources.pak")); 380 break; 381 case chrome::DIR_RESOURCES_EXTENSION: 382 if (!PathService::Get(base::DIR_MODULE, &cur)) 383 return false; 384 cur = cur.Append(FILE_PATH_LITERAL("resources")) 385 .Append(FILE_PATH_LITERAL("extension")); 386 break; 387#if defined(OS_CHROMEOS) 388 case chrome::DIR_CHROMEOS_WALLPAPERS: 389 if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) 390 return false; 391 cur = cur.Append(FILE_PATH_LITERAL("wallpapers")); 392 break; 393 case chrome::DIR_CHROMEOS_WALLPAPER_THUMBNAILS: 394 if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) 395 return false; 396 cur = cur.Append(FILE_PATH_LITERAL("wallpaper_thumbnails")); 397 break; 398 case chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS: 399 if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) 400 return false; 401 cur = cur.Append(FILE_PATH_LITERAL("custom_wallpapers")); 402 break; 403#endif 404#if defined(OS_LINUX) && defined(ENABLE_MANAGED_USERS) 405 case chrome::DIR_MANAGED_USERS_DEFAULT_APPS: 406 if (!PathService::Get(chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS, &cur)) 407 return false; 408 cur = cur.Append(FILE_PATH_LITERAL("managed_users")); 409 break; 410#endif 411 // The following are only valid in the development environment, and 412 // will fail if executed from an installed executable (because the 413 // generated path won't exist). 414 case chrome::DIR_GEN_TEST_DATA: 415 if (!PathService::Get(base::DIR_MODULE, &cur)) 416 return false; 417 cur = cur.Append(FILE_PATH_LITERAL("test_data")); 418 if (!base::PathExists(cur)) // We don't want to create this. 419 return false; 420 break; 421 case chrome::DIR_TEST_DATA: 422 if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur)) 423 return false; 424 cur = cur.Append(FILE_PATH_LITERAL("chrome")); 425 cur = cur.Append(FILE_PATH_LITERAL("test")); 426 cur = cur.Append(FILE_PATH_LITERAL("data")); 427 if (!base::PathExists(cur)) // We don't want to create this. 428 return false; 429 break; 430 case chrome::DIR_TEST_TOOLS: 431 if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur)) 432 return false; 433 cur = cur.Append(FILE_PATH_LITERAL("chrome")); 434 cur = cur.Append(FILE_PATH_LITERAL("tools")); 435 cur = cur.Append(FILE_PATH_LITERAL("test")); 436 if (!base::PathExists(cur)) // We don't want to create this 437 return false; 438 break; 439#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) 440 case chrome::DIR_POLICY_FILES: { 441#if defined(GOOGLE_CHROME_BUILD) 442 cur = base::FilePath(FILE_PATH_LITERAL("/etc/opt/chrome/policies")); 443#else 444 cur = base::FilePath(FILE_PATH_LITERAL("/etc/chromium/policies")); 445#endif 446 break; 447 } 448#endif 449#if defined(OS_MACOSX) && !defined(OS_IOS) 450 case chrome::DIR_MANAGED_PREFS: { 451 if (!GetLocalLibraryDirectory(&cur)) 452 return false; 453 cur = cur.Append(FILE_PATH_LITERAL("Managed Preferences")); 454 char* login = getlogin(); 455 if (!login) 456 return false; 457 cur = cur.AppendASCII(login); 458 if (!base::PathExists(cur)) // We don't want to create this. 459 return false; 460 break; 461 } 462#endif 463#if defined(OS_CHROMEOS) || (defined(OS_MACOSX) && !defined(OS_IOS)) 464 case chrome::DIR_USER_EXTERNAL_EXTENSIONS: { 465 if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) 466 return false; 467 cur = cur.Append(FILE_PATH_LITERAL("External Extensions")); 468 break; 469 } 470#endif 471#if defined(OS_LINUX) 472 case chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS: { 473 cur = base::FilePath(kFilepathSinglePrefExtensions); 474 break; 475 } 476#endif 477 case chrome::DIR_EXTERNAL_EXTENSIONS: 478#if defined(OS_MACOSX) && !defined(OS_IOS) 479 if (!chrome::GetGlobalApplicationSupportDirectory(&cur)) 480 return false; 481 482 cur = cur.Append(FILE_PATH_LITERAL("Google")) 483 .Append(FILE_PATH_LITERAL("Chrome")) 484 .Append(FILE_PATH_LITERAL("External Extensions")); 485 create_dir = false; 486#else 487 if (!PathService::Get(base::DIR_MODULE, &cur)) 488 return false; 489 490 cur = cur.Append(FILE_PATH_LITERAL("extensions")); 491 create_dir = true; 492#endif 493 break; 494 495 case chrome::DIR_DEFAULT_APPS: 496#if defined(OS_MACOSX) 497 cur = base::mac::FrameworkBundlePath(); 498 cur = cur.Append(FILE_PATH_LITERAL("Default Apps")); 499#else 500 if (!PathService::Get(chrome::DIR_APP, &cur)) 501 return false; 502 cur = cur.Append(FILE_PATH_LITERAL("default_apps")); 503#endif 504 break; 505 506 default: 507 return false; 508 } 509 510 // TODO(bauerb): http://crbug.com/259796 511 base::ThreadRestrictions::ScopedAllowIO allow_io; 512 if (create_dir && !base::PathExists(cur) && 513 !base::CreateDirectory(cur)) 514 return false; 515 516 *result = cur; 517 return true; 518} 519 520// This cannot be done as a static initializer sadly since Visual Studio will 521// eliminate this object file if there is no direct entry point into it. 522void RegisterPathProvider() { 523 PathService::RegisterProvider(PathProvider, PATH_START, PATH_END); 524} 525 526} // namespace chrome 527