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