path_service.cc 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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.
  4. #include "base/path_service.h"
  5. #include <unordered_map>
  6. #include "base/memory/raw_ptr.h"
  7. #include "build/build_config.h"
  8. #if BUILDFLAG(IS_WIN)
  9. #include <windows.h>
  10. #include <shellapi.h>
  11. #include <shlobj.h>
  12. #endif
  13. #include "base/check_op.h"
  14. #include "base/files/file_path.h"
  15. #include "base/files/file_util.h"
  16. #include "base/logging.h"
  17. #include "base/synchronization/lock.h"
  18. #include "build/build_config.h"
  19. namespace base {
  20. bool PathProvider(int key, FilePath* result);
  21. #if BUILDFLAG(IS_WIN)
  22. bool PathProviderWin(int key, FilePath* result);
  23. #elif BUILDFLAG(IS_APPLE)
  24. bool PathProviderMac(int key, FilePath* result);
  25. #elif BUILDFLAG(IS_ANDROID)
  26. bool PathProviderAndroid(int key, FilePath* result);
  27. #elif BUILDFLAG(IS_FUCHSIA)
  28. bool PathProviderFuchsia(int key, FilePath* result);
  29. #elif BUILDFLAG(IS_POSIX)
  30. // PathProviderPosix is the default path provider on POSIX OSes other than
  31. // Mac and Android.
  32. bool PathProviderPosix(int key, FilePath* result);
  33. #endif
  34. namespace {
  35. typedef std::unordered_map<int, FilePath> PathMap;
  36. // We keep a linked list of providers. In a debug build we ensure that no two
  37. // providers claim overlapping keys.
  38. struct Provider {
  39. PathService::ProviderFunc func;
  40. struct Provider* next;
  41. #ifndef NDEBUG
  42. int key_start;
  43. int key_end;
  44. #endif
  45. bool is_static;
  46. };
  47. Provider base_provider = {PathProvider, nullptr,
  48. #ifndef NDEBUG
  49. PATH_START, PATH_END,
  50. #endif
  51. true};
  52. #if BUILDFLAG(IS_WIN)
  53. Provider base_provider_win = {
  54. PathProviderWin,
  55. &base_provider,
  56. #ifndef NDEBUG
  57. PATH_WIN_START,
  58. PATH_WIN_END,
  59. #endif
  60. true
  61. };
  62. #endif
  63. #if BUILDFLAG(IS_APPLE)
  64. Provider base_provider_mac = {
  65. PathProviderMac,
  66. &base_provider,
  67. #ifndef NDEBUG
  68. PATH_MAC_START,
  69. PATH_MAC_END,
  70. #endif
  71. true
  72. };
  73. #endif
  74. #if BUILDFLAG(IS_ANDROID)
  75. Provider base_provider_android = {
  76. PathProviderAndroid,
  77. &base_provider,
  78. #ifndef NDEBUG
  79. PATH_ANDROID_START,
  80. PATH_ANDROID_END,
  81. #endif
  82. true
  83. };
  84. #endif
  85. #if BUILDFLAG(IS_FUCHSIA)
  86. Provider base_provider_fuchsia = {PathProviderFuchsia, &base_provider,
  87. #ifndef NDEBUG
  88. 0, 0,
  89. #endif
  90. true};
  91. #endif
  92. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_ANDROID)
  93. Provider base_provider_posix = {
  94. PathProviderPosix,
  95. &base_provider,
  96. #ifndef NDEBUG
  97. PATH_POSIX_START,
  98. PATH_POSIX_END,
  99. #endif
  100. true
  101. };
  102. #endif
  103. struct PathData {
  104. Lock lock;
  105. PathMap cache; // Cache mappings from path key to path value.
  106. PathMap overrides; // Track path overrides.
  107. raw_ptr<Provider> providers; // Linked list of path service providers.
  108. bool cache_disabled; // Don't use cache if true;
  109. PathData() : cache_disabled(false) {
  110. #if BUILDFLAG(IS_WIN)
  111. providers = &base_provider_win;
  112. #elif BUILDFLAG(IS_APPLE)
  113. providers = &base_provider_mac;
  114. #elif BUILDFLAG(IS_ANDROID)
  115. providers = &base_provider_android;
  116. #elif BUILDFLAG(IS_FUCHSIA)
  117. providers = &base_provider_fuchsia;
  118. #elif BUILDFLAG(IS_POSIX)
  119. providers = &base_provider_posix;
  120. #endif
  121. }
  122. };
  123. static PathData* GetPathData() {
  124. static auto* path_data = new PathData();
  125. return path_data;
  126. }
  127. // Tries to find |key| in the cache.
  128. bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result)
  129. EXCLUSIVE_LOCKS_REQUIRED(path_data->lock) {
  130. if (path_data->cache_disabled)
  131. return false;
  132. // check for a cached version
  133. auto it = path_data->cache.find(key);
  134. if (it != path_data->cache.end()) {
  135. *result = it->second;
  136. return true;
  137. }
  138. return false;
  139. }
  140. // Tries to find |key| in the overrides map.
  141. bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result)
  142. EXCLUSIVE_LOCKS_REQUIRED(path_data->lock) {
  143. // check for an overridden version.
  144. PathMap::const_iterator it = path_data->overrides.find(key);
  145. if (it != path_data->overrides.end()) {
  146. if (!path_data->cache_disabled)
  147. path_data->cache[key] = it->second;
  148. *result = it->second;
  149. return true;
  150. }
  151. return false;
  152. }
  153. } // namespace
  154. // TODO(brettw): this function does not handle long paths (filename > MAX_PATH)
  155. // characters). This isn't supported very well by Windows right now, so it is
  156. // moot, but we should keep this in mind for the future.
  157. // static
  158. bool PathService::Get(int key, FilePath* result) {
  159. PathData* path_data = GetPathData();
  160. DCHECK(path_data);
  161. DCHECK(result);
  162. DCHECK_GT(key, PATH_START);
  163. // Special case the current directory because it can never be cached.
  164. if (key == DIR_CURRENT)
  165. return GetCurrentDirectory(result);
  166. Provider* provider = nullptr;
  167. {
  168. AutoLock scoped_lock(path_data->lock);
  169. if (LockedGetFromCache(key, path_data, result))
  170. return true;
  171. if (LockedGetFromOverrides(key, path_data, result))
  172. return true;
  173. // Get the beginning of the list while it is still locked.
  174. provider = path_data->providers;
  175. }
  176. FilePath path;
  177. // Iterating does not need the lock because only the list head might be
  178. // modified on another thread.
  179. while (provider) {
  180. if (provider->func(key, &path))
  181. break;
  182. DCHECK(path.empty()) << "provider should not have modified path";
  183. provider = provider->next;
  184. }
  185. if (path.empty())
  186. return false;
  187. if (path.ReferencesParent()) {
  188. // Make sure path service never returns a path with ".." in it.
  189. path = MakeAbsoluteFilePath(path);
  190. if (path.empty())
  191. return false;
  192. }
  193. *result = path;
  194. AutoLock scoped_lock(path_data->lock);
  195. if (!path_data->cache_disabled)
  196. path_data->cache[key] = path;
  197. return true;
  198. }
  199. FilePath PathService::CheckedGet(int key) {
  200. FilePath path;
  201. LOG_IF(FATAL, !Get(key, &path)) << "Failed to get the path for " << key;
  202. return path;
  203. }
  204. // static
  205. bool PathService::Override(int key, const FilePath& path) {
  206. // Just call the full function with true for the value of |create|, and
  207. // assume that |path| may not be absolute yet.
  208. return OverrideAndCreateIfNeeded(key, path, false, true);
  209. }
  210. // static
  211. bool PathService::OverrideAndCreateIfNeeded(int key,
  212. const FilePath& path,
  213. bool is_absolute,
  214. bool create) {
  215. PathData* path_data = GetPathData();
  216. DCHECK(path_data);
  217. DCHECK_GT(key, PATH_START) << "invalid path key";
  218. FilePath file_path = path;
  219. // For some locations this will fail if called from inside the sandbox there-
  220. // fore we protect this call with a flag.
  221. if (create) {
  222. // Make sure the directory exists. We need to do this before we translate
  223. // this to the absolute path because on POSIX, MakeAbsoluteFilePath fails
  224. // if called on a non-existent path.
  225. if (!PathExists(file_path) && !CreateDirectory(file_path))
  226. return false;
  227. }
  228. // We need to have an absolute path.
  229. if (!is_absolute) {
  230. file_path = MakeAbsoluteFilePath(file_path);
  231. if (file_path.empty())
  232. return false;
  233. }
  234. DCHECK(file_path.IsAbsolute());
  235. AutoLock scoped_lock(path_data->lock);
  236. // Clear the cache now. Some of its entries could have depended
  237. // on the value we are overriding, and are now out of sync with reality.
  238. path_data->cache.clear();
  239. path_data->overrides[key] = file_path;
  240. return true;
  241. }
  242. // static
  243. bool PathService::RemoveOverrideForTests(int key) {
  244. PathData* path_data = GetPathData();
  245. DCHECK(path_data);
  246. AutoLock scoped_lock(path_data->lock);
  247. if (path_data->overrides.find(key) == path_data->overrides.end())
  248. return false;
  249. // Clear the cache now. Some of its entries could have depended on the value
  250. // we are going to remove, and are now out of sync.
  251. path_data->cache.clear();
  252. path_data->overrides.erase(key);
  253. return true;
  254. }
  255. // static
  256. bool PathService::IsOverriddenForTests(int key) {
  257. PathData* path_data = GetPathData();
  258. DCHECK(path_data);
  259. AutoLock scoped_lock(path_data->lock);
  260. return path_data->overrides.find(key) != path_data->overrides.end();
  261. }
  262. // static
  263. void PathService::RegisterProvider(ProviderFunc func, int key_start,
  264. int key_end) {
  265. PathData* path_data = GetPathData();
  266. DCHECK(path_data);
  267. DCHECK_GT(key_end, key_start);
  268. Provider* p;
  269. p = new Provider;
  270. p->is_static = false;
  271. p->func = func;
  272. #ifndef NDEBUG
  273. p->key_start = key_start;
  274. p->key_end = key_end;
  275. #endif
  276. AutoLock scoped_lock(path_data->lock);
  277. #ifndef NDEBUG
  278. Provider *iter = path_data->providers;
  279. while (iter) {
  280. DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) <<
  281. "path provider collision";
  282. iter = iter->next;
  283. }
  284. #endif
  285. p->next = path_data->providers;
  286. path_data->providers = p;
  287. }
  288. // static
  289. void PathService::DisableCache() {
  290. PathData* path_data = GetPathData();
  291. DCHECK(path_data);
  292. AutoLock scoped_lock(path_data->lock);
  293. path_data->cache.clear();
  294. path_data->cache_disabled = true;
  295. }
  296. } // namespace base