fixup! [M120 Migration] Notify media device state to webbrowser
[platform/framework/web/chromium-efl.git] / base / path_service.cc
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/path_service.h"
6
7 #include <unordered_map>
8 #include <utility>
9
10 #include "base/check_op.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/logging.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/memory/raw_ptr_exclusion.h"
16 #include "base/synchronization/lock.h"
17 #include "build/build_config.h"
18
19 #if BUILDFLAG(IS_WIN)
20 #include <windows.h>
21
22 #include <shellapi.h>
23 #include <shlobj.h>
24 #endif
25
26 namespace base {
27
28 bool PathProvider(int key, FilePath* result);
29
30 #if BUILDFLAG(IS_WIN)
31 bool PathProviderWin(int key, FilePath* result);
32 #elif BUILDFLAG(IS_MAC)
33 bool PathProviderMac(int key, FilePath* result);
34 #elif BUILDFLAG(IS_IOS)
35 bool PathProviderIOS(int key, FilePath* result);
36 #elif BUILDFLAG(IS_ANDROID)
37 bool PathProviderAndroid(int key, FilePath* result);
38 #elif BUILDFLAG(IS_FUCHSIA)
39 bool PathProviderFuchsia(int key, FilePath* result);
40 #elif BUILDFLAG(IS_POSIX)
41 // PathProviderPosix is the default path provider on POSIX OSes other than
42 // Mac and Android.
43 bool PathProviderPosix(int key, FilePath* result);
44 #endif
45
46 namespace {
47
48 typedef std::unordered_map<int, FilePath> PathMap;
49
50 // We keep a linked list of providers.  In a debug build we ensure that no two
51 // providers claim overlapping keys.
52 struct Provider {
53   PathService::ProviderFunc func;
54   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
55   // #reinterpret-cast-trivial-type, #global-scope
56   RAW_PTR_EXCLUSION struct Provider* next;
57 #ifndef NDEBUG
58   int key_start;
59   int key_end;
60 #endif
61   bool is_static;
62 };
63
64 Provider base_provider = {PathProvider, nullptr,
65 #ifndef NDEBUG
66                           PATH_START, PATH_END,
67 #endif
68                           true};
69
70 #if BUILDFLAG(IS_WIN)
71 Provider base_provider_win = {
72   PathProviderWin,
73   &base_provider,
74 #ifndef NDEBUG
75   PATH_WIN_START,
76   PATH_WIN_END,
77 #endif
78   true
79 };
80 #endif
81
82 #if BUILDFLAG(IS_MAC)
83 Provider base_provider_mac = {
84   PathProviderMac,
85   &base_provider,
86 #ifndef NDEBUG
87   PATH_MAC_START,
88   PATH_MAC_END,
89 #endif
90   true
91 };
92 #endif
93
94 #if BUILDFLAG(IS_IOS)
95 Provider base_provider_ios = {
96   PathProviderIOS,
97   &base_provider,
98 #ifndef NDEBUG
99   PATH_IOS_START,
100   PATH_IOS_END,
101 #endif
102   true
103 };
104 #endif
105
106 #if BUILDFLAG(IS_ANDROID)
107 Provider base_provider_android = {
108   PathProviderAndroid,
109   &base_provider,
110 #ifndef NDEBUG
111   PATH_ANDROID_START,
112   PATH_ANDROID_END,
113 #endif
114   true
115 };
116 #endif
117
118 #if BUILDFLAG(IS_FUCHSIA)
119 Provider base_provider_fuchsia = {PathProviderFuchsia, &base_provider,
120 #ifndef NDEBUG
121                                   0, 0,
122 #endif
123                                   true};
124 #endif
125
126 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_ANDROID)
127 Provider base_provider_posix = {
128   PathProviderPosix,
129   &base_provider,
130 #ifndef NDEBUG
131   PATH_POSIX_START,
132   PATH_POSIX_END,
133 #endif
134   true
135 };
136 #endif
137
138
139 struct PathData {
140   Lock lock;
141   PathMap cache;        // Cache mappings from path key to path value.
142   PathMap overrides;    // Track path overrides.
143   raw_ptr<Provider> providers;  // Linked list of path service providers.
144   bool cache_disabled;  // Don't use cache if true;
145
146   PathData() : cache_disabled(false) {
147 #if BUILDFLAG(IS_WIN)
148     providers = &base_provider_win;
149 #elif BUILDFLAG(IS_MAC)
150     providers = &base_provider_mac;
151 #elif BUILDFLAG(IS_IOS)
152     providers = &base_provider_ios;
153 #elif BUILDFLAG(IS_ANDROID)
154     providers = &base_provider_android;
155 #elif BUILDFLAG(IS_FUCHSIA)
156     providers = &base_provider_fuchsia;
157 #elif BUILDFLAG(IS_POSIX)
158     providers = &base_provider_posix;
159 #endif
160   }
161 };
162
163 static PathData* GetPathData() {
164   static auto* path_data = new PathData();
165   return path_data;
166 }
167
168 // Tries to find |key| in the cache.
169 bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result)
170     EXCLUSIVE_LOCKS_REQUIRED(path_data->lock) {
171   if (path_data->cache_disabled)
172     return false;
173   // check for a cached version
174   auto it = path_data->cache.find(key);
175   if (it != path_data->cache.end()) {
176     *result = it->second;
177     return true;
178   }
179   return false;
180 }
181
182 // Tries to find |key| in the overrides map.
183 bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result)
184     EXCLUSIVE_LOCKS_REQUIRED(path_data->lock) {
185   // check for an overridden version.
186   PathMap::const_iterator it = path_data->overrides.find(key);
187   if (it != path_data->overrides.end()) {
188     if (!path_data->cache_disabled)
189       path_data->cache[key] = it->second;
190     *result = it->second;
191     return true;
192   }
193   return false;
194 }
195
196 }  // namespace
197
198 // TODO(brettw): this function does not handle long paths (filename > MAX_PATH)
199 // characters). This isn't supported very well by Windows right now, so it is
200 // moot, but we should keep this in mind for the future.
201 // static
202 bool PathService::Get(int key, FilePath* result) {
203   PathData* path_data = GetPathData();
204   DCHECK(path_data);
205   DCHECK(result);
206   DCHECK_GT(key, PATH_START);
207
208   // Special case the current directory because it can never be cached.
209   if (key == DIR_CURRENT)
210     return GetCurrentDirectory(result);
211
212   Provider* provider = nullptr;
213   {
214     AutoLock scoped_lock(path_data->lock);
215     if (LockedGetFromCache(key, path_data, result))
216       return true;
217
218     if (LockedGetFromOverrides(key, path_data, result))
219       return true;
220
221     // Get the beginning of the list while it is still locked.
222     provider = path_data->providers;
223   }
224
225   FilePath path;
226
227   // Iterating does not need the lock because only the list head might be
228   // modified on another thread.
229   while (provider) {
230     if (provider->func(key, &path))
231       break;
232     DCHECK(path.empty()) << "provider should not have modified path";
233     provider = provider->next;
234   }
235
236   if (path.empty())
237     return false;
238
239   if (path.ReferencesParent()) {
240     // Make sure path service never returns a path with ".." in it.
241     path = MakeAbsoluteFilePath(path);
242     if (path.empty())
243       return false;
244   }
245   *result = path;
246
247   AutoLock scoped_lock(path_data->lock);
248   if (!path_data->cache_disabled)
249     path_data->cache[key] = path;
250
251   return true;
252 }
253
254 FilePath PathService::CheckedGet(int key) {
255   FilePath path;
256   LOG_IF(FATAL, !Get(key, &path)) << "Failed to get the path for " << key;
257   return path;
258 }
259
260 // static
261 bool PathService::Override(int key, const FilePath& path) {
262   // Just call the full function with true for the value of |create|, and
263   // assume that |path| may not be absolute yet.
264   return OverrideAndCreateIfNeeded(key, path, false, true);
265 }
266
267 // static
268 bool PathService::OverrideAndCreateIfNeeded(int key,
269                                             const FilePath& path,
270                                             bool is_absolute,
271                                             bool create) {
272   PathData* path_data = GetPathData();
273   DCHECK(path_data);
274   DCHECK_GT(key, PATH_START) << "invalid path key";
275
276   FilePath file_path = path;
277
278   // Create the directory if requested by the caller. Do this before resolving
279   // `file_path` to an absolute path because on POSIX, MakeAbsoluteFilePath
280   // requires that the path exists.
281   if (create &&
282 #if BUILDFLAG(IS_EFL)
283       !PathExists(file_path) &&
284 #endif
285       !CreateDirectory(file_path)) {
286     return false;
287   }
288
289   // We need to have an absolute path.
290   if (!is_absolute) {
291     file_path = MakeAbsoluteFilePath(file_path);
292     if (file_path.empty())
293       return false;
294   }
295   DCHECK(file_path.IsAbsolute());
296
297   AutoLock scoped_lock(path_data->lock);
298
299   // Clear the cache now. Some of its entries could have depended
300   // on the value we are overriding, and are now out of sync with reality.
301   path_data->cache.clear();
302
303   path_data->overrides[key] = std::move(file_path);
304
305   return true;
306 }
307
308 // static
309 bool PathService::RemoveOverrideForTests(int key) {
310   PathData* path_data = GetPathData();
311   DCHECK(path_data);
312
313   AutoLock scoped_lock(path_data->lock);
314
315   if (path_data->overrides.find(key) == path_data->overrides.end())
316     return false;
317
318   // Clear the cache now. Some of its entries could have depended on the value
319   // we are going to remove, and are now out of sync.
320   path_data->cache.clear();
321
322   path_data->overrides.erase(key);
323
324   return true;
325 }
326
327 // static
328 bool PathService::IsOverriddenForTesting(int key) {
329   PathData* path_data = GetPathData();
330   DCHECK(path_data);
331
332   AutoLock scoped_lock(path_data->lock);
333
334   return path_data->overrides.find(key) != path_data->overrides.end();
335 }
336
337 // static
338 void PathService::RegisterProvider(ProviderFunc func, int key_start,
339                                    int key_end) {
340   PathData* path_data = GetPathData();
341   DCHECK(path_data);
342   DCHECK_GT(key_end, key_start);
343
344   Provider* p;
345
346   p = new Provider;
347   p->is_static = false;
348   p->func = func;
349 #ifndef NDEBUG
350   p->key_start = key_start;
351   p->key_end = key_end;
352 #endif
353
354   AutoLock scoped_lock(path_data->lock);
355
356 #ifndef NDEBUG
357   Provider *iter = path_data->providers;
358   while (iter) {
359     DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) <<
360       "path provider collision";
361     iter = iter->next;
362   }
363 #endif
364
365   p->next = path_data->providers;
366   path_data->providers = p;
367 }
368
369 // static
370 void PathService::DisableCache() {
371   PathData* path_data = GetPathData();
372   DCHECK(path_data);
373
374   AutoLock scoped_lock(path_data->lock);
375   path_data->cache.clear();
376   path_data->cache_disabled = true;
377 }
378
379 }  // namespace base