ipc/chromium/src/base/path_service.cc

changeset 0
6474c204b198
     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 +}

mercurial