// We keep a linked list of providers. In a debug build we ensure that no two // providers claim overlapping keys. struct Provider {
PathService::ProviderFunc func; // This field is not a raw_ptr<> because it was filtered by the rewriter for: // #reinterpret-cast-trivial-type, #global-scope
RAW_PTR_EXCLUSION struct Provider* next; #ifndef NDEBUG int key_start; int key_end; #endif bool is_static;
};
// Tries to find |key| in the cache. bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result)
EXCLUSIVE_LOCKS_REQUIRED(path_data->lock) { if (path_data->cache_disabled) returnfalse; // check for a cached version auto it = path_data->cache.find(key); if (it != path_data->cache.end()) {
*result = it->second; return true;
} returnfalse;
}
// Tries to find |key| in the overrides map. bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result)
EXCLUSIVE_LOCKS_REQUIRED(path_data->lock) { // check for an overridden version.
PathMap::const_iterator it = path_data->overrides.find(key); if (it != path_data->overrides.end()) { if (!path_data->cache_disabled)
path_data->cache[key] = it->second;
*result = it->second; return true;
} returnfalse;
}
} // namespace
// TODO(brettw): this function does not handle long paths (filename > MAX_PATH) // characters). This isn't supported very well by Windows right now, so it is // moot, but we should keep this in mind for the future. // static bool PathService::Get(int key, FilePath* result) {
PathData* path_data = GetPathData();
DCHECK(path_data);
DCHECK(result);
DCHECK_GT(key, PATH_START);
// Special case the current directory because it can never be cached. if (key == DIR_CURRENT) return GetCurrentDirectory(result);
if (LockedGetFromOverrides(key, path_data, result)) return true;
// Get the beginning of the list while it is still locked.
provider = path_data->providers;
}
FilePath path;
// Iterating does not need the lock because only the list head might be // modified on another thread. while (provider) { if (provider->func(key, &path)) break;
DCHECK(path.empty()) << "provider should not have modified path";
provider = provider->next;
}
if (path.empty()) returnfalse;
if (path.ReferencesParent()) { // Make sure path service never returns a path with ".." in it.
path = MakeAbsoluteFilePath(path); if (path.empty()) returnfalse;
}
*result = path;
AutoLock scoped_lock(path_data->lock); if (!path_data->cache_disabled)
path_data->cache[key] = path;
return true;
}
FilePath PathService::CheckedGet(int key) {
FilePath path;
LOG_IF(FATAL, !Get(key, &path)) << "Failed to get the path for " << key; return path;
}
// static bool PathService::Override(int key, const FilePath& path) { // Just call the full function with true for the value of |create|, and // assume that |path| may not be absolute yet. return OverrideAndCreateIfNeeded(key, path, false, true);
}
// Create the directory if requested by the caller. Do this before resolving // `file_path` to an absolute path because on POSIX, MakeAbsoluteFilePath // requires that the path exists. if (create && !CreateDirectory(file_path)) { returnfalse;
}
// We need to have an absolute path. if (!is_absolute) {
file_path = MakeAbsoluteFilePath(file_path); if (file_path.empty()) returnfalse;
}
DCHECK(file_path.IsAbsolute());
AutoLock scoped_lock(path_data->lock);
// Clear the cache now. Some of its entries could have depended // on the value we are overriding, and are now out of sync with reality.
path_data->cache.clear();
if (path_data->overrides.find(key) == path_data->overrides.end()) returnfalse;
// Clear the cache now. Some of its entries could have depended on the value // we are going to remove, and are now out of sync.
path_data->cache.clear();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.