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