| /* |
| * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. |
| * Copyright (C) 2008 Collabora, Ltd. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "PluginDatabase.h" |
| |
| #include "Frame.h" |
| #include "KURL.h" |
| #include "PluginPackage.h" |
| #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) |
| #include "FileSystem.h" |
| #endif |
| #include <stdlib.h> |
| #include <wtf/text/CString.h> |
| |
| #if PLATFORM(ANDROID) |
| #include "JavaSharedClient.h" |
| #include "PluginClient.h" |
| #endif |
| |
| namespace WebCore { |
| |
| typedef HashMap<String, RefPtr<PluginPackage> > PluginPackageByNameMap; |
| |
| #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) |
| static const size_t maximumPersistentPluginMetadataCacheSize = 32768; |
| |
| static bool gPersistentPluginMetadataCacheIsEnabled; |
| |
| String& persistentPluginMetadataCachePath() |
| { |
| DEFINE_STATIC_LOCAL(String, cachePath, ()); |
| return cachePath; |
| } |
| #endif |
| |
| PluginDatabase::PluginDatabase() |
| #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) |
| : m_persistentMetadataCacheIsLoaded(false) |
| #endif |
| { |
| } |
| |
| PluginDatabase* PluginDatabase::installedPlugins(bool populate) |
| { |
| static PluginDatabase* plugins = 0; |
| |
| if (!plugins) { |
| plugins = new PluginDatabase; |
| |
| if (populate) { |
| plugins->setPluginDirectories(PluginDatabase::defaultPluginDirectories()); |
| plugins->refresh(); |
| } |
| } |
| |
| return plugins; |
| } |
| |
| bool PluginDatabase::isMIMETypeRegistered(const String& mimeType) |
| { |
| if (mimeType.isNull()) |
| return false; |
| if (m_registeredMIMETypes.contains(mimeType)) |
| return true; |
| // No plugin was found, try refreshing the database and searching again |
| return (refresh() && m_registeredMIMETypes.contains(mimeType)); |
| } |
| |
| void PluginDatabase::addExtraPluginDirectory(const String& directory) |
| { |
| m_pluginDirectories.append(directory); |
| refresh(); |
| } |
| |
| bool PluginDatabase::refresh() |
| { |
| #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) |
| if (!m_persistentMetadataCacheIsLoaded) |
| loadPersistentMetadataCache(); |
| #endif |
| bool pluginSetChanged = false; |
| |
| if (!m_plugins.isEmpty()) { |
| PluginSet pluginsToUnload; |
| getDeletedPlugins(pluginsToUnload); |
| |
| // Unload plugins |
| PluginSet::const_iterator end = pluginsToUnload.end(); |
| for (PluginSet::const_iterator it = pluginsToUnload.begin(); it != end; ++it) |
| remove(it->get()); |
| |
| pluginSetChanged = !pluginsToUnload.isEmpty(); |
| } |
| |
| HashSet<String> paths; |
| getPluginPathsInDirectories(paths); |
| |
| HashMap<String, time_t> pathsWithTimes; |
| |
| // We should only skip unchanged files if we didn't remove any plugins above. If we did remove |
| // any plugins, we need to look at every plugin file so that, e.g., if the user has two versions |
| // of RealPlayer installed and just removed the newer one, we'll pick up the older one. |
| bool shouldSkipUnchangedFiles = !pluginSetChanged; |
| |
| HashSet<String>::const_iterator pathsEnd = paths.end(); |
| for (HashSet<String>::const_iterator it = paths.begin(); it != pathsEnd; ++it) { |
| time_t lastModified; |
| if (!getFileModificationTime(*it, lastModified)) |
| continue; |
| |
| pathsWithTimes.add(*it, lastModified); |
| |
| // If the path's timestamp hasn't changed since the last time we ran refresh(), we don't have to do anything. |
| if (shouldSkipUnchangedFiles && m_pluginPathsWithTimes.get(*it) == lastModified) |
| continue; |
| |
| if (RefPtr<PluginPackage> oldPackage = m_pluginsByPath.get(*it)) { |
| ASSERT(!shouldSkipUnchangedFiles || oldPackage->lastModified() != lastModified); |
| remove(oldPackage.get()); |
| } |
| |
| RefPtr<PluginPackage> package = PluginPackage::createPackage(*it, lastModified); |
| if (package && add(package.release())) |
| pluginSetChanged = true; |
| } |
| |
| // Cache all the paths we found with their timestamps for next time. |
| pathsWithTimes.swap(m_pluginPathsWithTimes); |
| |
| if (!pluginSetChanged) |
| return false; |
| |
| #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) |
| updatePersistentMetadataCache(); |
| #endif |
| |
| m_registeredMIMETypes.clear(); |
| |
| // Register plug-in MIME types |
| PluginSet::const_iterator end = m_plugins.end(); |
| for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { |
| // Get MIME types |
| MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin(); |
| MIMEToDescriptionsMap::const_iterator map_end = (*it)->mimeToDescriptions().end(); |
| for (; map_it != map_end; ++map_it) |
| m_registeredMIMETypes.add(map_it->first); |
| } |
| |
| return true; |
| } |
| |
| Vector<PluginPackage*> PluginDatabase::plugins() const |
| { |
| Vector<PluginPackage*> result; |
| |
| PluginSet::const_iterator end = m_plugins.end(); |
| for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) |
| result.append((*it).get()); |
| |
| return result; |
| } |
| |
| int PluginDatabase::preferredPluginCompare(const void* a, const void* b) |
| { |
| PluginPackage* pluginA = *static_cast<PluginPackage* const*>(a); |
| PluginPackage* pluginB = *static_cast<PluginPackage* const*>(b); |
| |
| return pluginA->compare(*pluginB); |
| } |
| |
| PluginPackage* PluginDatabase::pluginForMIMEType(const String& mimeType) |
| { |
| if (mimeType.isEmpty()) |
| return 0; |
| |
| String key = mimeType.lower(); |
| PluginSet::const_iterator end = m_plugins.end(); |
| PluginPackage* preferredPlugin = m_preferredPlugins.get(key).get(); |
| if (preferredPlugin |
| && preferredPlugin->isEnabled() |
| && preferredPlugin->mimeToDescriptions().contains(key)) { |
| return preferredPlugin; |
| } |
| |
| Vector<PluginPackage*, 2> pluginChoices; |
| |
| for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { |
| PluginPackage* plugin = (*it).get(); |
| |
| if (!plugin->isEnabled()) |
| continue; |
| |
| if (plugin->mimeToDescriptions().contains(key)) { |
| #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) |
| if (!plugin->ensurePluginLoaded()) |
| continue; |
| #endif |
| pluginChoices.append(plugin); |
| } |
| } |
| |
| if (pluginChoices.isEmpty()) |
| return 0; |
| |
| qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare); |
| |
| return pluginChoices[0]; |
| } |
| |
| String PluginDatabase::MIMETypeForExtension(const String& extension) const |
| { |
| if (extension.isEmpty()) |
| return String(); |
| |
| PluginSet::const_iterator end = m_plugins.end(); |
| String mimeType; |
| Vector<PluginPackage*, 2> pluginChoices; |
| HashMap<PluginPackage*, String> mimeTypeForPlugin; |
| |
| for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { |
| if (!(*it)->isEnabled()) |
| continue; |
| |
| MIMEToExtensionsMap::const_iterator mime_end = (*it)->mimeToExtensions().end(); |
| |
| for (MIMEToExtensionsMap::const_iterator mime_it = (*it)->mimeToExtensions().begin(); mime_it != mime_end; ++mime_it) { |
| mimeType = mime_it->first; |
| PluginPackage* preferredPlugin = m_preferredPlugins.get(mimeType).get(); |
| const Vector<String>& extensions = mime_it->second; |
| bool foundMapping = false; |
| for (unsigned i = 0; i < extensions.size(); i++) { |
| if (equalIgnoringCase(extensions[i], extension)) { |
| PluginPackage* plugin = (*it).get(); |
| |
| if (preferredPlugin && PluginPackage::equal(*plugin, *preferredPlugin)) |
| return mimeType; |
| |
| #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) |
| if (!plugin->ensurePluginLoaded()) |
| continue; |
| #endif |
| pluginChoices.append(plugin); |
| mimeTypeForPlugin.add(plugin, mimeType); |
| foundMapping = true; |
| break; |
| } |
| } |
| if (foundMapping) |
| break; |
| } |
| } |
| |
| if (pluginChoices.isEmpty()) |
| return String(); |
| |
| qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare); |
| |
| return mimeTypeForPlugin.get(pluginChoices[0]); |
| } |
| |
| PluginPackage* PluginDatabase::findPlugin(const KURL& url, String& mimeType) |
| { |
| if (!mimeType.isEmpty()) |
| return pluginForMIMEType(mimeType); |
| |
| String filename = url.lastPathComponent(); |
| if (filename.endsWith("/")) |
| return 0; |
| |
| int extensionPos = filename.reverseFind('.'); |
| if (extensionPos == -1) |
| return 0; |
| |
| String mimeTypeForExtension = MIMETypeForExtension(filename.substring(extensionPos + 1)); |
| PluginPackage* plugin = pluginForMIMEType(mimeTypeForExtension); |
| if (!plugin) { |
| // FIXME: if no plugin could be found, query Windows for the mime type |
| // corresponding to the extension. |
| return 0; |
| } |
| |
| mimeType = mimeTypeForExtension; |
| return plugin; |
| } |
| |
| void PluginDatabase::setPreferredPluginForMIMEType(const String& mimeType, PluginPackage* plugin) |
| { |
| if (!plugin || plugin->mimeToExtensions().contains(mimeType)) |
| m_preferredPlugins.set(mimeType.lower(), plugin); |
| } |
| |
| void PluginDatabase::getDeletedPlugins(PluginSet& plugins) const |
| { |
| PluginSet::const_iterator end = m_plugins.end(); |
| for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { |
| if (!fileExists((*it)->path())) |
| plugins.add(*it); |
| } |
| } |
| |
| bool PluginDatabase::add(PassRefPtr<PluginPackage> prpPackage) |
| { |
| ASSERT_ARG(prpPackage, prpPackage); |
| |
| RefPtr<PluginPackage> package = prpPackage; |
| |
| if (!m_plugins.add(package).second) |
| return false; |
| |
| m_pluginsByPath.add(package->path(), package); |
| return true; |
| } |
| |
| void PluginDatabase::remove(PluginPackage* package) |
| { |
| MIMEToExtensionsMap::const_iterator it = package->mimeToExtensions().begin(); |
| MIMEToExtensionsMap::const_iterator end = package->mimeToExtensions().end(); |
| for ( ; it != end; ++it) { |
| PluginPackageByNameMap::iterator packageInMap = m_preferredPlugins.find(it->first); |
| if (packageInMap != m_preferredPlugins.end() && packageInMap->second == package) |
| m_preferredPlugins.remove(packageInMap); |
| } |
| |
| m_plugins.remove(package); |
| m_pluginsByPath.remove(package->path()); |
| } |
| |
| void PluginDatabase::clear() |
| { |
| m_plugins.clear(); |
| m_pluginsByPath.clear(); |
| m_pluginPathsWithTimes.clear(); |
| m_registeredMIMETypes.clear(); |
| m_preferredPlugins.clear(); |
| #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) |
| m_persistentMetadataCacheIsLoaded = false; |
| #endif |
| } |
| |
| #if (!OS(WINCE)) && (!OS(SYMBIAN)) && (!OS(WINDOWS) || !ENABLE(NETSCAPE_PLUGIN_API)) |
| // For Safari/Win the following three methods are implemented |
| // in PluginDatabaseWin.cpp, but if we can use WebCore constructs |
| // for the logic we should perhaps move it here under XP_WIN? |
| |
| Vector<String> PluginDatabase::defaultPluginDirectories() |
| { |
| Vector<String> paths; |
| |
| // Add paths specific to each platform |
| #if defined(XP_UNIX) |
| String userPluginPath = homeDirectoryPath(); |
| userPluginPath.append(String("/.mozilla/plugins")); |
| paths.append(userPluginPath); |
| |
| userPluginPath = homeDirectoryPath(); |
| userPluginPath.append(String("/.netscape/plugins")); |
| paths.append(userPluginPath); |
| |
| paths.append("/usr/lib/browser/plugins"); |
| paths.append("/usr/local/lib/mozilla/plugins"); |
| paths.append("/usr/lib/firefox/plugins"); |
| paths.append("/usr/lib64/browser-plugins"); |
| paths.append("/usr/lib/browser-plugins"); |
| paths.append("/usr/lib/mozilla/plugins"); |
| paths.append("/usr/local/netscape/plugins"); |
| paths.append("/opt/mozilla/plugins"); |
| paths.append("/opt/mozilla/lib/plugins"); |
| paths.append("/opt/netscape/plugins"); |
| paths.append("/opt/netscape/communicator/plugins"); |
| paths.append("/usr/lib/netscape/plugins"); |
| paths.append("/usr/lib/netscape/plugins-libc5"); |
| paths.append("/usr/lib/netscape/plugins-libc6"); |
| paths.append("/usr/lib64/netscape/plugins"); |
| paths.append("/usr/lib64/mozilla/plugins"); |
| paths.append("/usr/lib/nsbrowser/plugins"); |
| paths.append("/usr/lib64/nsbrowser/plugins"); |
| |
| String mozHome(getenv("MOZILLA_HOME")); |
| mozHome.append("/plugins"); |
| paths.append(mozHome); |
| |
| Vector<String> mozPaths; |
| String mozPath(getenv("MOZ_PLUGIN_PATH")); |
| mozPath.split(UChar(':'), /* allowEmptyEntries */ false, mozPaths); |
| paths.append(mozPaths); |
| #elif defined(XP_MACOSX) |
| String userPluginPath = homeDirectoryPath(); |
| userPluginPath.append(String("/Library/Internet Plug-Ins")); |
| paths.append(userPluginPath); |
| paths.append("/Library/Internet Plug-Ins"); |
| #elif defined(XP_WIN) |
| String userPluginPath = homeDirectoryPath(); |
| userPluginPath.append(String("\\Application Data\\Mozilla\\plugins")); |
| paths.append(userPluginPath); |
| #endif |
| |
| // Add paths specific to each port |
| #if PLATFORM(QT) |
| Vector<String> qtPaths; |
| String qtPath(qgetenv("QTWEBKIT_PLUGIN_PATH").constData()); |
| qtPath.split(UChar(':'), /* allowEmptyEntries */ false, qtPaths); |
| paths.append(qtPaths); |
| #endif |
| |
| #if PLATFORM(ANDROID) |
| if (android::JavaSharedClient::GetPluginClient()) |
| return android::JavaSharedClient::GetPluginClient()->getPluginDirectories(); |
| #endif |
| |
| return paths; |
| } |
| |
| bool PluginDatabase::isPreferredPluginDirectory(const String& path) |
| { |
| String preferredPath = homeDirectoryPath(); |
| |
| #if defined(XP_UNIX) |
| preferredPath.append(String("/.mozilla/plugins")); |
| #elif defined(XP_MACOSX) |
| preferredPath.append(String("/Library/Internet Plug-Ins")); |
| #elif defined(XP_WIN) |
| preferredPath.append(String("\\Application Data\\Mozilla\\plugins")); |
| #endif |
| |
| // TODO: We should normalize the path before doing a comparison. |
| return path == preferredPath; |
| } |
| |
| void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const |
| { |
| // FIXME: This should be a case insensitive set. |
| HashSet<String> uniqueFilenames; |
| |
| #if defined(XP_UNIX) || defined(ANDROID) |
| String fileNameFilter("*.so"); |
| #else |
| String fileNameFilter(""); |
| #endif |
| |
| Vector<String>::const_iterator dirsEnd = m_pluginDirectories.end(); |
| for (Vector<String>::const_iterator dIt = m_pluginDirectories.begin(); dIt != dirsEnd; ++dIt) { |
| Vector<String> pluginPaths = listDirectory(*dIt, fileNameFilter); |
| Vector<String>::const_iterator pluginsEnd = pluginPaths.end(); |
| for (Vector<String>::const_iterator pIt = pluginPaths.begin(); pIt != pluginsEnd; ++pIt) { |
| if (!fileExists(*pIt)) |
| continue; |
| |
| paths.add(*pIt); |
| } |
| } |
| } |
| |
| #endif // !OS(SYMBIAN) && !OS(WINDOWS) |
| |
| #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE) |
| |
| static void fillBufferWithContentsOfFile(PlatformFileHandle file, Vector<char>& buffer) |
| { |
| size_t bufferSize = 0; |
| size_t bufferCapacity = 1024; |
| buffer.resize(bufferCapacity); |
| |
| do { |
| bufferSize += readFromFile(file, buffer.data() + bufferSize, bufferCapacity - bufferSize); |
| if (bufferSize == bufferCapacity) { |
| if (bufferCapacity < maximumPersistentPluginMetadataCacheSize) { |
| bufferCapacity *= 2; |
| buffer.resize(bufferCapacity); |
| } else { |
| buffer.clear(); |
| return; |
| } |
| } else |
| break; |
| } while (true); |
| |
| buffer.shrink(bufferSize); |
| } |
| |
| static bool readUTF8String(String& resultString, char*& start, const char* end) |
| { |
| if (start >= end) |
| return false; |
| |
| int len = strlen(start); |
| resultString = String::fromUTF8(start, len); |
| start += len + 1; |
| |
| return true; |
| } |
| |
| static bool readTime(time_t& resultTime, char*& start, const char* end) |
| { |
| if (start + sizeof(time_t) >= end) |
| return false; |
| |
| resultTime = *reinterpret_cast_ptr<time_t*>(start); |
| start += sizeof(time_t); |
| |
| return true; |
| } |
| |
| static const char schemaVersion = '1'; |
| static const char persistentPluginMetadataCacheFilename[] = "PluginMetadataCache.bin"; |
| |
| void PluginDatabase::loadPersistentMetadataCache() |
| { |
| if (!isPersistentMetadataCacheEnabled() || persistentMetadataCachePath().isEmpty()) |
| return; |
| |
| PlatformFileHandle file; |
| String absoluteCachePath = pathByAppendingComponent(persistentMetadataCachePath(), persistentPluginMetadataCacheFilename); |
| file = openFile(absoluteCachePath, OpenForRead); |
| |
| if (!isHandleValid(file)) |
| return; |
| |
| // Mark cache as loaded regardless of success or failure. If |
| // there's error in the cache, we won't try to load it anymore. |
| m_persistentMetadataCacheIsLoaded = true; |
| |
| Vector<char> fileContents; |
| fillBufferWithContentsOfFile(file, fileContents); |
| closeFile(file); |
| |
| if (fileContents.size() < 2 || fileContents.first() != schemaVersion || fileContents.last() != '\0') { |
| LOG_ERROR("Unable to read plugin metadata cache: corrupt schema"); |
| deleteFile(absoluteCachePath); |
| return; |
| } |
| |
| char* bufferPos = fileContents.data() + 1; |
| char* end = fileContents.data() + fileContents.size(); |
| |
| PluginSet cachedPlugins; |
| HashMap<String, time_t> cachedPluginPathsWithTimes; |
| HashMap<String, RefPtr<PluginPackage> > cachedPluginsByPath; |
| |
| while (bufferPos < end) { |
| String path; |
| time_t lastModified; |
| String name; |
| String desc; |
| String mimeDesc; |
| if (!(readUTF8String(path, bufferPos, end) |
| && readTime(lastModified, bufferPos, end) |
| && readUTF8String(name, bufferPos, end) |
| && readUTF8String(desc, bufferPos, end) |
| && readUTF8String(mimeDesc, bufferPos, end))) { |
| LOG_ERROR("Unable to read plugin metadata cache: corrupt data"); |
| deleteFile(absoluteCachePath); |
| return; |
| } |
| |
| // Skip metadata that points to plugins from directories that |
| // are not part of plugin directory list anymore. |
| String pluginDirectoryName = directoryName(path); |
| if (m_pluginDirectories.find(pluginDirectoryName) == WTF::notFound) |
| continue; |
| |
| RefPtr<PluginPackage> package = PluginPackage::createPackageFromCache(path, lastModified, name, desc, mimeDesc); |
| |
| if (package && cachedPlugins.add(package).second) { |
| cachedPluginPathsWithTimes.add(package->path(), package->lastModified()); |
| cachedPluginsByPath.add(package->path(), package); |
| } |
| } |
| |
| m_plugins.swap(cachedPlugins); |
| m_pluginsByPath.swap(cachedPluginsByPath); |
| m_pluginPathsWithTimes.swap(cachedPluginPathsWithTimes); |
| } |
| |
| static bool writeUTF8String(PlatformFileHandle file, const String& string) |
| { |
| CString utf8String = string.utf8(); |
| int length = utf8String.length() + 1; |
| return writeToFile(file, utf8String.data(), length) == length; |
| } |
| |
| static bool writeTime(PlatformFileHandle file, const time_t& time) |
| { |
| return writeToFile(file, reinterpret_cast<const char*>(&time), sizeof(time_t)) == sizeof(time_t); |
| } |
| |
| void PluginDatabase::updatePersistentMetadataCache() |
| { |
| if (!isPersistentMetadataCacheEnabled() || persistentMetadataCachePath().isEmpty()) |
| return; |
| |
| makeAllDirectories(persistentMetadataCachePath()); |
| String absoluteCachePath = pathByAppendingComponent(persistentMetadataCachePath(), persistentPluginMetadataCacheFilename); |
| deleteFile(absoluteCachePath); |
| |
| if (m_plugins.isEmpty()) |
| return; |
| |
| PlatformFileHandle file; |
| file = openFile(absoluteCachePath, OpenForWrite); |
| |
| if (!isHandleValid(file)) { |
| LOG_ERROR("Unable to open plugin metadata cache for saving"); |
| return; |
| } |
| |
| char localSchemaVersion = schemaVersion; |
| if (writeToFile(file, &localSchemaVersion, 1) != 1) { |
| LOG_ERROR("Unable to write plugin metadata cache schema"); |
| closeFile(file); |
| deleteFile(absoluteCachePath); |
| return; |
| } |
| |
| PluginSet::const_iterator end = m_plugins.end(); |
| for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) { |
| if (!(writeUTF8String(file, (*it)->path()) |
| && writeTime(file, (*it)->lastModified()) |
| && writeUTF8String(file, (*it)->name()) |
| && writeUTF8String(file, (*it)->description()) |
| && writeUTF8String(file, (*it)->fullMIMEDescription()))) { |
| LOG_ERROR("Unable to write plugin metadata to cache"); |
| closeFile(file); |
| deleteFile(absoluteCachePath); |
| return; |
| } |
| } |
| |
| closeFile(file); |
| } |
| |
| bool PluginDatabase::isPersistentMetadataCacheEnabled() |
| { |
| return gPersistentPluginMetadataCacheIsEnabled; |
| } |
| |
| void PluginDatabase::setPersistentMetadataCacheEnabled(bool isEnabled) |
| { |
| gPersistentPluginMetadataCacheIsEnabled = isEnabled; |
| } |
| |
| String PluginDatabase::persistentMetadataCachePath() |
| { |
| return WebCore::persistentPluginMetadataCachePath(); |
| } |
| |
| void PluginDatabase::setPersistentMetadataCachePath(const String& persistentMetadataCachePath) |
| { |
| WebCore::persistentPluginMetadataCachePath() = persistentMetadataCachePath; |
| } |
| #endif |
| } |