QMimeDatabase: handle removal of a mime directory

The previous commit didn't handle correctly the case where an entire
mime directory is deleted. The unittest wasn't testing that case,
now it is. We need to move providers into a new list, and then
delete those left over (i.e. now unused).

Change-Id: I04fd8b39b511a2331d706864f695ce5074acf916
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
David Faure 2017-10-11 20:38:57 +02:00
parent 7a5644d648
commit 648840c617
2 changed files with 18 additions and 11 deletions

View File

@ -104,14 +104,15 @@ void QMimeDatabasePrivate::loadProviders()
mimeDirs.prepend(QLatin1String(":/qt-project.org/qmime"));
//qDebug() << "mime dirs:" << mimeDirs;
QVector<QMimeProviderBase *> currentProviders = m_providers;
m_providers.clear();
m_providers.reserve(mimeDirs.size());
for (const QString &mimeDir : qAsConst(mimeDirs)) {
const QString cacheFile = mimeDir + QStringLiteral("/mime.cache");
QFileInfo fileInfo(cacheFile);
// Check if we already have a provider for this dir
// [This could be optimized by keeping a copy of mimeDirs and comparing the stringlists]
const auto it = std::find_if(m_providers.begin(), m_providers.end(), [mimeDir](QMimeProviderBase *prov) { return prov->directory() == mimeDir; });
if (it == m_providers.end()) {
const auto it = std::find_if(currentProviders.begin(), currentProviders.end(), [mimeDir](QMimeProviderBase *prov) { return prov->directory() == mimeDir; });
if (it == currentProviders.end()) {
QMimeProviderBase *provider = nullptr;
#if defined(QT_USE_MMAP)
if (qEnvironmentVariableIsEmpty("QT_NO_MIME_CACHE") && fileInfo.exists()) {
@ -130,15 +131,17 @@ void QMimeDatabasePrivate::loadProviders()
m_providers.append(provider);
} else {
QMimeProviderBase *provider = *it;
currentProviders.erase(it);
provider->ensureLoaded();
if (!provider->isValid()) {
delete provider;
provider = new QMimeXMLProvider(this, mimeDir);
//qDebug() << "Created XML provider to replace binary provider for" << mimeDir;
*it = provider;
}
m_providers.append(provider);
}
}
qDeleteAll(currentProviders);
}
QVector<QMimeProviderBase *> QMimeDatabasePrivate::providers()

View File

@ -1042,17 +1042,21 @@ void tst_QMimeDatabase::installNewLocalMimeType()
QCOMPARE(db.mimeTypeForFile(qmlTestFile).name(),
QString::fromLatin1("text/x-qml"));
// Now test removing the local mimetypes again (note, this leaves a mostly-empty mime.cache file)
for (int i = 0; i < m_additionalMimeFileNames.size(); ++i)
QFile::remove(destDir + m_additionalMimeFileNames.at(i));
// Now test removing local mimetypes
for (int i = 1 ; i <= 3 ; ++i)
QFile::remove(destDir + QStringLiteral("invalid-magic%1.xml").arg(i));
if (m_isUsingCacheProvider && !waitAndRunUpdateMimeDatabase(m_localMimeDir))
QSKIP("shared-mime-info not found, skipping mime.cache test");
QCOMPARE(db.mimeTypeForFile(QLatin1String("foo.ymu"), QMimeDatabase::MatchExtension).name(),
QString::fromLatin1("application/octet-stream"));
QVERIFY(!db.mimeTypeForName(QLatin1String("text/x-suse-ymp")).isValid());
QVERIFY(!db.mimeTypeForName(QLatin1String("text/invalid-magic1")).isValid()); // deleted
QVERIFY(db.mimeTypeForName(QLatin1String("text/x-suse-ymp")).isValid()); // still present
// And now the user goes wild and uses rm -rf
// The user deletes the cache -> the XML provider makes things still work
QFile::remove(m_localMimeDir + QString::fromLatin1("/mime.cache"));
QVERIFY(!db.mimeTypeForName(QLatin1String("text/invalid-magic1")).isValid()); // deleted
QVERIFY(db.mimeTypeForName(QLatin1String("text/x-suse-ymp")).isValid()); // still present
// Finally, the user deletes the whole local dir
QVERIFY2(QDir(m_localMimeDir).removeRecursively(), qPrintable(m_localMimeDir + ": " + qt_error_string()));
QCOMPARE(db.mimeTypeForFile(QLatin1String("foo.ymu"), QMimeDatabase::MatchExtension).name(),
QString::fromLatin1("application/octet-stream"));
QVERIFY(!db.mimeTypeForName(QLatin1String("text/x-suse-ymp")).isValid());