Chromium Code Reviews| 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 // Adds a value to the cache map. |path_data| should be locked by the caller! |
| 144 void LockedAddToCache(int key, const FilePath& path, PathData* path_data) { | |
| 145 // Save the computed path in our cache. | |
| 146 path_data->cache[key] = path; | |
|
jar (doing other things)
2012/09/18 16:47:17
This line of code (which is the whole function), s
pastarmovj
2012/09/19 11:24:28
Done.
| |
| 147 } | |
| 144 | 148 |
| 145 | 149 // Tries to find |key| in the cache. |path_data| should be locked by the caller! |
| 146 // static | 150 bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) { |
| 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 | 151 // check for a cached version |
| 152 PathMap::const_iterator it = path_data->cache.find(key); | 152 PathMap::const_iterator it = path_data->cache.find(key); |
| 153 if (it != path_data->cache.end()) { | 153 if (it != path_data->cache.end()) { |
| 154 *result = it->second; | 154 *result = it->second; |
| 155 return true; | 155 return true; |
| 156 } | 156 } |
| 157 return false; | 157 return false; |
| 158 } | 158 } |
| 159 | 159 |
| 160 // static | 160 // Tries to find |key| in the overrides map. |path_data| should be locked by the |
| 161 bool PathService::GetFromOverrides(int key, FilePath* result) { | 161 // caller! |
| 162 PathData* path_data = GetPathData(); | 162 bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) { |
| 163 base::AutoLock scoped_lock(path_data->lock); | |
| 164 | |
| 165 // check for an overridden version. | 163 // check for an overridden version. |
| 166 PathMap::const_iterator it = path_data->overrides.find(key); | 164 PathMap::const_iterator it = path_data->overrides.find(key); |
| 167 if (it != path_data->overrides.end()) { | 165 if (it != path_data->overrides.end()) { |
| 166 LockedAddToCache(key, it->second, path_data); | |
| 168 *result = it->second; | 167 *result = it->second; |
| 169 return true; | 168 return true; |
| 170 } | 169 } |
| 171 return false; | 170 return false; |
| 172 } | 171 } |
| 173 | 172 |
| 174 // static | 173 } // 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 | 174 |
| 182 // TODO(brettw): this function does not handle long paths (filename > MAX_PATH) | 175 // 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 | 176 // 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. | 177 // moot, but we should keep this in mind for the future. |
| 185 // static | 178 // static |
| 186 bool PathService::Get(int key, FilePath* result) { | 179 bool PathService::Get(int key, FilePath* result) { |
| 187 PathData* path_data = GetPathData(); | 180 PathData* path_data = GetPathData(); |
| 188 DCHECK(path_data); | 181 DCHECK(path_data); |
| 189 DCHECK(result); | 182 DCHECK(result); |
| 190 DCHECK_GE(key, base::DIR_CURRENT); | 183 DCHECK_GE(key, base::DIR_CURRENT); |
| 191 | 184 |
| 185 Provider* provider = NULL; | |
| 192 // special case the current directory because it can never be cached | 186 // special case the current directory because it can never be cached |
| 193 if (key == base::DIR_CURRENT) | 187 if (key == base::DIR_CURRENT) |
| 194 return file_util::GetCurrentDirectory(result); | 188 return file_util::GetCurrentDirectory(result); |
| 195 | 189 |
| 196 if (GetFromCache(key, result)) | 190 { |
| 197 return true; | 191 base::AutoLock scoped_lock(path_data->lock); |
| 192 if (LockedGetFromCache(key, path_data, result)) | |
| 193 return true; | |
| 198 | 194 |
| 199 if (GetFromOverrides(key, result)) | 195 if (LockedGetFromOverrides(key, path_data, result)) |
| 200 return true; | 196 return true; |
| 197 | |
| 198 // Get the beginning of the list while it is still locked. | |
| 199 provider = path_data->providers; | |
| 200 } | |
| 201 | 201 |
| 202 FilePath path; | 202 FilePath path; |
| 203 | 203 |
| 204 // search providers for the requested path | 204 // search providers for the requested path |
| 205 // NOTE: it should be safe to iterate here without the lock | 205 // NOTE: it should be safe to iterate here without the lock |
| 206 // since RegisterProvider always prepends. | 206 // since RegisterProvider always prepends. |
| 207 Provider* provider = path_data->providers; | |
| 208 while (provider) { | 207 while (provider) { |
| 209 if (provider->func(key, &path)) | 208 if (provider->func(key, &path)) |
| 210 break; | 209 break; |
| 211 DCHECK(path.empty()) << "provider should not have modified path"; | 210 DCHECK(path.empty()) << "provider should not have modified path"; |
| 212 provider = provider->next; | 211 provider = provider->next; |
| 213 } | 212 } |
| 214 | 213 |
| 215 if (path.empty()) | 214 if (path.empty()) |
| 216 return false; | 215 return false; |
| 217 | 216 |
| 218 AddToCache(key, path); | 217 { |
| 218 base::AutoLock scoped_lock(path_data->lock); | |
| 219 LockedAddToCache(key, path, path_data); | |
|
jar (doing other things)
2012/09/18 16:47:17
nit: Move these two line down to between lines 222
pastarmovj
2012/09/19 11:24:28
Done.
| |
| 220 } | |
| 219 | 221 |
| 220 *result = path; | 222 *result = path; |
| 221 return true; | 223 return true; |
| 222 } | 224 } |
| 223 | 225 |
| 226 // static | |
| 224 bool PathService::Override(int key, const FilePath& path) { | 227 bool PathService::Override(int key, const FilePath& path) { |
| 225 // Just call the full function with true for the value of |create|. | 228 // Just call the full function with true for the value of |create|. |
| 226 return OverrideAndCreateIfNeeded(key, path, true); | 229 return OverrideAndCreateIfNeeded(key, path, true); |
| 227 } | 230 } |
| 228 | 231 |
| 232 // static | |
| 229 bool PathService::OverrideAndCreateIfNeeded(int key, | 233 bool PathService::OverrideAndCreateIfNeeded(int key, |
| 230 const FilePath& path, | 234 const FilePath& path, |
| 231 bool create) { | 235 bool create) { |
| 232 PathData* path_data = GetPathData(); | 236 PathData* path_data = GetPathData(); |
| 233 DCHECK(path_data); | 237 DCHECK(path_data); |
| 234 DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key"; | 238 DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key"; |
| 235 | 239 |
| 236 FilePath file_path = path; | 240 FilePath file_path = path; |
| 237 | 241 |
| 238 // For some locations this will fail if called from inside the sandbox there- | 242 // For some locations this will fail if called from inside the sandbox there- |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 251 // relative path. | 255 // relative path. |
| 252 if (!file_util::AbsolutePath(&file_path)) | 256 if (!file_util::AbsolutePath(&file_path)) |
| 253 return false; | 257 return false; |
| 254 | 258 |
| 255 base::AutoLock scoped_lock(path_data->lock); | 259 base::AutoLock scoped_lock(path_data->lock); |
| 256 | 260 |
| 257 // Clear the cache now. Some of its entries could have depended | 261 // 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. | 262 // on the value we are overriding, and are now out of sync with reality. |
| 259 path_data->cache.clear(); | 263 path_data->cache.clear(); |
| 260 | 264 |
| 261 path_data->cache[key] = file_path; | |
| 262 path_data->overrides[key] = file_path; | 265 path_data->overrides[key] = file_path; |
| 263 | 266 |
| 264 return true; | 267 return true; |
| 265 } | 268 } |
| 266 | 269 |
| 270 // static | |
| 271 bool PathService::RemoveOverride(int key) { | |
| 272 PathData* path_data = GetPathData(); | |
| 273 DCHECK(path_data); | |
| 274 | |
| 275 base::AutoLock scoped_lock(path_data->lock); | |
| 276 | |
| 277 if (path_data->overrides.find(key) == path_data->overrides.end()) | |
| 278 return false; | |
| 279 | |
| 280 // Clear the cache now. Some of its entries could have depended on the value | |
| 281 // we are going to remove, and are now out of sync. | |
| 282 path_data->cache.clear(); | |
| 283 | |
| 284 path_data->overrides.erase(key); | |
| 285 | |
| 286 return true; | |
| 287 } | |
| 288 | |
| 289 // static | |
| 267 void PathService::RegisterProvider(ProviderFunc func, int key_start, | 290 void PathService::RegisterProvider(ProviderFunc func, int key_start, |
| 268 int key_end) { | 291 int key_end) { |
| 269 PathData* path_data = GetPathData(); | 292 PathData* path_data = GetPathData(); |
| 270 DCHECK(path_data); | 293 DCHECK(path_data); |
| 271 DCHECK_GT(key_end, key_start); | 294 DCHECK_GT(key_end, key_start); |
| 272 | 295 |
| 273 base::AutoLock scoped_lock(path_data->lock); | |
| 274 | |
| 275 Provider* p; | 296 Provider* p; |
| 276 | 297 |
| 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; | 298 p = new Provider; |
| 287 p->is_static = false; | 299 p->is_static = false; |
| 288 p->func = func; | 300 p->func = func; |
| 289 p->next = path_data->providers; | |
| 290 #ifndef NDEBUG | 301 #ifndef NDEBUG |
| 291 p->key_start = key_start; | 302 p->key_start = key_start; |
| 292 p->key_end = key_end; | 303 p->key_end = key_end; |
| 293 #endif | 304 #endif |
| 305 | |
| 306 base::AutoLock scoped_lock(path_data->lock); | |
| 307 | |
| 308 #ifndef NDEBUG | |
| 309 Provider *iter = path_data->providers; | |
| 310 while (iter) { | |
| 311 DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) << | |
| 312 "path provider collision"; | |
| 313 iter = iter->next; | |
| 314 } | |
| 315 #endif | |
| 316 | |
| 317 p->next = path_data->providers; | |
| 294 path_data->providers = p; | 318 path_data->providers = p; |
| 295 } | 319 } |
| OLD | NEW |