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.

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

mercurial