1 /*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28 #include "PluginDatabase.h"
29
30 #include "Frame.h"
31 #include "KURL.h"
32 #include "PluginPackage.h"
33 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
34 #include "FileSystem.h"
35 #endif
36 #include <stdlib.h>
37 #include <wtf/text/CString.h>
38
39 #if PLATFORM(ANDROID)
40 #include "JavaSharedClient.h"
41 #include "PluginClient.h"
42 #endif
43
44 namespace WebCore {
45
46 typedef HashMap<String, RefPtr<PluginPackage> > PluginPackageByNameMap;
47
48 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
49 static const size_t maximumPersistentPluginMetadataCacheSize = 32768;
50
51 static bool gPersistentPluginMetadataCacheIsEnabled;
52
persistentPluginMetadataCachePath()53 String& persistentPluginMetadataCachePath()
54 {
55 DEFINE_STATIC_LOCAL(String, cachePath, ());
56 return cachePath;
57 }
58 #endif
59
PluginDatabase()60 PluginDatabase::PluginDatabase()
61 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
62 : m_persistentMetadataCacheIsLoaded(false)
63 #endif
64 {
65 }
66
installedPlugins(bool populate)67 PluginDatabase* PluginDatabase::installedPlugins(bool populate)
68 {
69 static PluginDatabase* plugins = 0;
70
71 if (!plugins) {
72 plugins = new PluginDatabase;
73
74 if (populate) {
75 plugins->setPluginDirectories(PluginDatabase::defaultPluginDirectories());
76 plugins->refresh();
77 }
78 }
79
80 return plugins;
81 }
82
isMIMETypeRegistered(const String & mimeType)83 bool PluginDatabase::isMIMETypeRegistered(const String& mimeType)
84 {
85 if (mimeType.isNull())
86 return false;
87 if (m_registeredMIMETypes.contains(mimeType))
88 return true;
89 // No plugin was found, try refreshing the database and searching again
90 return (refresh() && m_registeredMIMETypes.contains(mimeType));
91 }
92
addExtraPluginDirectory(const String & directory)93 void PluginDatabase::addExtraPluginDirectory(const String& directory)
94 {
95 m_pluginDirectories.append(directory);
96 refresh();
97 }
98
refresh()99 bool PluginDatabase::refresh()
100 {
101 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
102 if (!m_persistentMetadataCacheIsLoaded)
103 loadPersistentMetadataCache();
104 #endif
105 bool pluginSetChanged = false;
106
107 if (!m_plugins.isEmpty()) {
108 PluginSet pluginsToUnload;
109 getDeletedPlugins(pluginsToUnload);
110
111 // Unload plugins
112 PluginSet::const_iterator end = pluginsToUnload.end();
113 for (PluginSet::const_iterator it = pluginsToUnload.begin(); it != end; ++it)
114 remove(it->get());
115
116 pluginSetChanged = !pluginsToUnload.isEmpty();
117 }
118
119 HashSet<String> paths;
120 getPluginPathsInDirectories(paths);
121
122 HashMap<String, time_t> pathsWithTimes;
123
124 // We should only skip unchanged files if we didn't remove any plugins above. If we did remove
125 // any plugins, we need to look at every plugin file so that, e.g., if the user has two versions
126 // of RealPlayer installed and just removed the newer one, we'll pick up the older one.
127 bool shouldSkipUnchangedFiles = !pluginSetChanged;
128
129 HashSet<String>::const_iterator pathsEnd = paths.end();
130 for (HashSet<String>::const_iterator it = paths.begin(); it != pathsEnd; ++it) {
131 time_t lastModified;
132 if (!getFileModificationTime(*it, lastModified))
133 continue;
134
135 pathsWithTimes.add(*it, lastModified);
136
137 // If the path's timestamp hasn't changed since the last time we ran refresh(), we don't have to do anything.
138 if (shouldSkipUnchangedFiles && m_pluginPathsWithTimes.get(*it) == lastModified)
139 continue;
140
141 if (RefPtr<PluginPackage> oldPackage = m_pluginsByPath.get(*it)) {
142 ASSERT(!shouldSkipUnchangedFiles || oldPackage->lastModified() != lastModified);
143 remove(oldPackage.get());
144 }
145
146 RefPtr<PluginPackage> package = PluginPackage::createPackage(*it, lastModified);
147 if (package && add(package.release()))
148 pluginSetChanged = true;
149 }
150
151 // Cache all the paths we found with their timestamps for next time.
152 pathsWithTimes.swap(m_pluginPathsWithTimes);
153
154 if (!pluginSetChanged)
155 return false;
156
157 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
158 updatePersistentMetadataCache();
159 #endif
160
161 m_registeredMIMETypes.clear();
162
163 // Register plug-in MIME types
164 PluginSet::const_iterator end = m_plugins.end();
165 for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
166 // Get MIME types
167 MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin();
168 MIMEToDescriptionsMap::const_iterator map_end = (*it)->mimeToDescriptions().end();
169 for (; map_it != map_end; ++map_it)
170 m_registeredMIMETypes.add(map_it->first);
171 }
172
173 return true;
174 }
175
plugins() const176 Vector<PluginPackage*> PluginDatabase::plugins() const
177 {
178 Vector<PluginPackage*> result;
179
180 PluginSet::const_iterator end = m_plugins.end();
181 for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it)
182 result.append((*it).get());
183
184 return result;
185 }
186
preferredPluginCompare(const void * a,const void * b)187 int PluginDatabase::preferredPluginCompare(const void* a, const void* b)
188 {
189 PluginPackage* pluginA = *static_cast<PluginPackage* const*>(a);
190 PluginPackage* pluginB = *static_cast<PluginPackage* const*>(b);
191
192 return pluginA->compare(*pluginB);
193 }
194
pluginForMIMEType(const String & mimeType)195 PluginPackage* PluginDatabase::pluginForMIMEType(const String& mimeType)
196 {
197 if (mimeType.isEmpty())
198 return 0;
199
200 String key = mimeType.lower();
201 PluginSet::const_iterator end = m_plugins.end();
202 PluginPackage* preferredPlugin = m_preferredPlugins.get(key).get();
203 if (preferredPlugin
204 && preferredPlugin->isEnabled()
205 && preferredPlugin->mimeToDescriptions().contains(key)) {
206 return preferredPlugin;
207 }
208
209 Vector<PluginPackage*, 2> pluginChoices;
210
211 for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
212 PluginPackage* plugin = (*it).get();
213
214 if (!plugin->isEnabled())
215 continue;
216
217 if (plugin->mimeToDescriptions().contains(key)) {
218 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
219 if (!plugin->ensurePluginLoaded())
220 continue;
221 #endif
222 pluginChoices.append(plugin);
223 }
224 }
225
226 if (pluginChoices.isEmpty())
227 return 0;
228
229 qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare);
230
231 return pluginChoices[0];
232 }
233
MIMETypeForExtension(const String & extension) const234 String PluginDatabase::MIMETypeForExtension(const String& extension) const
235 {
236 if (extension.isEmpty())
237 return String();
238
239 PluginSet::const_iterator end = m_plugins.end();
240 String mimeType;
241 Vector<PluginPackage*, 2> pluginChoices;
242 HashMap<PluginPackage*, String> mimeTypeForPlugin;
243
244 for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
245 if (!(*it)->isEnabled())
246 continue;
247
248 MIMEToExtensionsMap::const_iterator mime_end = (*it)->mimeToExtensions().end();
249
250 for (MIMEToExtensionsMap::const_iterator mime_it = (*it)->mimeToExtensions().begin(); mime_it != mime_end; ++mime_it) {
251 mimeType = mime_it->first;
252 PluginPackage* preferredPlugin = m_preferredPlugins.get(mimeType).get();
253 const Vector<String>& extensions = mime_it->second;
254 bool foundMapping = false;
255 for (unsigned i = 0; i < extensions.size(); i++) {
256 if (equalIgnoringCase(extensions[i], extension)) {
257 PluginPackage* plugin = (*it).get();
258
259 if (preferredPlugin && PluginPackage::equal(*plugin, *preferredPlugin))
260 return mimeType;
261
262 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
263 if (!plugin->ensurePluginLoaded())
264 continue;
265 #endif
266 pluginChoices.append(plugin);
267 mimeTypeForPlugin.add(plugin, mimeType);
268 foundMapping = true;
269 break;
270 }
271 }
272 if (foundMapping)
273 break;
274 }
275 }
276
277 if (pluginChoices.isEmpty())
278 return String();
279
280 qsort(pluginChoices.data(), pluginChoices.size(), sizeof(PluginPackage*), PluginDatabase::preferredPluginCompare);
281
282 return mimeTypeForPlugin.get(pluginChoices[0]);
283 }
284
findPlugin(const KURL & url,String & mimeType)285 PluginPackage* PluginDatabase::findPlugin(const KURL& url, String& mimeType)
286 {
287 if (!mimeType.isEmpty())
288 return pluginForMIMEType(mimeType);
289
290 String filename = url.lastPathComponent();
291 if (filename.endsWith("/"))
292 return 0;
293
294 int extensionPos = filename.reverseFind('.');
295 if (extensionPos == -1)
296 return 0;
297
298 String mimeTypeForExtension = MIMETypeForExtension(filename.substring(extensionPos + 1));
299 PluginPackage* plugin = pluginForMIMEType(mimeTypeForExtension);
300 if (!plugin) {
301 // FIXME: if no plugin could be found, query Windows for the mime type
302 // corresponding to the extension.
303 return 0;
304 }
305
306 mimeType = mimeTypeForExtension;
307 return plugin;
308 }
309
setPreferredPluginForMIMEType(const String & mimeType,PluginPackage * plugin)310 void PluginDatabase::setPreferredPluginForMIMEType(const String& mimeType, PluginPackage* plugin)
311 {
312 if (!plugin || plugin->mimeToExtensions().contains(mimeType))
313 m_preferredPlugins.set(mimeType.lower(), plugin);
314 }
315
getDeletedPlugins(PluginSet & plugins) const316 void PluginDatabase::getDeletedPlugins(PluginSet& plugins) const
317 {
318 PluginSet::const_iterator end = m_plugins.end();
319 for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
320 if (!fileExists((*it)->path()))
321 plugins.add(*it);
322 }
323 }
324
add(PassRefPtr<PluginPackage> prpPackage)325 bool PluginDatabase::add(PassRefPtr<PluginPackage> prpPackage)
326 {
327 ASSERT_ARG(prpPackage, prpPackage);
328
329 RefPtr<PluginPackage> package = prpPackage;
330
331 if (!m_plugins.add(package).second)
332 return false;
333
334 m_pluginsByPath.add(package->path(), package);
335 return true;
336 }
337
remove(PluginPackage * package)338 void PluginDatabase::remove(PluginPackage* package)
339 {
340 MIMEToExtensionsMap::const_iterator it = package->mimeToExtensions().begin();
341 MIMEToExtensionsMap::const_iterator end = package->mimeToExtensions().end();
342 for ( ; it != end; ++it) {
343 PluginPackageByNameMap::iterator packageInMap = m_preferredPlugins.find(it->first);
344 if (packageInMap != m_preferredPlugins.end() && packageInMap->second == package)
345 m_preferredPlugins.remove(packageInMap);
346 }
347
348 m_plugins.remove(package);
349 m_pluginsByPath.remove(package->path());
350 }
351
clear()352 void PluginDatabase::clear()
353 {
354 m_plugins.clear();
355 m_pluginsByPath.clear();
356 m_pluginPathsWithTimes.clear();
357 m_registeredMIMETypes.clear();
358 m_preferredPlugins.clear();
359 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
360 m_persistentMetadataCacheIsLoaded = false;
361 #endif
362 }
363
364 #if (!OS(WINCE)) && (!OS(SYMBIAN)) && (!OS(WINDOWS) || !ENABLE(NETSCAPE_PLUGIN_API))
365 // For Safari/Win the following three methods are implemented
366 // in PluginDatabaseWin.cpp, but if we can use WebCore constructs
367 // for the logic we should perhaps move it here under XP_WIN?
368
defaultPluginDirectories()369 Vector<String> PluginDatabase::defaultPluginDirectories()
370 {
371 Vector<String> paths;
372
373 // Add paths specific to each platform
374 #if defined(XP_UNIX)
375 String userPluginPath = homeDirectoryPath();
376 userPluginPath.append(String("/.mozilla/plugins"));
377 paths.append(userPluginPath);
378
379 userPluginPath = homeDirectoryPath();
380 userPluginPath.append(String("/.netscape/plugins"));
381 paths.append(userPluginPath);
382
383 paths.append("/usr/lib/browser/plugins");
384 paths.append("/usr/local/lib/mozilla/plugins");
385 paths.append("/usr/lib/firefox/plugins");
386 paths.append("/usr/lib64/browser-plugins");
387 paths.append("/usr/lib/browser-plugins");
388 paths.append("/usr/lib/mozilla/plugins");
389 paths.append("/usr/local/netscape/plugins");
390 paths.append("/opt/mozilla/plugins");
391 paths.append("/opt/mozilla/lib/plugins");
392 paths.append("/opt/netscape/plugins");
393 paths.append("/opt/netscape/communicator/plugins");
394 paths.append("/usr/lib/netscape/plugins");
395 paths.append("/usr/lib/netscape/plugins-libc5");
396 paths.append("/usr/lib/netscape/plugins-libc6");
397 paths.append("/usr/lib64/netscape/plugins");
398 paths.append("/usr/lib64/mozilla/plugins");
399 paths.append("/usr/lib/nsbrowser/plugins");
400 paths.append("/usr/lib64/nsbrowser/plugins");
401
402 String mozHome(getenv("MOZILLA_HOME"));
403 mozHome.append("/plugins");
404 paths.append(mozHome);
405
406 Vector<String> mozPaths;
407 String mozPath(getenv("MOZ_PLUGIN_PATH"));
408 mozPath.split(UChar(':'), /* allowEmptyEntries */ false, mozPaths);
409 paths.append(mozPaths);
410 #elif defined(XP_MACOSX)
411 String userPluginPath = homeDirectoryPath();
412 userPluginPath.append(String("/Library/Internet Plug-Ins"));
413 paths.append(userPluginPath);
414 paths.append("/Library/Internet Plug-Ins");
415 #elif defined(XP_WIN)
416 String userPluginPath = homeDirectoryPath();
417 userPluginPath.append(String("\\Application Data\\Mozilla\\plugins"));
418 paths.append(userPluginPath);
419 #endif
420
421 // Add paths specific to each port
422 #if PLATFORM(QT)
423 Vector<String> qtPaths;
424 String qtPath(qgetenv("QTWEBKIT_PLUGIN_PATH").constData());
425 qtPath.split(UChar(':'), /* allowEmptyEntries */ false, qtPaths);
426 paths.append(qtPaths);
427 #endif
428
429 #if PLATFORM(ANDROID)
430 if (android::JavaSharedClient::GetPluginClient())
431 return android::JavaSharedClient::GetPluginClient()->getPluginDirectories();
432 #endif
433
434 return paths;
435 }
436
isPreferredPluginDirectory(const String & path)437 bool PluginDatabase::isPreferredPluginDirectory(const String& path)
438 {
439 String preferredPath = homeDirectoryPath();
440
441 #if defined(XP_UNIX)
442 preferredPath.append(String("/.mozilla/plugins"));
443 #elif defined(XP_MACOSX)
444 preferredPath.append(String("/Library/Internet Plug-Ins"));
445 #elif defined(XP_WIN)
446 preferredPath.append(String("\\Application Data\\Mozilla\\plugins"));
447 #endif
448
449 // TODO: We should normalize the path before doing a comparison.
450 return path == preferredPath;
451 }
452
getPluginPathsInDirectories(HashSet<String> & paths) const453 void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const
454 {
455 // FIXME: This should be a case insensitive set.
456 HashSet<String> uniqueFilenames;
457
458 #if defined(XP_UNIX) || defined(ANDROID)
459 String fileNameFilter("*.so");
460 #else
461 String fileNameFilter("");
462 #endif
463
464 Vector<String>::const_iterator dirsEnd = m_pluginDirectories.end();
465 for (Vector<String>::const_iterator dIt = m_pluginDirectories.begin(); dIt != dirsEnd; ++dIt) {
466 Vector<String> pluginPaths = listDirectory(*dIt, fileNameFilter);
467 Vector<String>::const_iterator pluginsEnd = pluginPaths.end();
468 for (Vector<String>::const_iterator pIt = pluginPaths.begin(); pIt != pluginsEnd; ++pIt) {
469 if (!fileExists(*pIt))
470 continue;
471
472 paths.add(*pIt);
473 }
474 }
475 }
476
477 #endif // !OS(SYMBIAN) && !OS(WINDOWS)
478
479 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
480
fillBufferWithContentsOfFile(PlatformFileHandle file,Vector<char> & buffer)481 static void fillBufferWithContentsOfFile(PlatformFileHandle file, Vector<char>& buffer)
482 {
483 size_t bufferSize = 0;
484 size_t bufferCapacity = 1024;
485 buffer.resize(bufferCapacity);
486
487 do {
488 bufferSize += readFromFile(file, buffer.data() + bufferSize, bufferCapacity - bufferSize);
489 if (bufferSize == bufferCapacity) {
490 if (bufferCapacity < maximumPersistentPluginMetadataCacheSize) {
491 bufferCapacity *= 2;
492 buffer.resize(bufferCapacity);
493 } else {
494 buffer.clear();
495 return;
496 }
497 } else
498 break;
499 } while (true);
500
501 buffer.shrink(bufferSize);
502 }
503
readUTF8String(String & resultString,char * & start,const char * end)504 static bool readUTF8String(String& resultString, char*& start, const char* end)
505 {
506 if (start >= end)
507 return false;
508
509 int len = strlen(start);
510 resultString = String::fromUTF8(start, len);
511 start += len + 1;
512
513 return true;
514 }
515
readTime(time_t & resultTime,char * & start,const char * end)516 static bool readTime(time_t& resultTime, char*& start, const char* end)
517 {
518 if (start + sizeof(time_t) >= end)
519 return false;
520
521 resultTime = *reinterpret_cast_ptr<time_t*>(start);
522 start += sizeof(time_t);
523
524 return true;
525 }
526
527 static const char schemaVersion = '1';
528 static const char persistentPluginMetadataCacheFilename[] = "PluginMetadataCache.bin";
529
loadPersistentMetadataCache()530 void PluginDatabase::loadPersistentMetadataCache()
531 {
532 if (!isPersistentMetadataCacheEnabled() || persistentMetadataCachePath().isEmpty())
533 return;
534
535 PlatformFileHandle file;
536 String absoluteCachePath = pathByAppendingComponent(persistentMetadataCachePath(), persistentPluginMetadataCacheFilename);
537 file = openFile(absoluteCachePath, OpenForRead);
538
539 if (!isHandleValid(file))
540 return;
541
542 // Mark cache as loaded regardless of success or failure. If
543 // there's error in the cache, we won't try to load it anymore.
544 m_persistentMetadataCacheIsLoaded = true;
545
546 Vector<char> fileContents;
547 fillBufferWithContentsOfFile(file, fileContents);
548 closeFile(file);
549
550 if (fileContents.size() < 2 || fileContents.first() != schemaVersion || fileContents.last() != '\0') {
551 LOG_ERROR("Unable to read plugin metadata cache: corrupt schema");
552 deleteFile(absoluteCachePath);
553 return;
554 }
555
556 char* bufferPos = fileContents.data() + 1;
557 char* end = fileContents.data() + fileContents.size();
558
559 PluginSet cachedPlugins;
560 HashMap<String, time_t> cachedPluginPathsWithTimes;
561 HashMap<String, RefPtr<PluginPackage> > cachedPluginsByPath;
562
563 while (bufferPos < end) {
564 String path;
565 time_t lastModified;
566 String name;
567 String desc;
568 String mimeDesc;
569 if (!(readUTF8String(path, bufferPos, end)
570 && readTime(lastModified, bufferPos, end)
571 && readUTF8String(name, bufferPos, end)
572 && readUTF8String(desc, bufferPos, end)
573 && readUTF8String(mimeDesc, bufferPos, end))) {
574 LOG_ERROR("Unable to read plugin metadata cache: corrupt data");
575 deleteFile(absoluteCachePath);
576 return;
577 }
578
579 // Skip metadata that points to plugins from directories that
580 // are not part of plugin directory list anymore.
581 String pluginDirectoryName = directoryName(path);
582 if (m_pluginDirectories.find(pluginDirectoryName) == WTF::notFound)
583 continue;
584
585 RefPtr<PluginPackage> package = PluginPackage::createPackageFromCache(path, lastModified, name, desc, mimeDesc);
586
587 if (package && cachedPlugins.add(package).second) {
588 cachedPluginPathsWithTimes.add(package->path(), package->lastModified());
589 cachedPluginsByPath.add(package->path(), package);
590 }
591 }
592
593 m_plugins.swap(cachedPlugins);
594 m_pluginsByPath.swap(cachedPluginsByPath);
595 m_pluginPathsWithTimes.swap(cachedPluginPathsWithTimes);
596 }
597
writeUTF8String(PlatformFileHandle file,const String & string)598 static bool writeUTF8String(PlatformFileHandle file, const String& string)
599 {
600 CString utf8String = string.utf8();
601 int length = utf8String.length() + 1;
602 return writeToFile(file, utf8String.data(), length) == length;
603 }
604
writeTime(PlatformFileHandle file,const time_t & time)605 static bool writeTime(PlatformFileHandle file, const time_t& time)
606 {
607 return writeToFile(file, reinterpret_cast<const char*>(&time), sizeof(time_t)) == sizeof(time_t);
608 }
609
updatePersistentMetadataCache()610 void PluginDatabase::updatePersistentMetadataCache()
611 {
612 if (!isPersistentMetadataCacheEnabled() || persistentMetadataCachePath().isEmpty())
613 return;
614
615 makeAllDirectories(persistentMetadataCachePath());
616 String absoluteCachePath = pathByAppendingComponent(persistentMetadataCachePath(), persistentPluginMetadataCacheFilename);
617 deleteFile(absoluteCachePath);
618
619 if (m_plugins.isEmpty())
620 return;
621
622 PlatformFileHandle file;
623 file = openFile(absoluteCachePath, OpenForWrite);
624
625 if (!isHandleValid(file)) {
626 LOG_ERROR("Unable to open plugin metadata cache for saving");
627 return;
628 }
629
630 char localSchemaVersion = schemaVersion;
631 if (writeToFile(file, &localSchemaVersion, 1) != 1) {
632 LOG_ERROR("Unable to write plugin metadata cache schema");
633 closeFile(file);
634 deleteFile(absoluteCachePath);
635 return;
636 }
637
638 PluginSet::const_iterator end = m_plugins.end();
639 for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
640 if (!(writeUTF8String(file, (*it)->path())
641 && writeTime(file, (*it)->lastModified())
642 && writeUTF8String(file, (*it)->name())
643 && writeUTF8String(file, (*it)->description())
644 && writeUTF8String(file, (*it)->fullMIMEDescription()))) {
645 LOG_ERROR("Unable to write plugin metadata to cache");
646 closeFile(file);
647 deleteFile(absoluteCachePath);
648 return;
649 }
650 }
651
652 closeFile(file);
653 }
654
isPersistentMetadataCacheEnabled()655 bool PluginDatabase::isPersistentMetadataCacheEnabled()
656 {
657 return gPersistentPluginMetadataCacheIsEnabled;
658 }
659
setPersistentMetadataCacheEnabled(bool isEnabled)660 void PluginDatabase::setPersistentMetadataCacheEnabled(bool isEnabled)
661 {
662 gPersistentPluginMetadataCacheIsEnabled = isEnabled;
663 }
664
persistentMetadataCachePath()665 String PluginDatabase::persistentMetadataCachePath()
666 {
667 return WebCore::persistentPluginMetadataCachePath();
668 }
669
setPersistentMetadataCachePath(const String & persistentMetadataCachePath)670 void PluginDatabase::setPersistentMetadataCachePath(const String& persistentMetadataCachePath)
671 {
672 WebCore::persistentPluginMetadataCachePath() = persistentMetadataCachePath;
673 }
674 #endif
675 }
676