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 AddToCache(int key, const FilePath& path, PathData* path_data) { | |
| 145 // Save the computed path in our cache. | |
| 146 path_data->cache[key] = path; | |
| 147 } | |
| 144 | 148 |
| 145 | 149 // Tries to find |key| in the cache. |path_data| should be locked by the caller! |
| 146 // static | 150 bool GetFromCache(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 GetFromOverrides(int key, PathData* path_data, FilePath* result) { |
|
jar (doing other things)
2012/09/17 17:06:08
A good readability pattern is to preface helper fu
pastarmovj
2012/09/18 14:27:13
Done.
| |
| 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 AddToCache(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 |
| 192 // special case the current directory because it can never be cached | 185 // special case the current directory because it can never be cached |
| 193 if (key == base::DIR_CURRENT) | 186 if (key == base::DIR_CURRENT) |
| 194 return file_util::GetCurrentDirectory(result); | 187 return file_util::GetCurrentDirectory(result); |
| 195 | 188 |
| 196 if (GetFromCache(key, result)) | 189 { |
| 197 return true; | 190 base::AutoLock scoped_lock(path_data->lock); |
| 191 if (GetFromCache(key, path_data, result)) | |
| 192 return true; | |
| 198 | 193 |
| 199 if (GetFromOverrides(key, result)) | 194 if (GetFromOverrides(key, path_data, result)) |
| 200 return true; | 195 return true; |
| 196 } | |
| 201 | 197 |
| 202 FilePath path; | 198 FilePath path; |
| 203 | 199 |
| 204 // search providers for the requested path | 200 // search providers for the requested path |
| 205 // NOTE: it should be safe to iterate here without the lock | 201 // NOTE: it should be safe to iterate here without the lock |
| 206 // since RegisterProvider always prepends. | 202 // since RegisterProvider always prepends. |
| 207 Provider* provider = path_data->providers; | 203 Provider* provider = path_data->providers; |
| 208 while (provider) { | 204 while (provider) { |
| 209 if (provider->func(key, &path)) | 205 if (provider->func(key, &path)) |
| 210 break; | 206 break; |
| 211 DCHECK(path.empty()) << "provider should not have modified path"; | 207 DCHECK(path.empty()) << "provider should not have modified path"; |
| 212 provider = provider->next; | 208 provider = provider->next; |
| 213 } | 209 } |
| 214 | 210 |
| 215 if (path.empty()) | 211 if (path.empty()) |
| 216 return false; | 212 return false; |
| 217 | 213 |
| 218 AddToCache(key, path); | 214 { |
| 215 base::AutoLock scoped_lock(path_data->lock); | |
| 216 AddToCache(key, path, path_data); | |
| 217 } | |
| 219 | 218 |
| 220 *result = path; | 219 *result = path; |
| 221 return true; | 220 return true; |
| 222 } | 221 } |
| 223 | 222 |
| 223 // static | |
| 224 bool PathService::Override(int key, const FilePath& path) { | 224 bool PathService::Override(int key, const FilePath& path) { |
| 225 // Just call the full function with true for the value of |create|. | 225 // Just call the full function with true for the value of |create|. |
| 226 return OverrideAndCreateIfNeeded(key, path, true); | 226 return OverrideAndCreateIfNeeded(key, path, true); |
| 227 } | 227 } |
| 228 | 228 |
| 229 // static | |
| 229 bool PathService::OverrideAndCreateIfNeeded(int key, | 230 bool PathService::OverrideAndCreateIfNeeded(int key, |
| 230 const FilePath& path, | 231 const FilePath& path, |
| 231 bool create) { | 232 bool create) { |
| 232 PathData* path_data = GetPathData(); | 233 PathData* path_data = GetPathData(); |
| 233 DCHECK(path_data); | 234 DCHECK(path_data); |
| 234 DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key"; | 235 DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key"; |
| 235 | 236 |
| 236 FilePath file_path = path; | 237 FilePath file_path = path; |
| 237 | 238 |
| 238 // For some locations this will fail if called from inside the sandbox there- | 239 // For some locations this will fail if called from inside the sandbox there- |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 251 // relative path. | 252 // relative path. |
| 252 if (!file_util::AbsolutePath(&file_path)) | 253 if (!file_util::AbsolutePath(&file_path)) |
| 253 return false; | 254 return false; |
| 254 | 255 |
| 255 base::AutoLock scoped_lock(path_data->lock); | 256 base::AutoLock scoped_lock(path_data->lock); |
| 256 | 257 |
| 257 // Clear the cache now. Some of its entries could have depended | 258 // 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. | 259 // on the value we are overriding, and are now out of sync with reality. |
| 259 path_data->cache.clear(); | 260 path_data->cache.clear(); |
| 260 | 261 |
| 261 path_data->cache[key] = file_path; | |
| 262 path_data->overrides[key] = file_path; | 262 path_data->overrides[key] = file_path; |
| 263 | 263 |
| 264 return true; | 264 return true; |
| 265 } | 265 } |
| 266 | 266 |
| 267 // static | |
| 268 bool PathService::RemoveOverride(int key) { | |
| 269 PathData* path_data = GetPathData(); | |
| 270 DCHECK(path_data); | |
| 271 | |
| 272 base::AutoLock scoped_lock(path_data->lock); | |
| 273 | |
| 274 if (path_data->overrides.find(key) == path_data->overrides.end()) | |
| 275 return false; | |
| 276 | |
| 277 // Clear the cache now. Some of its entries could have depended on the value | |
| 278 // we are going to remove, and are now out of sync. | |
| 279 path_data->cache.clear(); | |
| 280 | |
| 281 path_data->overrides.erase(key); | |
| 282 | |
| 283 return true; | |
| 284 } | |
| 285 | |
| 286 // static | |
| 267 void PathService::RegisterProvider(ProviderFunc func, int key_start, | 287 void PathService::RegisterProvider(ProviderFunc func, int key_start, |
| 268 int key_end) { | 288 int key_end) { |
| 269 PathData* path_data = GetPathData(); | 289 PathData* path_data = GetPathData(); |
| 270 DCHECK(path_data); | 290 DCHECK(path_data); |
| 271 DCHECK_GT(key_end, key_start); | 291 DCHECK_GT(key_end, key_start); |
| 272 | 292 |
| 273 base::AutoLock scoped_lock(path_data->lock); | |
| 274 | |
| 275 Provider* p; | 293 Provider* p; |
| 276 | 294 |
| 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; | 295 p = new Provider; |
| 287 p->is_static = false; | 296 p->is_static = false; |
| 288 p->func = func; | 297 p->func = func; |
| 289 p->next = path_data->providers; | |
| 290 #ifndef NDEBUG | 298 #ifndef NDEBUG |
| 291 p->key_start = key_start; | 299 p->key_start = key_start; |
| 292 p->key_end = key_end; | 300 p->key_end = key_end; |
| 293 #endif | 301 #endif |
| 302 | |
| 303 base::AutoLock scoped_lock(path_data->lock); | |
| 304 | |
| 305 #ifndef NDEBUG | |
| 306 Provider *iter = path_data->providers; | |
| 307 while (iter) { | |
| 308 DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) << | |
| 309 "path provider collision"; | |
| 310 iter = iter->next; | |
| 311 } | |
| 312 #endif | |
| 313 | |
| 314 p->next = path_data->providers; | |
| 294 path_data->providers = p; | 315 path_data->providers = p; |
| 295 } | 316 } |
| OLD | NEW |