1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/base/path_service.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,267 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/path_service.h" 1.9 + 1.10 +#ifdef OS_WIN 1.11 +#include <windows.h> 1.12 +#include <shellapi.h> 1.13 +#include <shlobj.h> 1.14 +#endif 1.15 + 1.16 +#include "base/file_path.h" 1.17 +#include "base/file_util.h" 1.18 +#include "base/hash_tables.h" 1.19 +#include "base/lock.h" 1.20 +#include "base/logging.h" 1.21 +#include "base/singleton.h" 1.22 +#include "base/string_util.h" 1.23 + 1.24 +namespace base { 1.25 + bool PathProvider(int key, FilePath* result); 1.26 +#if defined(OS_WIN) 1.27 + bool PathProviderWin(int key, FilePath* result); 1.28 +#elif defined(OS_MACOSX) 1.29 + bool PathProviderMac(int key, FilePath* result); 1.30 +#elif defined(OS_LINUX) 1.31 + bool PathProviderLinux(int key, FilePath* result); 1.32 +#endif 1.33 +} 1.34 + 1.35 +namespace { 1.36 + 1.37 +typedef base::hash_map<int, FilePath> PathMap; 1.38 +typedef base::hash_set<int> PathSet; 1.39 + 1.40 +// We keep a linked list of providers. In a debug build we ensure that no two 1.41 +// providers claim overlapping keys. 1.42 +struct Provider { 1.43 + PathService::ProviderFunc func; 1.44 + struct Provider* next; 1.45 +#ifndef NDEBUG 1.46 + int key_start; 1.47 + int key_end; 1.48 +#endif 1.49 + bool is_static; 1.50 +}; 1.51 + 1.52 +static Provider base_provider = { 1.53 + base::PathProvider, 1.54 + NULL, 1.55 +#ifndef NDEBUG 1.56 + base::PATH_START, 1.57 + base::PATH_END, 1.58 +#endif 1.59 + true 1.60 +}; 1.61 + 1.62 +#ifdef OS_WIN 1.63 +static Provider base_provider_win = { 1.64 + base::PathProviderWin, 1.65 + &base_provider, 1.66 +#ifndef NDEBUG 1.67 + base::PATH_WIN_START, 1.68 + base::PATH_WIN_END, 1.69 +#endif 1.70 + true 1.71 +}; 1.72 +#endif 1.73 + 1.74 +#ifdef OS_MACOSX 1.75 +static Provider base_provider_mac = { 1.76 + base::PathProviderMac, 1.77 + &base_provider, 1.78 +#ifndef NDEBUG 1.79 + base::PATH_MAC_START, 1.80 + base::PATH_MAC_END, 1.81 +#endif 1.82 + true 1.83 +}; 1.84 +#endif 1.85 + 1.86 +#if defined(OS_LINUX) 1.87 +static Provider base_provider_linux = { 1.88 + base::PathProviderLinux, 1.89 + &base_provider, 1.90 +#ifndef NDEBUG 1.91 + base::PATH_LINUX_START, 1.92 + base::PATH_LINUX_END, 1.93 +#endif 1.94 + true 1.95 +}; 1.96 +#endif 1.97 + 1.98 + 1.99 +struct PathData { 1.100 + Lock lock; 1.101 + PathMap cache; // Track mappings from path key to path value. 1.102 + PathSet overrides; // Track whether a path has been overridden. 1.103 + Provider* providers; // Linked list of path service providers. 1.104 + 1.105 + PathData() { 1.106 +#if defined(OS_WIN) 1.107 + providers = &base_provider_win; 1.108 +#elif defined(OS_MACOSX) 1.109 + providers = &base_provider_mac; 1.110 +#elif defined(OS_LINUX) 1.111 + providers = &base_provider_linux; 1.112 +#endif 1.113 + } 1.114 + 1.115 + ~PathData() { 1.116 + Provider* p = providers; 1.117 + while (p) { 1.118 + Provider* next = p->next; 1.119 + if (!p->is_static) 1.120 + delete p; 1.121 + p = next; 1.122 + } 1.123 + } 1.124 +}; 1.125 + 1.126 +static PathData* GetPathData() { 1.127 + return Singleton<PathData>::get(); 1.128 +} 1.129 + 1.130 +} // namespace 1.131 + 1.132 + 1.133 +// static 1.134 +bool PathService::GetFromCache(int key, FilePath* result) { 1.135 + PathData* path_data = GetPathData(); 1.136 + AutoLock scoped_lock(path_data->lock); 1.137 + 1.138 + // check for a cached version 1.139 + PathMap::const_iterator it = path_data->cache.find(key); 1.140 + if (it != path_data->cache.end()) { 1.141 + *result = it->second; 1.142 + return true; 1.143 + } 1.144 + return false; 1.145 +} 1.146 + 1.147 +// static 1.148 +void PathService::AddToCache(int key, const FilePath& path) { 1.149 + PathData* path_data = GetPathData(); 1.150 + AutoLock scoped_lock(path_data->lock); 1.151 + // Save the computed path in our cache. 1.152 + path_data->cache[key] = path; 1.153 +} 1.154 + 1.155 +// TODO(brettw): this function does not handle long paths (filename > MAX_PATH) 1.156 +// characters). This isn't supported very well by Windows right now, so it is 1.157 +// moot, but we should keep this in mind for the future. 1.158 +// static 1.159 +bool PathService::Get(int key, FilePath* result) { 1.160 + PathData* path_data = GetPathData(); 1.161 + DCHECK(path_data); 1.162 + DCHECK(result); 1.163 + DCHECK(key >= base::DIR_CURRENT); 1.164 + 1.165 + // special case the current directory because it can never be cached 1.166 + if (key == base::DIR_CURRENT) 1.167 + return file_util::GetCurrentDirectory(result); 1.168 + 1.169 + if (GetFromCache(key, result)) 1.170 + return true; 1.171 + 1.172 + FilePath path; 1.173 + 1.174 + // search providers for the requested path 1.175 + // NOTE: it should be safe to iterate here without the lock 1.176 + // since RegisterProvider always prepends. 1.177 + Provider* provider = path_data->providers; 1.178 + while (provider) { 1.179 + if (provider->func(key, &path)) 1.180 + break; 1.181 + DCHECK(path.empty()) << "provider should not have modified path"; 1.182 + provider = provider->next; 1.183 + } 1.184 + 1.185 + if (path.empty()) 1.186 + return false; 1.187 + 1.188 + AddToCache(key, path); 1.189 + 1.190 + *result = path; 1.191 + return true; 1.192 +} 1.193 + 1.194 +// static 1.195 +bool PathService::Get(int key, std::wstring* result) { 1.196 + // Deprecated compatibility function. 1.197 + FilePath path; 1.198 + if (!Get(key, &path)) 1.199 + return false; 1.200 + *result = path.ToWStringHack(); 1.201 + return true; 1.202 +} 1.203 + 1.204 +bool PathService::IsOverridden(int key) { 1.205 + PathData* path_data = GetPathData(); 1.206 + DCHECK(path_data); 1.207 + 1.208 + AutoLock scoped_lock(path_data->lock); 1.209 + return path_data->overrides.find(key) != path_data->overrides.end(); 1.210 +} 1.211 + 1.212 +bool PathService::Override(int key, const std::wstring& path) { 1.213 + PathData* path_data = GetPathData(); 1.214 + DCHECK(path_data); 1.215 + DCHECK(key > base::DIR_CURRENT) << "invalid path key"; 1.216 + 1.217 + std::wstring file_path = path; 1.218 +#if defined(OS_WIN) 1.219 + // On Windows we switch the current working directory to load plugins (at 1.220 + // least). That's not the case on POSIX. 1.221 + // Also, on POSIX, AbsolutePath fails if called on a non-existant path. 1.222 + if (!file_util::AbsolutePath(&file_path)) 1.223 + return false; 1.224 +#endif 1.225 + 1.226 + // make sure the directory exists: 1.227 + if (!file_util::CreateDirectory(file_path)) 1.228 + return false; 1.229 + 1.230 + file_util::TrimTrailingSeparator(&file_path); 1.231 + 1.232 + AutoLock scoped_lock(path_data->lock); 1.233 + path_data->cache[key] = FilePath::FromWStringHack(file_path); 1.234 + path_data->overrides.insert(key); 1.235 + return true; 1.236 +} 1.237 + 1.238 +bool PathService::SetCurrentDirectory(const std::wstring& current_directory) { 1.239 + return file_util::SetCurrentDirectory(current_directory); 1.240 +} 1.241 + 1.242 +void PathService::RegisterProvider(ProviderFunc func, int key_start, 1.243 + int key_end) { 1.244 + PathData* path_data = GetPathData(); 1.245 + DCHECK(path_data); 1.246 + DCHECK(key_end > key_start); 1.247 + 1.248 + AutoLock scoped_lock(path_data->lock); 1.249 + 1.250 + Provider* p; 1.251 + 1.252 +#ifndef NDEBUG 1.253 + p = path_data->providers; 1.254 + while (p) { 1.255 + DCHECK(key_start >= p->key_end || key_end <= p->key_start) << 1.256 + "path provider collision"; 1.257 + p = p->next; 1.258 + } 1.259 +#endif 1.260 + 1.261 + p = new Provider; 1.262 + p->is_static = false; 1.263 + p->func = func; 1.264 + p->next = path_data->providers; 1.265 +#ifndef NDEBUG 1.266 + p->key_start = key_start; 1.267 + p->key_end = key_end; 1.268 +#endif 1.269 + path_data->providers = p; 1.270 +}