security/sandbox/chromium/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) 2012 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 #if defined(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/containers/hash_tables.h"
michael@0 14 #include "base/file_util.h"
michael@0 15 #include "base/files/file_path.h"
michael@0 16 #include "base/lazy_instance.h"
michael@0 17 #include "base/logging.h"
michael@0 18 #include "base/synchronization/lock.h"
michael@0 19
michael@0 20 using base::FilePath;
michael@0 21 using base::MakeAbsoluteFilePath;
michael@0 22
michael@0 23 namespace base {
michael@0 24 bool PathProvider(int key, FilePath* result);
michael@0 25 #if defined(OS_WIN)
michael@0 26 bool PathProviderWin(int key, FilePath* result);
michael@0 27 #elif defined(OS_MACOSX)
michael@0 28 bool PathProviderMac(int key, FilePath* result);
michael@0 29 #elif defined(OS_ANDROID)
michael@0 30 bool PathProviderAndroid(int key, FilePath* result);
michael@0 31 #elif defined(OS_POSIX)
michael@0 32 // PathProviderPosix is the default path provider on POSIX OSes other than
michael@0 33 // Mac and Android.
michael@0 34 bool PathProviderPosix(int key, FilePath* result);
michael@0 35 #endif
michael@0 36 }
michael@0 37
michael@0 38 namespace {
michael@0 39
michael@0 40 typedef base::hash_map<int, FilePath> PathMap;
michael@0 41
michael@0 42 // We keep a linked list of providers. In a debug build we ensure that no two
michael@0 43 // providers claim overlapping keys.
michael@0 44 struct Provider {
michael@0 45 PathService::ProviderFunc func;
michael@0 46 struct Provider* next;
michael@0 47 #ifndef NDEBUG
michael@0 48 int key_start;
michael@0 49 int key_end;
michael@0 50 #endif
michael@0 51 bool is_static;
michael@0 52 };
michael@0 53
michael@0 54 Provider base_provider = {
michael@0 55 base::PathProvider,
michael@0 56 NULL,
michael@0 57 #ifndef NDEBUG
michael@0 58 base::PATH_START,
michael@0 59 base::PATH_END,
michael@0 60 #endif
michael@0 61 true
michael@0 62 };
michael@0 63
michael@0 64 #if defined(OS_WIN)
michael@0 65 Provider base_provider_win = {
michael@0 66 base::PathProviderWin,
michael@0 67 &base_provider,
michael@0 68 #ifndef NDEBUG
michael@0 69 base::PATH_WIN_START,
michael@0 70 base::PATH_WIN_END,
michael@0 71 #endif
michael@0 72 true
michael@0 73 };
michael@0 74 #endif
michael@0 75
michael@0 76 #if defined(OS_MACOSX)
michael@0 77 Provider base_provider_mac = {
michael@0 78 base::PathProviderMac,
michael@0 79 &base_provider,
michael@0 80 #ifndef NDEBUG
michael@0 81 base::PATH_MAC_START,
michael@0 82 base::PATH_MAC_END,
michael@0 83 #endif
michael@0 84 true
michael@0 85 };
michael@0 86 #endif
michael@0 87
michael@0 88 #if defined(OS_ANDROID)
michael@0 89 Provider base_provider_android = {
michael@0 90 base::PathProviderAndroid,
michael@0 91 &base_provider,
michael@0 92 #ifndef NDEBUG
michael@0 93 base::PATH_ANDROID_START,
michael@0 94 base::PATH_ANDROID_END,
michael@0 95 #endif
michael@0 96 true
michael@0 97 };
michael@0 98 #endif
michael@0 99
michael@0 100 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
michael@0 101 Provider base_provider_posix = {
michael@0 102 base::PathProviderPosix,
michael@0 103 &base_provider,
michael@0 104 #ifndef NDEBUG
michael@0 105 base::PATH_POSIX_START,
michael@0 106 base::PATH_POSIX_END,
michael@0 107 #endif
michael@0 108 true
michael@0 109 };
michael@0 110 #endif
michael@0 111
michael@0 112
michael@0 113 struct PathData {
michael@0 114 base::Lock lock;
michael@0 115 PathMap cache; // Cache mappings from path key to path value.
michael@0 116 PathMap overrides; // Track path overrides.
michael@0 117 Provider* providers; // Linked list of path service providers.
michael@0 118 bool cache_disabled; // Don't use cache if true;
michael@0 119
michael@0 120 PathData() : cache_disabled(false) {
michael@0 121 #if defined(OS_WIN)
michael@0 122 providers = &base_provider_win;
michael@0 123 #elif defined(OS_MACOSX)
michael@0 124 providers = &base_provider_mac;
michael@0 125 #elif defined(OS_ANDROID)
michael@0 126 providers = &base_provider_android;
michael@0 127 #elif defined(OS_POSIX)
michael@0 128 providers = &base_provider_posix;
michael@0 129 #endif
michael@0 130 }
michael@0 131
michael@0 132 ~PathData() {
michael@0 133 Provider* p = providers;
michael@0 134 while (p) {
michael@0 135 Provider* next = p->next;
michael@0 136 if (!p->is_static)
michael@0 137 delete p;
michael@0 138 p = next;
michael@0 139 }
michael@0 140 }
michael@0 141 };
michael@0 142
michael@0 143 static base::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
michael@0 144
michael@0 145 static PathData* GetPathData() {
michael@0 146 return g_path_data.Pointer();
michael@0 147 }
michael@0 148
michael@0 149 // Tries to find |key| in the cache. |path_data| should be locked by the caller!
michael@0 150 bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) {
michael@0 151 if (path_data->cache_disabled)
michael@0 152 return false;
michael@0 153 // check for a cached version
michael@0 154 PathMap::const_iterator it = path_data->cache.find(key);
michael@0 155 if (it != path_data->cache.end()) {
michael@0 156 *result = it->second;
michael@0 157 return true;
michael@0 158 }
michael@0 159 return false;
michael@0 160 }
michael@0 161
michael@0 162 // Tries to find |key| in the overrides map. |path_data| should be locked by the
michael@0 163 // caller!
michael@0 164 bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) {
michael@0 165 // check for an overridden version.
michael@0 166 PathMap::const_iterator it = path_data->overrides.find(key);
michael@0 167 if (it != path_data->overrides.end()) {
michael@0 168 if (!path_data->cache_disabled)
michael@0 169 path_data->cache[key] = it->second;
michael@0 170 *result = it->second;
michael@0 171 return true;
michael@0 172 }
michael@0 173 return false;
michael@0 174 }
michael@0 175
michael@0 176 } // namespace
michael@0 177
michael@0 178 // TODO(brettw): this function does not handle long paths (filename > MAX_PATH)
michael@0 179 // characters). This isn't supported very well by Windows right now, so it is
michael@0 180 // moot, but we should keep this in mind for the future.
michael@0 181 // static
michael@0 182 bool PathService::Get(int key, FilePath* result) {
michael@0 183 PathData* path_data = GetPathData();
michael@0 184 DCHECK(path_data);
michael@0 185 DCHECK(result);
michael@0 186 DCHECK_GE(key, base::DIR_CURRENT);
michael@0 187
michael@0 188 // special case the current directory because it can never be cached
michael@0 189 if (key == base::DIR_CURRENT)
michael@0 190 return file_util::GetCurrentDirectory(result);
michael@0 191
michael@0 192 Provider* provider = NULL;
michael@0 193 {
michael@0 194 base::AutoLock scoped_lock(path_data->lock);
michael@0 195 if (LockedGetFromCache(key, path_data, result))
michael@0 196 return true;
michael@0 197
michael@0 198 if (LockedGetFromOverrides(key, path_data, result))
michael@0 199 return true;
michael@0 200
michael@0 201 // Get the beginning of the list while it is still locked.
michael@0 202 provider = path_data->providers;
michael@0 203 }
michael@0 204
michael@0 205 FilePath path;
michael@0 206
michael@0 207 // Iterating does not need the lock because only the list head might be
michael@0 208 // modified on another thread.
michael@0 209 while (provider) {
michael@0 210 if (provider->func(key, &path))
michael@0 211 break;
michael@0 212 DCHECK(path.empty()) << "provider should not have modified path";
michael@0 213 provider = provider->next;
michael@0 214 }
michael@0 215
michael@0 216 if (path.empty())
michael@0 217 return false;
michael@0 218
michael@0 219 if (path.ReferencesParent()) {
michael@0 220 // Make sure path service never returns a path with ".." in it.
michael@0 221 path = MakeAbsoluteFilePath(path);
michael@0 222 if (path.empty())
michael@0 223 return false;
michael@0 224 }
michael@0 225 *result = path;
michael@0 226
michael@0 227 base::AutoLock scoped_lock(path_data->lock);
michael@0 228 if (!path_data->cache_disabled)
michael@0 229 path_data->cache[key] = path;
michael@0 230
michael@0 231 return true;
michael@0 232 }
michael@0 233
michael@0 234 // static
michael@0 235 bool PathService::Override(int key, const FilePath& path) {
michael@0 236 // Just call the full function with true for the value of |create|.
michael@0 237 return OverrideAndCreateIfNeeded(key, path, true);
michael@0 238 }
michael@0 239
michael@0 240 // static
michael@0 241 bool PathService::OverrideAndCreateIfNeeded(int key,
michael@0 242 const FilePath& path,
michael@0 243 bool create) {
michael@0 244 PathData* path_data = GetPathData();
michael@0 245 DCHECK(path_data);
michael@0 246 DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key";
michael@0 247
michael@0 248 FilePath file_path = path;
michael@0 249
michael@0 250 // For some locations this will fail if called from inside the sandbox there-
michael@0 251 // fore we protect this call with a flag.
michael@0 252 if (create) {
michael@0 253 // Make sure the directory exists. We need to do this before we translate
michael@0 254 // this to the absolute path because on POSIX, MakeAbsoluteFilePath fails
michael@0 255 // if called on a non-existent path.
michael@0 256 if (!base::PathExists(file_path) &&
michael@0 257 !file_util::CreateDirectory(file_path))
michael@0 258 return false;
michael@0 259 }
michael@0 260
michael@0 261 // We need to have an absolute path.
michael@0 262 file_path = MakeAbsoluteFilePath(file_path);
michael@0 263 if (file_path.empty())
michael@0 264 return false;
michael@0 265
michael@0 266 base::AutoLock scoped_lock(path_data->lock);
michael@0 267
michael@0 268 // Clear the cache now. Some of its entries could have depended
michael@0 269 // on the value we are overriding, and are now out of sync with reality.
michael@0 270 path_data->cache.clear();
michael@0 271
michael@0 272 path_data->overrides[key] = file_path;
michael@0 273
michael@0 274 return true;
michael@0 275 }
michael@0 276
michael@0 277 // static
michael@0 278 bool PathService::RemoveOverride(int key) {
michael@0 279 PathData* path_data = GetPathData();
michael@0 280 DCHECK(path_data);
michael@0 281
michael@0 282 base::AutoLock scoped_lock(path_data->lock);
michael@0 283
michael@0 284 if (path_data->overrides.find(key) == path_data->overrides.end())
michael@0 285 return false;
michael@0 286
michael@0 287 // Clear the cache now. Some of its entries could have depended on the value
michael@0 288 // we are going to remove, and are now out of sync.
michael@0 289 path_data->cache.clear();
michael@0 290
michael@0 291 path_data->overrides.erase(key);
michael@0 292
michael@0 293 return true;
michael@0 294 }
michael@0 295
michael@0 296 // static
michael@0 297 void PathService::RegisterProvider(ProviderFunc func, int key_start,
michael@0 298 int key_end) {
michael@0 299 PathData* path_data = GetPathData();
michael@0 300 DCHECK(path_data);
michael@0 301 DCHECK_GT(key_end, key_start);
michael@0 302
michael@0 303 Provider* p;
michael@0 304
michael@0 305 p = new Provider;
michael@0 306 p->is_static = false;
michael@0 307 p->func = func;
michael@0 308 #ifndef NDEBUG
michael@0 309 p->key_start = key_start;
michael@0 310 p->key_end = key_end;
michael@0 311 #endif
michael@0 312
michael@0 313 base::AutoLock scoped_lock(path_data->lock);
michael@0 314
michael@0 315 #ifndef NDEBUG
michael@0 316 Provider *iter = path_data->providers;
michael@0 317 while (iter) {
michael@0 318 DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) <<
michael@0 319 "path provider collision";
michael@0 320 iter = iter->next;
michael@0 321 }
michael@0 322 #endif
michael@0 323
michael@0 324 p->next = path_data->providers;
michael@0 325 path_data->providers = p;
michael@0 326 }
michael@0 327
michael@0 328 // static
michael@0 329 void PathService::DisableCache() {
michael@0 330 PathData* path_data = GetPathData();
michael@0 331 DCHECK(path_data);
michael@0 332
michael@0 333 base::AutoLock scoped_lock(path_data->lock);
michael@0 334 path_data->cache.clear();
michael@0 335 path_data->cache_disabled = true;
michael@0 336 }

mercurial