| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/path_service.h" | 5 #include "base/path_service.h" |
| 6 | 6 |
| 7 #ifdef OS_WIN | 7 #ifdef OS_WIN |
| 8 #include <windows.h> | 8 #include <windows.h> |
| 9 #include <shellapi.h> | 9 #include <shellapi.h> |
| 10 #include <shlobj.h> | 10 #include <shlobj.h> |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 } | 133 } |
| 134 } | 134 } |
| 135 }; | 135 }; |
| 136 | 136 |
| 137 static base::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER; | 137 static base::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER; |
| 138 | 138 |
| 139 static PathData* GetPathData() { | 139 static PathData* GetPathData() { |
| 140 return g_path_data.Pointer(); | 140 return g_path_data.Pointer(); |
| 141 } | 141 } |
| 142 | 142 |
| 143 } // namespace | 143 // Tries to find |key| in the cache. |path_data| should be locked by the caller! |
| 144 | 144 bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) { |
| 145 | |
| 146 // static | |
| 147 bool PathService::GetFromCache(int key, FilePath* result) { | |
| 148 PathData* path_data = GetPathData(); | |
| 149 base::AutoLock scoped_lock(path_data->lock); | |
| 150 | |
| 151 // check for a cached version | 145 // check for a cached version |
| 152 PathMap::const_iterator it = path_data->cache.find(key); | 146 PathMap::const_iterator it = path_data->cache.find(key); |
| 153 if (it != path_data->cache.end()) { | 147 if (it != path_data->cache.end()) { |
| 154 *result = it->second; | 148 *result = it->second; |
| 155 return true; | 149 return true; |
| 156 } | 150 } |
| 157 return false; | 151 return false; |
| 158 } | 152 } |
| 159 | 153 |
| 160 // static | 154 // Tries to find |key| in the overrides map. |path_data| should be locked by the |
| 161 bool PathService::GetFromOverrides(int key, FilePath* result) { | 155 // caller! |
| 162 PathData* path_data = GetPathData(); | 156 bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) { |
| 163 base::AutoLock scoped_lock(path_data->lock); | |
| 164 | |
| 165 // check for an overridden version. | 157 // check for an overridden version. |
| 166 PathMap::const_iterator it = path_data->overrides.find(key); | 158 PathMap::const_iterator it = path_data->overrides.find(key); |
| 167 if (it != path_data->overrides.end()) { | 159 if (it != path_data->overrides.end()) { |
| 160 path_data->cache[key] = it->second; |
| 168 *result = it->second; | 161 *result = it->second; |
| 169 return true; | 162 return true; |
| 170 } | 163 } |
| 171 return false; | 164 return false; |
| 172 } | 165 } |
| 173 | 166 |
| 174 // static | 167 } // namespace |
| 175 void PathService::AddToCache(int key, const FilePath& path) { | |
| 176 PathData* path_data = GetPathData(); | |
| 177 base::AutoLock scoped_lock(path_data->lock); | |
| 178 // Save the computed path in our cache. | |
| 179 path_data->cache[key] = path; | |
| 180 } | |
| 181 | 168 |
| 182 // TODO(brettw): this function does not handle long paths (filename > MAX_PATH) | 169 // TODO(brettw): this function does not handle long paths (filename > MAX_PATH) |
| 183 // characters). This isn't supported very well by Windows right now, so it is | 170 // characters). This isn't supported very well by Windows right now, so it is |
| 184 // moot, but we should keep this in mind for the future. | 171 // moot, but we should keep this in mind for the future. |
| 185 // static | 172 // static |
| 186 bool PathService::Get(int key, FilePath* result) { | 173 bool PathService::Get(int key, FilePath* result) { |
| 187 PathData* path_data = GetPathData(); | 174 PathData* path_data = GetPathData(); |
| 188 DCHECK(path_data); | 175 DCHECK(path_data); |
| 189 DCHECK(result); | 176 DCHECK(result); |
| 190 DCHECK_GE(key, base::DIR_CURRENT); | 177 DCHECK_GE(key, base::DIR_CURRENT); |
| 191 | 178 |
| 192 // special case the current directory because it can never be cached | 179 // special case the current directory because it can never be cached |
| 193 if (key == base::DIR_CURRENT) | 180 if (key == base::DIR_CURRENT) |
| 194 return file_util::GetCurrentDirectory(result); | 181 return file_util::GetCurrentDirectory(result); |
| 195 | 182 |
| 196 if (GetFromCache(key, result)) | 183 Provider* provider = NULL; |
| 197 return true; | 184 { |
| 185 base::AutoLock scoped_lock(path_data->lock); |
| 186 if (LockedGetFromCache(key, path_data, result)) |
| 187 return true; |
| 198 | 188 |
| 199 if (GetFromOverrides(key, result)) | 189 if (LockedGetFromOverrides(key, path_data, result)) |
| 200 return true; | 190 return true; |
| 191 |
| 192 // Get the beginning of the list while it is still locked. |
| 193 provider = path_data->providers; |
| 194 } |
| 201 | 195 |
| 202 FilePath path; | 196 FilePath path; |
| 203 | 197 |
| 204 // search providers for the requested path | 198 // Iterating does not need the lock because only the list head might be |
| 205 // NOTE: it should be safe to iterate here without the lock | 199 // modified on another thread. |
| 206 // since RegisterProvider always prepends. | |
| 207 Provider* provider = path_data->providers; | |
| 208 while (provider) { | 200 while (provider) { |
| 209 if (provider->func(key, &path)) | 201 if (provider->func(key, &path)) |
| 210 break; | 202 break; |
| 211 DCHECK(path.empty()) << "provider should not have modified path"; | 203 DCHECK(path.empty()) << "provider should not have modified path"; |
| 212 provider = provider->next; | 204 provider = provider->next; |
| 213 } | 205 } |
| 214 | 206 |
| 215 if (path.empty()) | 207 if (path.empty()) |
| 216 return false; | 208 return false; |
| 217 | 209 |
| 218 AddToCache(key, path); | 210 *result = path; |
| 219 | 211 |
| 220 *result = path; | 212 base::AutoLock scoped_lock(path_data->lock); |
| 213 path_data->cache[key] = path; |
| 214 |
| 221 return true; | 215 return true; |
| 222 } | 216 } |
| 223 | 217 |
| 218 // static |
| 224 bool PathService::Override(int key, const FilePath& path) { | 219 bool PathService::Override(int key, const FilePath& path) { |
| 225 // Just call the full function with true for the value of |create|. | 220 // Just call the full function with true for the value of |create|. |
| 226 return OverrideAndCreateIfNeeded(key, path, true); | 221 return OverrideAndCreateIfNeeded(key, path, true); |
| 227 } | 222 } |
| 228 | 223 |
| 224 // static |
| 229 bool PathService::OverrideAndCreateIfNeeded(int key, | 225 bool PathService::OverrideAndCreateIfNeeded(int key, |
| 230 const FilePath& path, | 226 const FilePath& path, |
| 231 bool create) { | 227 bool create) { |
| 232 PathData* path_data = GetPathData(); | 228 PathData* path_data = GetPathData(); |
| 233 DCHECK(path_data); | 229 DCHECK(path_data); |
| 234 DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key"; | 230 DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key"; |
| 235 | 231 |
| 236 FilePath file_path = path; | 232 FilePath file_path = path; |
| 237 | 233 |
| 238 // For some locations this will fail if called from inside the sandbox there- | 234 // For some locations this will fail if called from inside the sandbox there- |
| (...skipping 12 matching lines...) Expand all Loading... |
| 251 // relative path. | 247 // relative path. |
| 252 if (!file_util::AbsolutePath(&file_path)) | 248 if (!file_util::AbsolutePath(&file_path)) |
| 253 return false; | 249 return false; |
| 254 | 250 |
| 255 base::AutoLock scoped_lock(path_data->lock); | 251 base::AutoLock scoped_lock(path_data->lock); |
| 256 | 252 |
| 257 // Clear the cache now. Some of its entries could have depended | 253 // Clear the cache now. Some of its entries could have depended |
| 258 // on the value we are overriding, and are now out of sync with reality. | 254 // on the value we are overriding, and are now out of sync with reality. |
| 259 path_data->cache.clear(); | 255 path_data->cache.clear(); |
| 260 | 256 |
| 261 path_data->cache[key] = file_path; | |
| 262 path_data->overrides[key] = file_path; | 257 path_data->overrides[key] = file_path; |
| 263 | 258 |
| 264 return true; | 259 return true; |
| 265 } | 260 } |
| 266 | 261 |
| 262 // static |
| 263 bool PathService::RemoveOverride(int key) { |
| 264 PathData* path_data = GetPathData(); |
| 265 DCHECK(path_data); |
| 266 |
| 267 base::AutoLock scoped_lock(path_data->lock); |
| 268 |
| 269 if (path_data->overrides.find(key) == path_data->overrides.end()) |
| 270 return false; |
| 271 |
| 272 // Clear the cache now. Some of its entries could have depended on the value |
| 273 // we are going to remove, and are now out of sync. |
| 274 path_data->cache.clear(); |
| 275 |
| 276 path_data->overrides.erase(key); |
| 277 |
| 278 return true; |
| 279 } |
| 280 |
| 281 // static |
| 267 void PathService::RegisterProvider(ProviderFunc func, int key_start, | 282 void PathService::RegisterProvider(ProviderFunc func, int key_start, |
| 268 int key_end) { | 283 int key_end) { |
| 269 PathData* path_data = GetPathData(); | 284 PathData* path_data = GetPathData(); |
| 270 DCHECK(path_data); | 285 DCHECK(path_data); |
| 271 DCHECK_GT(key_end, key_start); | 286 DCHECK_GT(key_end, key_start); |
| 272 | 287 |
| 273 base::AutoLock scoped_lock(path_data->lock); | |
| 274 | |
| 275 Provider* p; | 288 Provider* p; |
| 276 | 289 |
| 277 #ifndef NDEBUG | |
| 278 p = path_data->providers; | |
| 279 while (p) { | |
| 280 DCHECK(key_start >= p->key_end || key_end <= p->key_start) << | |
| 281 "path provider collision"; | |
| 282 p = p->next; | |
| 283 } | |
| 284 #endif | |
| 285 | |
| 286 p = new Provider; | 290 p = new Provider; |
| 287 p->is_static = false; | 291 p->is_static = false; |
| 288 p->func = func; | 292 p->func = func; |
| 289 p->next = path_data->providers; | |
| 290 #ifndef NDEBUG | 293 #ifndef NDEBUG |
| 291 p->key_start = key_start; | 294 p->key_start = key_start; |
| 292 p->key_end = key_end; | 295 p->key_end = key_end; |
| 293 #endif | 296 #endif |
| 297 |
| 298 base::AutoLock scoped_lock(path_data->lock); |
| 299 |
| 300 #ifndef NDEBUG |
| 301 Provider *iter = path_data->providers; |
| 302 while (iter) { |
| 303 DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) << |
| 304 "path provider collision"; |
| 305 iter = iter->next; |
| 306 } |
| 307 #endif |
| 308 |
| 309 p->next = path_data->providers; |
| 294 path_data->providers = p; | 310 path_data->providers = p; |
| 295 } | 311 } |
| OLD | NEW |