QMimeDatabase: don't stat() something that isn't a local file
We must check that the path is an actual file on the filesystem before
using native APIs. This regression was introduced by commit
047d8f36de
.
[ChangeLog][QtCore][QMimeDatabase] Fixed a regression from 6.4.0 that
made certain QMimeDatabase functions that inspected file contents to fail
on Unix systems, if the file was not a native file (e.g., a Qt resource).
Fixes: QTBUG-110707
Pick-to: 6.4 6.5
Change-Id: I570832c9ac8b4e03bde8fffd173f7b4c6b164192
Reviewed-by: Igor Kushnir <igorkuo@gmail.com>
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
parent
bfe42ebdeb
commit
40dd38813c
@ -444,31 +444,32 @@ QMimeType QMimeDatabasePrivate::mimeTypeForData(QIODevice *device)
|
||||
}
|
||||
|
||||
QMimeType QMimeDatabasePrivate::mimeTypeForFile(const QString &fileName,
|
||||
[[maybe_unused]] const QFileInfo *fileInfo,
|
||||
const QFileInfo &fileInfo,
|
||||
QMimeDatabase::MatchMode mode)
|
||||
{
|
||||
if (false) {
|
||||
#ifdef Q_OS_UNIX
|
||||
// Cannot access statBuf.st_mode from the filesystem engine, so we have to stat again.
|
||||
// In addition we want to follow symlinks.
|
||||
const QByteArray nativeFilePath = QFile::encodeName(fileName);
|
||||
QT_STATBUF statBuffer;
|
||||
if (QT_STAT(nativeFilePath.constData(), &statBuffer) == 0) {
|
||||
if (S_ISDIR(statBuffer.st_mode))
|
||||
return mimeTypeForName(directoryMimeType());
|
||||
if (S_ISCHR(statBuffer.st_mode))
|
||||
return mimeTypeForName(QStringLiteral("inode/chardevice"));
|
||||
if (S_ISBLK(statBuffer.st_mode))
|
||||
return mimeTypeForName(QStringLiteral("inode/blockdevice"));
|
||||
if (S_ISFIFO(statBuffer.st_mode))
|
||||
return mimeTypeForName(QStringLiteral("inode/fifo"));
|
||||
if (S_ISSOCK(statBuffer.st_mode))
|
||||
return mimeTypeForName(QStringLiteral("inode/socket"));
|
||||
}
|
||||
#else
|
||||
const bool isDirectory = fileInfo ? fileInfo->isDir() : QFileInfo(fileName).isDir();
|
||||
if (isDirectory)
|
||||
return mimeTypeForName(directoryMimeType());
|
||||
} else if (fileInfo.isNativePath()) {
|
||||
// If this is a local file, we'll want to do a stat() ourselves so we can
|
||||
// detect additional inode types. In addition we want to follow symlinks.
|
||||
const QByteArray nativeFilePath = QFile::encodeName(fileName);
|
||||
QT_STATBUF statBuffer;
|
||||
if (QT_STAT(nativeFilePath.constData(), &statBuffer) == 0) {
|
||||
if (S_ISDIR(statBuffer.st_mode))
|
||||
return mimeTypeForName(directoryMimeType());
|
||||
if (S_ISCHR(statBuffer.st_mode))
|
||||
return mimeTypeForName(QStringLiteral("inode/chardevice"));
|
||||
if (S_ISBLK(statBuffer.st_mode))
|
||||
return mimeTypeForName(QStringLiteral("inode/blockdevice"));
|
||||
if (S_ISFIFO(statBuffer.st_mode))
|
||||
return mimeTypeForName(QStringLiteral("inode/fifo"));
|
||||
if (S_ISSOCK(statBuffer.st_mode))
|
||||
return mimeTypeForName(QStringLiteral("inode/socket"));
|
||||
}
|
||||
#endif
|
||||
} else if (fileInfo.isDir()) {
|
||||
return mimeTypeForName(directoryMimeType());
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case QMimeDatabase::MatchDefault:
|
||||
@ -615,7 +616,7 @@ QMimeType QMimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mo
|
||||
{
|
||||
QMutexLocker locker(&d->mutex);
|
||||
|
||||
return d->mimeTypeForFile(fileInfo.filePath(), &fileInfo, mode);
|
||||
return d->mimeTypeForFile(fileInfo.filePath(), fileInfo, mode);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -630,7 +631,8 @@ QMimeType QMimeDatabase::mimeTypeForFile(const QString &fileName, MatchMode mode
|
||||
if (mode == MatchExtension) {
|
||||
return d->mimeTypeForFileExtension(fileName);
|
||||
} else {
|
||||
return d->mimeTypeForFile(fileName, nullptr, mode);
|
||||
QFileInfo fileInfo(fileName);
|
||||
return d->mimeTypeForFile(fileName, fileInfo, mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
QMimeType mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device);
|
||||
QMimeType mimeTypeForFileExtension(const QString &fileName);
|
||||
QMimeType mimeTypeForData(QIODevice *device);
|
||||
QMimeType mimeTypeForFile(const QString &fileName, const QFileInfo *fileInfo, QMimeDatabase::MatchMode mode);
|
||||
QMimeType mimeTypeForFile(const QString &fileName, const QFileInfo &fileInfo, QMimeDatabase::MatchMode mode);
|
||||
QMimeType findByData(const QByteArray &data, int *priorityPtr);
|
||||
QStringList mimeTypeForFileName(const QString &fileName);
|
||||
QMimeGlobMatchResult findByFileName(const QString &fileName);
|
||||
|
@ -48,6 +48,14 @@ qt_internal_add_resource(tst_qmimedatabase-cache "testdata"
|
||||
${testdata_resource_files}
|
||||
)
|
||||
|
||||
qt_internal_add_resource(tst_qmimedatabase-cache "testfiles"
|
||||
PREFIX
|
||||
"/files"
|
||||
FILES
|
||||
"../test.txt"
|
||||
"../test.qml"
|
||||
)
|
||||
|
||||
# special case begin
|
||||
set(corelib_source_dir ../../../../../../src/corelib)
|
||||
include(${corelib_source_dir}/mimetypes/mimetypes_resources.cmake)
|
||||
|
@ -48,6 +48,14 @@ qt_internal_add_resource(tst_qmimedatabase-xml "testdata"
|
||||
${testdata_resource_files}
|
||||
)
|
||||
|
||||
qt_internal_add_resource(tst_qmimedatabase-xml "testfiles"
|
||||
PREFIX
|
||||
"/files"
|
||||
FILES
|
||||
"../test.txt"
|
||||
"../test.qml"
|
||||
)
|
||||
|
||||
# special case begin
|
||||
set(corelib_source_dir ../../../../../../src/corelib)
|
||||
include(${corelib_source_dir}/mimetypes/mimetypes_resources.cmake)
|
||||
|
6
tests/auto/corelib/mimetypes/qmimedatabase/test.txt
Normal file
6
tests/auto/corelib/mimetypes/qmimedatabase/test.txt
Normal file
@ -0,0 +1,6 @@
|
||||
// Copyright (C) 2012 David Faure <faure@kde.org>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick 1.1
|
||||
Item {
|
||||
}
|
@ -26,6 +26,8 @@
|
||||
#include <QProcess>
|
||||
#endif
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
static const char *const additionalMimeFiles[] = {
|
||||
"yast2-metapackage-handler-mimetypes.xml",
|
||||
"qml-again.xml",
|
||||
@ -246,6 +248,7 @@ void tst_QMimeDatabase::mimeTypeForFileName_data()
|
||||
// fdo bug 15436, needs shared-mime-info >= 0.40 (and this tests the globs2-parsing code).
|
||||
QTest::newRow("glob that ends with *, also matches *.pdf. *.pdf has higher weight") << "README.pdf" << "application/pdf";
|
||||
QTest::newRow("directory") << "/" << "inode/directory";
|
||||
QTest::newRow("resource-directory") << ":/files/" << "inode/directory";
|
||||
QTest::newRow("doesn't exist, no extension") << "IDontExist" << "application/octet-stream";
|
||||
QTest::newRow("doesn't exist but has known extension") << "IDontExist.txt" << "text/plain";
|
||||
QTest::newRow("empty") << "" << "application/octet-stream";
|
||||
@ -498,6 +501,42 @@ void tst_QMimeDatabase::mimeTypeForFileWithContent()
|
||||
QCOMPARE(mime.name(), QString::fromLatin1("application/smil+xml"));
|
||||
}
|
||||
|
||||
// Test what happens with Qt resources (file engines in general)
|
||||
{
|
||||
QFile rccFile(":/files/test.txt");
|
||||
|
||||
mime = db.mimeTypeForFile(rccFile.fileName());
|
||||
QCOMPARE(mime.name(), "text/plain"_L1);
|
||||
|
||||
QVERIFY(rccFile.open(QIODevice::ReadOnly));
|
||||
mime = db.mimeTypeForData(&rccFile);
|
||||
QCOMPARE(mime.name(), "text/x-qml"_L1);
|
||||
QVERIFY(rccFile.isOpen());
|
||||
|
||||
mime = db.mimeTypeForFile(rccFile.fileName(), QMimeDatabase::MatchContent);
|
||||
QCOMPARE(mime.name(), "text/x-qml"_L1);
|
||||
}
|
||||
|
||||
// Directories
|
||||
{
|
||||
mime = db.mimeTypeForFile("/");
|
||||
QCOMPARE(mime.name(), "inode/directory"_L1);
|
||||
|
||||
QString dirName = QDir::tempPath();
|
||||
if (!dirName.endsWith(u'/'))
|
||||
dirName += u'/';
|
||||
mime = db.mimeTypeForFile(dirName);
|
||||
QCOMPARE(mime.name(), "inode/directory"_L1);
|
||||
|
||||
while (dirName.endsWith(u'/'))
|
||||
dirName.chop(1);
|
||||
mime = db.mimeTypeForFile(dirName);
|
||||
QCOMPARE(mime.name(), "inode/directory"_L1);
|
||||
|
||||
mime = db.mimeTypeForFile(":/files");
|
||||
QCOMPARE(mime.name(), "inode/directory"_L1);
|
||||
}
|
||||
|
||||
// Test what happens with an incorrect path
|
||||
mime = db.mimeTypeForFile(QString::fromLatin1("file:///etc/passwd" /* incorrect code, use a path instead */));
|
||||
QVERIFY(mime.isDefault());
|
||||
|
Loading…
Reference in New Issue
Block a user