1// Copyright (c) 2011 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/command_line.h"
8#include "base/file_util.h"
9#include "base/logging.h"
10#include "base/path_service.h"
11#include "base/string_util.h"
12#include "base/sys_info.h"
13#include "chrome/common/chrome_constants.h"
14#include "chrome/common/chrome_paths_internal.h"
15#include "chrome/common/chrome_switches.h"
16
17#if defined(OS_MACOSX)
18#include "base/mac/mac_util.h"
19#endif
20
21namespace {
22
23// File name of the internal Flash plugin on different platforms.
24const FilePath::CharType kInternalFlashPluginFileName[] =
25#if defined(OS_MACOSX)
26    FILE_PATH_LITERAL("Flash Player Plugin for Chrome.plugin");
27#elif defined(OS_WIN)
28    FILE_PATH_LITERAL("gcswf32.dll");
29#else  // OS_LINUX, etc.
30    FILE_PATH_LITERAL("libgcflashplayer.so");
31#endif
32
33// File name of the internal PDF plugin on different platforms.
34const FilePath::CharType kInternalPDFPluginFileName[] =
35#if defined(OS_WIN)
36    FILE_PATH_LITERAL("pdf.dll");
37#elif defined(OS_MACOSX)
38    FILE_PATH_LITERAL("PDF.plugin");
39#else  // Linux and Chrome OS
40    FILE_PATH_LITERAL("libpdf.so");
41#endif
42
43// File name of the internal NaCl plugin on different platforms.
44const FilePath::CharType kInternalNaClPluginFileName[] =
45#if defined(OS_WIN)
46    FILE_PATH_LITERAL("ppGoogleNaClPluginChrome.dll");
47#elif defined(OS_MACOSX)
48    // TODO(noelallen) Please verify this extention name is correct.
49    FILE_PATH_LITERAL("ppGoogleNaClPluginChrome.plugin");
50#else  // Linux and Chrome OS
51    FILE_PATH_LITERAL("libppGoogleNaClPluginChrome.so");
52#endif
53
54}  // namespace
55
56namespace chrome {
57
58// Gets the path for internal plugins.
59bool GetInternalPluginsDirectory(FilePath* result) {
60#if defined(OS_MACOSX)
61  // If called from Chrome, get internal plugins from a subdirectory of the
62  // framework.
63  if (base::mac::AmIBundled()) {
64    *result = chrome::GetFrameworkBundlePath();
65    DCHECK(!result->empty());
66    *result = result->Append("Internet Plug-Ins");
67    return true;
68  }
69  // In tests, just look in the module directory (below).
70#endif
71
72  // The rest of the world expects plugins in the module directory.
73  return PathService::Get(base::DIR_MODULE, result);
74}
75
76bool PathProvider(int key, FilePath* result) {
77  // Some keys are just aliases...
78  switch (key) {
79    case chrome::DIR_APP:
80      return PathService::Get(base::DIR_MODULE, result);
81    case chrome::DIR_LOGS:
82#ifdef NDEBUG
83      // Release builds write to the data dir
84      return PathService::Get(chrome::DIR_USER_DATA, result);
85#else
86      // Debug builds write next to the binary (in the build tree)
87#if defined(OS_MACOSX)
88      if (!PathService::Get(base::DIR_EXE, result))
89        return false;
90      if (base::mac::AmIBundled()) {
91        // If we're called from chrome, dump it beside the app (outside the
92        // app bundle), if we're called from a unittest, we'll already
93        // outside the bundle so use the exe dir.
94        // exe_dir gave us .../Chromium.app/Contents/MacOS/Chromium.
95        *result = result->DirName();
96        *result = result->DirName();
97        *result = result->DirName();
98      }
99      return true;
100#else
101      return PathService::Get(base::DIR_EXE, result);
102#endif  // defined(OS_MACOSX)
103#endif  // NDEBUG
104    case chrome::FILE_RESOURCE_MODULE:
105      return PathService::Get(base::FILE_MODULE, result);
106  }
107
108  // Assume that we will not need to create the directory if it does not exist.
109  // This flag can be set to true for the cases where we want to create it.
110  bool create_dir = false;
111
112  FilePath cur;
113  switch (key) {
114    case chrome::DIR_USER_DATA:
115      if (!GetDefaultUserDataDirectory(&cur)) {
116        NOTREACHED();
117        return false;
118      }
119      create_dir = true;
120      break;
121    case chrome::DIR_USER_DOCUMENTS:
122      if (!GetUserDocumentsDirectory(&cur))
123        return false;
124      create_dir = true;
125      break;
126    case chrome::DIR_DEFAULT_DOWNLOADS_SAFE:
127#if defined(OS_WIN)
128      if (!GetUserDownloadsDirectorySafe(&cur))
129        return false;
130      break;
131#else
132      // Fall through for all other platforms.
133#endif
134    case chrome::DIR_DEFAULT_DOWNLOADS:
135      if (!GetUserDownloadsDirectory(&cur))
136        return false;
137      // Do not create the download directory here, we have done it twice now
138      // and annoyed a lot of users.
139      break;
140    case chrome::DIR_CRASH_DUMPS:
141      // The crash reports are always stored relative to the default user data
142      // directory.  This avoids the problem of having to re-initialize the
143      // exception handler after parsing command line options, which may
144      // override the location of the app's profile directory.
145      if (!GetDefaultUserDataDirectory(&cur))
146        return false;
147      cur = cur.Append(FILE_PATH_LITERAL("Crash Reports"));
148      create_dir = true;
149      break;
150    case chrome::DIR_USER_DESKTOP:
151      if (!GetUserDesktop(&cur))
152        return false;
153      break;
154    case chrome::DIR_RESOURCES:
155#if defined(OS_MACOSX)
156      cur = base::mac::MainAppBundlePath();
157      cur = cur.Append(FILE_PATH_LITERAL("Resources"));
158#else
159      if (!PathService::Get(chrome::DIR_APP, &cur))
160        return false;
161      cur = cur.Append(FILE_PATH_LITERAL("resources"));
162#endif
163      break;
164    case chrome::DIR_SHARED_RESOURCES:
165      if (!PathService::Get(chrome::DIR_RESOURCES, &cur))
166        return false;
167      cur = cur.Append(FILE_PATH_LITERAL("shared"));
168      break;
169    case chrome::DIR_INSPECTOR:
170      if (!PathService::Get(chrome::DIR_RESOURCES, &cur))
171        return false;
172      cur = cur.Append(FILE_PATH_LITERAL("inspector"));
173      break;
174    case chrome::DIR_APP_DICTIONARIES:
175#if defined(OS_LINUX) || defined(OS_MACOSX)
176      // We can't write into the EXE dir on Linux, so keep dictionaries
177      // alongside the safe browsing database in the user data dir.
178      // And we don't want to write into the bundle on the Mac, so push
179      // it to the user data dir there also.
180      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
181        return false;
182#else
183      if (!PathService::Get(base::DIR_EXE, &cur))
184        return false;
185#endif
186      cur = cur.Append(FILE_PATH_LITERAL("Dictionaries"));
187      create_dir = true;
188      break;
189    case chrome::DIR_USER_DATA_TEMP:
190      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
191        return false;
192      cur = cur.Append(FILE_PATH_LITERAL("Temp"));
193      break;
194    case chrome::DIR_INTERNAL_PLUGINS:
195      if (!GetInternalPluginsDirectory(&cur))
196        return false;
197      break;
198    case chrome::DIR_MEDIA_LIBS:
199#if defined(OS_MACOSX)
200      *result = base::mac::MainAppBundlePath();
201      *result = result->Append("Libraries");
202      return true;
203#else
204      return PathService::Get(chrome::DIR_APP, result);
205#endif
206    case chrome::FILE_LOCAL_STATE:
207      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
208        return false;
209      cur = cur.Append(chrome::kLocalStateFilename);
210      break;
211    case chrome::FILE_RECORDED_SCRIPT:
212      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
213        return false;
214      cur = cur.Append(FILE_PATH_LITERAL("script.log"));
215      break;
216    case chrome::FILE_FLASH_PLUGIN:
217      if (!GetInternalPluginsDirectory(&cur))
218        return false;
219      cur = cur.Append(kInternalFlashPluginFileName);
220      if (!file_util::PathExists(cur))
221        return false;
222      break;
223    case chrome::FILE_PDF_PLUGIN:
224      if (!GetInternalPluginsDirectory(&cur))
225        return false;
226      cur = cur.Append(kInternalPDFPluginFileName);
227      break;
228    case chrome::FILE_NACL_PLUGIN:
229      if (!GetInternalPluginsDirectory(&cur))
230        return false;
231      cur = cur.Append(kInternalNaClPluginFileName);
232      break;
233    case chrome::FILE_RESOURCES_PACK:
234#if defined(OS_MACOSX)
235      if (base::mac::AmIBundled()) {
236        cur = base::mac::MainAppBundlePath();
237        cur = cur.Append(FILE_PATH_LITERAL("Resources"))
238                 .Append(FILE_PATH_LITERAL("resources.pak"));
239        break;
240      }
241      // If we're not bundled on mac, resources.pak should be next to the
242      // binary (e.g., for unit tests).
243#endif
244      if (!PathService::Get(base::DIR_MODULE, &cur))
245        return false;
246      cur = cur.Append(FILE_PATH_LITERAL("resources.pak"));
247      break;
248#if defined(OS_CHROMEOS)
249    case chrome::FILE_CHROMEOS_API:
250      if (!PathService::Get(base::DIR_MODULE, &cur))
251        return false;
252      cur = cur.Append(FILE_PATH_LITERAL("chromeos"));
253      cur = cur.Append(FILE_PATH_LITERAL("libcros.so"));
254      break;
255#endif
256    // The following are only valid in the development environment, and
257    // will fail if executed from an installed executable (because the
258    // generated path won't exist).
259    case chrome::DIR_TEST_DATA:
260      if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur))
261        return false;
262      cur = cur.Append(FILE_PATH_LITERAL("chrome"));
263      cur = cur.Append(FILE_PATH_LITERAL("test"));
264      cur = cur.Append(FILE_PATH_LITERAL("data"));
265      if (!file_util::PathExists(cur))  // we don't want to create this
266        return false;
267      break;
268    case chrome::DIR_TEST_TOOLS:
269      if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur))
270        return false;
271      cur = cur.Append(FILE_PATH_LITERAL("chrome"));
272      cur = cur.Append(FILE_PATH_LITERAL("tools"));
273      cur = cur.Append(FILE_PATH_LITERAL("test"));
274      if (!file_util::PathExists(cur))  // we don't want to create this
275        return false;
276      break;
277#if defined(OS_POSIX) && !defined(OS_MACOSX)
278    case chrome::DIR_POLICY_FILES: {
279#if defined(GOOGLE_CHROME_BUILD)
280      cur = FilePath(FILE_PATH_LITERAL("/etc/opt/chrome/policies"));
281#else
282      cur = FilePath(FILE_PATH_LITERAL("/etc/chromium/policies"));
283#endif
284      if (!file_util::PathExists(cur))  // we don't want to create this
285        return false;
286      break;
287    }
288#endif
289#if defined(OS_MACOSX)
290    case chrome::DIR_MANAGED_PREFS: {
291      if (!GetLocalLibraryDirectory(&cur))
292        return false;
293      cur = cur.Append(FILE_PATH_LITERAL("Managed Preferences"));
294      char* login = getlogin();
295      if (!login)
296        return false;
297      cur = cur.AppendASCII(login);
298      if (!file_util::PathExists(cur))  // we don't want to create this
299        return false;
300      break;
301    }
302#endif
303#if defined(OS_CHROMEOS)
304    case chrome::DIR_USER_EXTERNAL_EXTENSIONS: {
305      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
306        return false;
307      cur = cur.Append(FILE_PATH_LITERAL("External Extensions"));
308      break;
309    }
310#endif
311    default:
312      return false;
313  }
314
315  if (create_dir && !file_util::PathExists(cur) &&
316      !file_util::CreateDirectory(cur))
317    return false;
318
319  *result = cur;
320  return true;
321}
322
323// This cannot be done as a static initializer sadly since Visual Studio will
324// eliminate this object file if there is no direct entry point into it.
325void RegisterPathProvider() {
326  PathService::RegisterProvider(PathProvider, PATH_START, PATH_END);
327}
328
329}  // namespace chrome
330