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