ipc/chromium/src/base/path_service.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "base/path_service.h"
michael@0 6
michael@0 7 #ifdef OS_WIN
michael@0 8 #include <windows.h>
michael@0 9 #include <shellapi.h>
michael@0 10 #include <shlobj.h>
michael@0 11 #endif
michael@0 12
michael@0 13 #include "base/file_path.h"
michael@0 14 #include "base/file_util.h"
michael@0 15 #include "base/hash_tables.h"
michael@0 16 #include "base/lock.h"
michael@0 17 #include "base/logging.h"
michael@0 18 #include "base/singleton.h"
michael@0 19 #include "base/string_util.h"
michael@0 20
michael@0 21 namespace base {
michael@0 22 bool PathProvider(int key, FilePath* result);
michael@0 23 #if defined(OS_WIN)
michael@0 24 bool PathProviderWin(int key, FilePath* result);
michael@0 25 #elif defined(OS_MACOSX)
michael@0 26 bool PathProviderMac(int key, FilePath* result);
michael@0 27 #elif defined(OS_LINUX)
michael@0 28 bool PathProviderLinux(int key, FilePath* result);
michael@0 29 #endif
michael@0 30 }
michael@0 31
michael@0 32 namespace {
michael@0 33
michael@0 34 typedef base::hash_map<int, FilePath> PathMap;
michael@0 35 typedef base::hash_set<int> PathSet;
michael@0 36
michael@0 37 // We keep a linked list of providers. In a debug build we ensure that no two
michael@0 38 // providers claim overlapping keys.
michael@0 39 struct Provider {
michael@0 40 PathService::ProviderFunc func;
michael@0 41 struct Provider* next;
michael@0 42 #ifndef NDEBUG
michael@0 43 int key_start;
michael@0 44 int key_end;
michael@0 45 #endif
michael@0 46 bool is_static;
michael@0 47 };
michael@0 48
michael@0 49 static Provider base_provider = {
michael@0 50 base::PathProvider,
michael@0 51 NULL,
michael@0 52 #ifndef NDEBUG
michael@0 53 base::PATH_START,
michael@0 54 base::PATH_END,
michael@0 55 #endif
michael@0 56 true
michael@0 57 };
michael@0 58
michael@0 59 #ifdef OS_WIN
michael@0 60 static Provider base_provider_win = {
michael@0 61 base::PathProviderWin,
michael@0 62 &base_provider,
michael@0 63 #ifndef NDEBUG
michael@0 64 base::PATH_WIN_START,
michael@0 65 base::PATH_WIN_END,
michael@0 66 #endif
michael@0 67 true
michael@0 68 };
michael@0 69 #endif
michael@0 70
michael@0 71 #ifdef OS_MACOSX
michael@0 72 static Provider base_provider_mac = {
michael@0 73 base::PathProviderMac,
michael@0 74 &base_provider,
michael@0 75 #ifndef NDEBUG
michael@0 76 base::PATH_MAC_START,
michael@0 77 base::PATH_MAC_END,
michael@0 78 #endif
michael@0 79 true
michael@0 80 };
michael@0 81 #endif
michael@0 82
michael@0 83 #if defined(OS_LINUX)
michael@0 84 static Provider base_provider_linux = {
michael@0 85 base::PathProviderLinux,
michael@0 86 &base_provider,
michael@0 87 #ifndef NDEBUG
michael@0 88 base::PATH_LINUX_START,
michael@0 89 base::PATH_LINUX_END,
michael@0 90 #endif
michael@0 91 true
michael@0 92 };
michael@0 93 #endif
michael@0 94
michael@0 95
michael@0 96 struct PathData {
michael@0 97 Lock lock;
michael@0 98 PathMap cache; // Track mappings from path key to path value.
michael@0 99 PathSet overrides; // Track whether a path has been overridden.
michael@0 100 Provider* providers; // Linked list of path service providers.
michael@0 101
michael@0 102 PathData() {
michael@0 103 #if defined(OS_WIN)
michael@0 104 providers = &base_provider_win;
michael@0 105 #elif defined(OS_MACOSX)
michael@0 106 providers = &base_provider_mac;
michael@0 107 #elif defined(OS_LINUX)
michael@0 108 providers = &base_provider_linux;
michael@0 109 #endif
michael@0 110 }
michael@0 111
michael@0 112 ~PathData() {
michael@0 113 Provider* p = providers;
michael@0 114 while (p) {
michael@0 115 Provider* next = p->next;
michael@0 116 if (!p->is_static)
michael@0 117 delete p;
michael@0 118 p = next;
michael@0 119 }
michael@0 120 }
michael@0 121 };
michael@0 122
michael@0 123 static PathData* GetPathData() {
michael@0 124 return Singleton<PathData>::get();
michael@0 125 }
michael@0 126
michael@0 127 } // namespace
michael@0 128
michael@0 129
michael@0 130 // static
michael@0 131 bool PathService::GetFromCache(int key, FilePath* result) {
michael@0 132 PathData* path_data = GetPathData();
michael@0 133 AutoLock scoped_lock(path_data->lock);
michael@0 134
michael@0 135 // check for a cached version
michael@0 136 PathMap::const_iterator it = path_data->cache.find(key);
michael@0 137 if (it != path_data->cache.end()) {
michael@0 138 *result = it->second;
michael@0 139 return true;
michael@0 140 }
michael@0 141 return false;
michael@0 142 }
michael@0 143
michael@0 144 // static
michael@0 145 void PathService::AddToCache(int key, const FilePath& path) {
michael@0 146 PathData* path_data = GetPathData();
michael@0 147 AutoLock scoped_lock(path_data->lock);
michael@0 148 // Save the computed path in our cache.
michael@0 149 path_data->cache[key] = path;
michael@0 150 }
michael@0 151
michael@0 152 // TODO(brettw): this function does not handle long paths (filename > MAX_PATH)
michael@0 153 // characters). This isn't supported very well by Windows right now, so it is
michael@0 154 // moot, but we should keep this in mind for the future.
michael@0 155 // static
michael@0 156 bool PathService::Get(int key, FilePath* result) {
michael@0 157 PathData* path_data = GetPathData();
michael@0 158 DCHECK(path_data);
michael@0 159 DCHECK(result);
michael@0 160 DCHECK(key >= base::DIR_CURRENT);
michael@0 161
michael@0 162 // special case the current directory because it can never be cached
michael@0 163 if (key == base::DIR_CURRENT)
michael@0 164 return file_util::GetCurrentDirectory(result);
michael@0 165
michael@0 166 if (GetFromCache(key, result))
michael@0 167 return true;
michael@0 168
michael@0 169 FilePath path;
michael@0 170
michael@0 171 // search providers for the requested path
michael@0 172 // NOTE: it should be safe to iterate here without the lock
michael@0 173 // since RegisterProvider always prepends.
michael@0 174 Provider* provider = path_data->providers;
michael@0 175 while (provider) {
michael@0 176 if (provider->func(key, &path))
michael@0 177 break;
michael@0 178 DCHECK(path.empty()) << "provider should not have modified path";
michael@0 179 provider = provider->next;
michael@0 180 }
michael@0 181
michael@0 182 if (path.empty())
michael@0 183 return false;
michael@0 184
michael@0 185 AddToCache(key, path);
michael@0 186
michael@0 187 *result = path;
michael@0 188 return true;
michael@0 189 }
michael@0 190
michael@0 191 // static
michael@0 192 bool PathService::Get(int key, std::wstring* result) {
michael@0 193 // Deprecated compatibility function.
michael@0 194 FilePath path;
michael@0 195 if (!Get(key, &path))
michael@0 196 return false;
michael@0 197 *result = path.ToWStringHack();
michael@0 198 return true;
michael@0 199 }
michael@0 200
michael@0 201 bool PathService::IsOverridden(int key) {
michael@0 202 PathData* path_data = GetPathData();
michael@0 203 DCHECK(path_data);
michael@0 204
michael@0 205 AutoLock scoped_lock(path_data->lock);
michael@0 206 return path_data->overrides.find(key) != path_data->overrides.end();
michael@0 207 }
michael@0 208
michael@0 209 bool PathService::Override(int key, const std::wstring& path) {
michael@0 210 PathData* path_data = GetPathData();
michael@0 211 DCHECK(path_data);
michael@0 212 DCHECK(key > base::DIR_CURRENT) << "invalid path key";
michael@0 213
michael@0 214 std::wstring file_path = path;
michael@0 215 #if defined(OS_WIN)
michael@0 216 // On Windows we switch the current working directory to load plugins (at
michael@0 217 // least). That's not the case on POSIX.
michael@0 218 // Also, on POSIX, AbsolutePath fails if called on a non-existant path.
michael@0 219 if (!file_util::AbsolutePath(&file_path))
michael@0 220 return false;
michael@0 221 #endif
michael@0 222
michael@0 223 // make sure the directory exists:
michael@0 224 if (!file_util::CreateDirectory(file_path))
michael@0 225 return false;
michael@0 226
michael@0 227 file_util::TrimTrailingSeparator(&file_path);
michael@0 228
michael@0 229 AutoLock scoped_lock(path_data->lock);
michael@0 230 path_data->cache[key] = FilePath::FromWStringHack(file_path);
michael@0 231 path_data->overrides.insert(key);
michael@0 232 return true;
michael@0 233 }
michael@0 234
michael@0 235 bool PathService::SetCurrentDirectory(const std::wstring& current_directory) {
michael@0 236 return file_util::SetCurrentDirectory(current_directory);
michael@0 237 }
michael@0 238
michael@0 239 void PathService::RegisterProvider(ProviderFunc func, int key_start,
michael@0 240 int key_end) {
michael@0 241 PathData* path_data = GetPathData();
michael@0 242 DCHECK(path_data);
michael@0 243 DCHECK(key_end > key_start);
michael@0 244
michael@0 245 AutoLock scoped_lock(path_data->lock);
michael@0 246
michael@0 247 Provider* p;
michael@0 248
michael@0 249 #ifndef NDEBUG
michael@0 250 p = path_data->providers;
michael@0 251 while (p) {
michael@0 252 DCHECK(key_start >= p->key_end || key_end <= p->key_start) <<
michael@0 253 "path provider collision";
michael@0 254 p = p->next;
michael@0 255 }
michael@0 256 #endif
michael@0 257
michael@0 258 p = new Provider;
michael@0 259 p->is_static = false;
michael@0 260 p->func = func;
michael@0 261 p->next = path_data->providers;
michael@0 262 #ifndef NDEBUG
michael@0 263 p->key_start = key_start;
michael@0 264 p->key_end = key_end;
michael@0 265 #endif
michael@0 266 path_data->providers = p;
michael@0 267 }

mercurial