// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "build/build_config.h" #if defined(OS_WIN) #include #include #include #endif #include "chrome/common/chrome_paths.h" #include "base/command_line.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/logging.h" #include "base/path_service.h" #include "base/sys_info.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" namespace chrome { // Gets the default user data directory, regardless of whether // DIR_USER_DATA has been overridden by a command-line option. bool GetDefaultUserDataDirectory(std::wstring* result) { #if defined(OS_WIN) if (!PathService::Get(base::DIR_LOCAL_APP_DATA, result)) return false; #if defined(GOOGLE_CHROME_BUILD) file_util::AppendToPath(result, L"Google"); #endif file_util::AppendToPath(result, chrome::kBrowserAppName); file_util::AppendToPath(result, chrome::kUserDataDirname); return true; #else // defined(OS_WIN) // TODO(port): Decide what to do on other platforms. NOTIMPLEMENTED(); return false; #endif // defined(OS_WIN) } bool GetGearsPluginPathFromCommandLine(std::wstring *path) { #ifndef NDEBUG // for debugging, support a cmd line based override CommandLine command_line; *path = command_line.GetSwitchValue(switches::kGearsPluginPathOverride); return !path->empty(); #else return false; #endif } bool PathProvider(int key, FilePath* result) { // Some keys are just aliases... switch (key) { case chrome::DIR_APP: return PathService::Get(base::DIR_MODULE, result); case chrome::DIR_LOGS: #ifndef NDEBUG return PathService::Get(chrome::DIR_USER_DATA, result); #else return PathService::Get(base::DIR_EXE, result); #endif case chrome::FILE_RESOURCE_MODULE: return PathService::Get(base::FILE_MODULE, result); } // Assume that we will need to create the directory if it does not already // exist. This flag can be set to true to prevent checking. bool exists = false; std::wstring cur; switch (key) { case chrome::DIR_USER_DATA: if (!GetDefaultUserDataDirectory(&cur)) return false; break; case chrome::DIR_USER_DOCUMENTS: #if defined(OS_WIN) { wchar_t path_buf[MAX_PATH]; if (FAILED(SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path_buf))) return false; cur.assign(path_buf); } #else // TODO(port): Get the path (possibly using xdg-user-dirs) // or decide we don't need it on other platforms. NOTIMPLEMENTED(); return false; #endif break; case chrome::DIR_DEFAULT_DOWNLOADS: // On Vista, we can get the download path using a Win API // (http://msdn.microsoft.com/en-us/library/bb762584(VS.85).aspx), // but it can be set to Desktop, which is dangerous. Instead, // we just use 'Downloads' under DIR_USER_DOCUMENTS. Localizing // 'downloads' is not a good idea because Chrome's UI language // can be changed. if (!PathService::Get(chrome::DIR_USER_DOCUMENTS, &cur)) return false; file_util::AppendToPath(&cur, L"Downloads"); // TODO(port): This will fail on other platforms unless we // implement DIR_USER_DOCUMENTS or use xdg-user-dirs to // get the download directory independently of DIR_USER_DOCUMENTS. break; case chrome::DIR_CRASH_DUMPS: // The crash reports are always stored relative to the default user data // directory. This avoids the problem of having to re-initialize the // exception handler after parsing command line options, which may // override the location of the app's profile directory. if (!GetDefaultUserDataDirectory(&cur)) return false; file_util::AppendToPath(&cur, L"Crash Reports"); break; case chrome::DIR_USER_DESKTOP: #if defined(OS_WIN) { // We need to go compute the value. It would be nice to support paths // with names longer than MAX_PATH, but the system functions don't seem // to be designed for it either, with the exception of GetTempPath // (but other things will surely break if the temp path is too long, // so we don't bother handling it. wchar_t system_buffer[MAX_PATH]; system_buffer[0] = 0; if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, system_buffer))) return false; cur.assign(system_buffer); } #else // TODO(port): Get the path (possibly using xdg-user-dirs) // or decide we don't need it on other platforms. NOTIMPLEMENTED(); return false; #endif exists = true; break; case chrome::DIR_RESOURCES: if (!PathService::Get(chrome::DIR_APP, &cur)) return false; file_util::AppendToPath(&cur, L"resources"); break; case chrome::DIR_INSPECTOR: if (!PathService::Get(chrome::DIR_APP, &cur)) return false; file_util::AppendToPath(&cur, L"Resources"); file_util::AppendToPath(&cur, L"Inspector"); exists = true; break; case chrome::DIR_THEMES: if (!PathService::Get(chrome::DIR_APP, &cur)) return false; file_util::AppendToPath(&cur, L"themes"); break; case chrome::DIR_LOCALES: if (!PathService::Get(chrome::DIR_APP, &cur)) return false; file_util::AppendToPath(&cur, L"locales"); break; case chrome::DIR_APP_DICTIONARIES: if (!PathService::Get(base::DIR_EXE, &cur)) return false; file_util::AppendToPath(&cur, L"Dictionaries"); break; case chrome::DIR_USER_SCRIPTS: // TODO(aa): Figure out where the script directory should live. #if defined(OS_WIN) cur = L"C:\\SCRIPTS\\"; #else NOTIMPLEMENTED(); return false; #endif exists = true; // don't trigger directory creation code break; case chrome::FILE_LOCAL_STATE: if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) return false; file_util::AppendToPath(&cur, chrome::kLocalStateFilename); exists = true; // don't trigger directory creation code break; case chrome::FILE_RECORDED_SCRIPT: if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) return false; file_util::AppendToPath(&cur, L"script.log"); exists = true; break; case chrome::FILE_GEARS_PLUGIN: if (!GetGearsPluginPathFromCommandLine(&cur)) { // Search for gears.dll alongside chrome.dll first. This new model // allows us to package gears.dll with the Chrome installer and update // it while Chrome is running. if (!PathService::Get(base::DIR_MODULE, &cur)) return false; file_util::AppendToPath(&cur, L"gears.dll"); if (!file_util::PathExists(cur)) { if (!PathService::Get(base::DIR_EXE, &cur)) return false; file_util::AppendToPath(&cur, L"plugins"); file_util::AppendToPath(&cur, L"gears"); file_util::AppendToPath(&cur, L"gears.dll"); } } exists = true; break; // The following are only valid in the development environment, and // will fail if executed from an installed executable (because the // generated path won't exist). case chrome::DIR_TEST_DATA: if (!PathService::Get(chrome::DIR_APP, &cur)) return false; file_util::UpOneDirectory(&cur); file_util::AppendToPath(&cur, L"test"); file_util::AppendToPath(&cur, L"data"); if (!file_util::PathExists(cur)) // we don't want to create this return false; exists = true; break; case chrome::DIR_TEST_TOOLS: if (!PathService::Get(chrome::DIR_APP, &cur)) return false; file_util::UpOneDirectory(&cur); file_util::AppendToPath(&cur, L"tools"); file_util::AppendToPath(&cur, L"test"); if (!file_util::PathExists(cur)) // we don't want to create this return false; exists = true; break; case chrome::FILE_PYTHON_RUNTIME: if (!PathService::Get(chrome::DIR_APP, &cur)) return false; file_util::UpOneDirectory(&cur); // chrome file_util::UpOneDirectory(&cur); file_util::AppendToPath(&cur, L"third_party"); file_util::AppendToPath(&cur, L"python_24"); file_util::AppendToPath(&cur, L"python.exe"); if (!file_util::PathExists(cur)) // we don't want to create this return false; exists = true; break; case chrome::FILE_TEST_SERVER: if (!PathService::Get(chrome::DIR_APP, &cur)) return false; file_util::UpOneDirectory(&cur); file_util::AppendToPath(&cur, L"tools"); file_util::AppendToPath(&cur, L"test"); file_util::AppendToPath(&cur, L"testserver"); file_util::AppendToPath(&cur, L"testserver.py"); if (!file_util::PathExists(cur)) // we don't want to create this return false; exists = true; break; default: return false; } if (!exists && !file_util::PathExists(cur) && !file_util::CreateDirectory(cur)) return false; *result = FilePath::FromWStringHack(cur); return true; } // This cannot be done as a static initializer sadly since Visual Studio will // eliminate this object file if there is no direct entry point into it. void RegisterPathProvider() { PathService::RegisterProvider(PathProvider, PATH_START, PATH_END); } } // namespace chrome