15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shellapi.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlobj.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/containers/hash_tables.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/files/file_util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::FilePath;
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using base::MakeAbsoluteFilePath;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool PathProvider(int key, FilePath* result);
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool PathProviderWin(int key, FilePath* result);
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_MACOSX)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool PathProviderMac(int key, FilePath* result);
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_ANDROID)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool PathProviderAndroid(int key, FilePath* result);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PathProviderPosix is the default path provider on POSIX OSes other than
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mac and Android.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool PathProviderPosix(int key, FilePath* result);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef base::hash_map<int, FilePath> PathMap;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We keep a linked list of providers.  In a debug build we ensure that no two
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// providers claim overlapping keys.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct Provider {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathService::ProviderFunc func;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct Provider* next;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int key_start;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int key_end;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_static;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Provider base_provider = {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PathProvider,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NULL,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PATH_START,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PATH_END,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  true
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Provider base_provider_win = {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PathProviderWin,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  &base_provider,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PATH_WIN_START,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PATH_WIN_END,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  true
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Provider base_provider_mac = {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PathProviderMac,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  &base_provider,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PATH_MAC_START,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PATH_MAC_END,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  true
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Provider base_provider_android = {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PathProviderAndroid,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  &base_provider,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PATH_ANDROID_START,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PATH_ANDROID_END,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  true
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Provider base_provider_posix = {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PathProviderPosix,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  &base_provider,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PATH_POSIX_START,
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::PATH_POSIX_END,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  true
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PathData {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock lock;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathMap cache;        // Cache mappings from path key to path value.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathMap overrides;    // Track path overrides.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Provider* providers;  // Linked list of path service providers.
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool cache_disabled;  // Don't use cache if true;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PathData() : cache_disabled(false) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    providers = &base_provider_win;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_MACOSX)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    providers = &base_provider_mac;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_ANDROID)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    providers = &base_provider_android;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    providers = &base_provider_posix;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~PathData() {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Provider* p = providers;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (p) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Provider* next = p->next;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!p->is_static)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        delete p;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p = next;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PathData* GetPathData() {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_path_data.Pointer();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tries to find |key| in the cache. |path_data| should be locked by the caller!
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) {
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (path_data->cache_disabled)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // check for a cached version
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathMap::const_iterator it = path_data->cache.find(key);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != path_data->cache.end()) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result = it->second;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tries to find |key| in the overrides map. |path_data| should be locked by the
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// caller!
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // check for an overridden version.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathMap::const_iterator it = path_data->overrides.find(key);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != path_data->overrides.end()) {
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!path_data->cache_disabled)
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path_data->cache[key] = it->second;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result = it->second;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(brettw): this function does not handle long paths (filename > MAX_PATH)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// characters). This isn't supported very well by Windows right now, so it is
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// moot, but we should keep this in mind for the future.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PathService::Get(int key, FilePath* result) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathData* path_data = GetPathData();
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(path_data);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(result);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(key, base::DIR_CURRENT);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // special case the current directory because it can never be cached
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (key == base::DIR_CURRENT)
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return base::GetCurrentDirectory(result);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Provider* provider = NULL;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock scoped_lock(path_data->lock);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (LockedGetFromCache(key, path_data, result))
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (LockedGetFromOverrides(key, path_data, result))
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the beginning of the list while it is still locked.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    provider = path_data->providers;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath path;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterating does not need the lock because only the list head might be
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // modified on another thread.
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (provider) {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (provider->func(key, &path))
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(path.empty()) << "provider should not have modified path";
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    provider = provider->next;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path.empty())
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (path.ReferencesParent()) {
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Make sure path service never returns a path with ".." in it.
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    path = MakeAbsoluteFilePath(path);
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (path.empty())
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *result = path;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock scoped_lock(path_data->lock);
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!path_data->cache_disabled)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    path_data->cache[key] = path;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PathService::Override(int key, const FilePath& path) {
236010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Just call the full function with true for the value of |create|, and
237010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // assume that |path| may not be absolute yet.
238010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return OverrideAndCreateIfNeeded(key, path, false, true);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PathService::OverrideAndCreateIfNeeded(int key,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const FilePath& path,
244010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                            bool is_absolute,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            bool create) {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathData* path_data = GetPathData();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(path_data);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key";
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath file_path = path;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For some locations this will fail if called from inside the sandbox there-
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // fore we protect this call with a flag.
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (create) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure the directory exists. We need to do this before we translate
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // this to the absolute path because on POSIX, MakeAbsoluteFilePath fails
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // if called on a non-existent path.
2587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!base::PathExists(file_path) &&
259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        !base::CreateDirectory(file_path))
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We need to have an absolute path.
264010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!is_absolute) {
265010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    file_path = MakeAbsoluteFilePath(file_path);
266010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (file_path.empty())
267010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return false;
268010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
269010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  DCHECK(file_path.IsAbsolute());
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock scoped_lock(path_data->lock);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear the cache now. Some of its entries could have depended
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // on the value we are overriding, and are now out of sync with reality.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  path_data->cache.clear();
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  path_data->overrides[key] = file_path;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PathService::RemoveOverride(int key) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathData* path_data = GetPathData();
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(path_data);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock scoped_lock(path_data->lock);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path_data->overrides.find(key) == path_data->overrides.end())
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear the cache now. Some of its entries could have depended on the value
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we are going to remove, and are now out of sync.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  path_data->cache.clear();
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  path_data->overrides.erase(key);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PathService::RegisterProvider(ProviderFunc func, int key_start,
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   int key_end) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathData* path_data = GetPathData();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(path_data);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(key_end, key_start);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Provider* p;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p = new Provider;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->is_static = false;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->func = func;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->key_start = key_start;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->key_end = key_end;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock scoped_lock(path_data->lock);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Provider *iter = path_data->providers;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (iter) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) <<
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "path provider collision";
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iter = iter->next;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->next = path_data->providers;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  path_data->providers = p;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PathService::DisableCache() {
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PathData* path_data = GetPathData();
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(path_data);
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock scoped_lock(path_data->lock);
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_data->cache.clear();
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_data->cache_disabled = true;
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
342