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 047d8f36de45ebb318726167f941b0dbc64754ba. [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 Change-Id: I570832c9ac8b4e03bde8fffd173f7b4c6b164192 Reviewed-by: Igor Kushnir <igorkuo@gmail.com> Reviewed-by: David Faure <david.faure@kdab.com> (cherry picked from commit 40dd38813cba4bc8425e846f220e358ffb0d19ac) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
30786ef596
commit
02a03f28f5
@ -444,31 +444,32 @@ QMimeType QMimeDatabasePrivate::mimeTypeForData(QIODevice *device)
|
|||||||
}
|
}
|
||||||
|
|
||||||
QMimeType QMimeDatabasePrivate::mimeTypeForFile(const QString &fileName,
|
QMimeType QMimeDatabasePrivate::mimeTypeForFile(const QString &fileName,
|
||||||
[[maybe_unused]] const QFileInfo *fileInfo,
|
const QFileInfo &fileInfo,
|
||||||
QMimeDatabase::MatchMode mode)
|
QMimeDatabase::MatchMode mode)
|
||||||
{
|
{
|
||||||
|
if (false) {
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
// Cannot access statBuf.st_mode from the filesystem engine, so we have to stat again.
|
} else if (fileInfo.isNativePath()) {
|
||||||
// In addition we want to follow symlinks.
|
// If this is a local file, we'll want to do a stat() ourselves so we can
|
||||||
const QByteArray nativeFilePath = QFile::encodeName(fileName);
|
// detect additional inode types. In addition we want to follow symlinks.
|
||||||
QT_STATBUF statBuffer;
|
const QByteArray nativeFilePath = QFile::encodeName(fileName);
|
||||||
if (QT_STAT(nativeFilePath.constData(), &statBuffer) == 0) {
|
QT_STATBUF statBuffer;
|
||||||
if (S_ISDIR(statBuffer.st_mode))
|
if (QT_STAT(nativeFilePath.constData(), &statBuffer) == 0) {
|
||||||
return mimeTypeForName(directoryMimeType());
|
if (S_ISDIR(statBuffer.st_mode))
|
||||||
if (S_ISCHR(statBuffer.st_mode))
|
return mimeTypeForName(directoryMimeType());
|
||||||
return mimeTypeForName(QStringLiteral("inode/chardevice"));
|
if (S_ISCHR(statBuffer.st_mode))
|
||||||
if (S_ISBLK(statBuffer.st_mode))
|
return mimeTypeForName(QStringLiteral("inode/chardevice"));
|
||||||
return mimeTypeForName(QStringLiteral("inode/blockdevice"));
|
if (S_ISBLK(statBuffer.st_mode))
|
||||||
if (S_ISFIFO(statBuffer.st_mode))
|
return mimeTypeForName(QStringLiteral("inode/blockdevice"));
|
||||||
return mimeTypeForName(QStringLiteral("inode/fifo"));
|
if (S_ISFIFO(statBuffer.st_mode))
|
||||||
if (S_ISSOCK(statBuffer.st_mode))
|
return mimeTypeForName(QStringLiteral("inode/fifo"));
|
||||||
return mimeTypeForName(QStringLiteral("inode/socket"));
|
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());
|
|
||||||
#endif
|
#endif
|
||||||
|
} else if (fileInfo.isDir()) {
|
||||||
|
return mimeTypeForName(directoryMimeType());
|
||||||
|
}
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case QMimeDatabase::MatchDefault:
|
case QMimeDatabase::MatchDefault:
|
||||||
@ -615,7 +616,7 @@ QMimeType QMimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mo
|
|||||||
{
|
{
|
||||||
QMutexLocker locker(&d->mutex);
|
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) {
|
if (mode == MatchExtension) {
|
||||||
return d->mimeTypeForFileExtension(fileName);
|
return d->mimeTypeForFileExtension(fileName);
|
||||||
} else {
|
} 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 mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device);
|
||||||
QMimeType mimeTypeForFileExtension(const QString &fileName);
|
QMimeType mimeTypeForFileExtension(const QString &fileName);
|
||||||
QMimeType mimeTypeForData(QIODevice *device);
|
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);
|
QMimeType findByData(const QByteArray &data, int *priorityPtr);
|
||||||
QStringList mimeTypeForFileName(const QString &fileName);
|
QStringList mimeTypeForFileName(const QString &fileName);
|
||||||
QMimeGlobMatchResult findByFileName(const QString &fileName);
|
QMimeGlobMatchResult findByFileName(const QString &fileName);
|
||||||
|
@ -45,6 +45,14 @@ qt_internal_add_resource(tst_qmimedatabase-cache "testdata"
|
|||||||
${testdata_resource_files}
|
${testdata_resource_files}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
qt_internal_add_resource(tst_qmimedatabase-cache "testfiles"
|
||||||
|
PREFIX
|
||||||
|
"/files"
|
||||||
|
FILES
|
||||||
|
"../test.txt"
|
||||||
|
"../test.qml"
|
||||||
|
)
|
||||||
|
|
||||||
# special case begin
|
# special case begin
|
||||||
set(corelib_source_dir ../../../../../../src/corelib)
|
set(corelib_source_dir ../../../../../../src/corelib)
|
||||||
include(${corelib_source_dir}/mimetypes/mimetypes_resources.cmake)
|
include(${corelib_source_dir}/mimetypes/mimetypes_resources.cmake)
|
||||||
|
@ -45,6 +45,14 @@ qt_internal_add_resource(tst_qmimedatabase-xml "testdata"
|
|||||||
${testdata_resource_files}
|
${testdata_resource_files}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
qt_internal_add_resource(tst_qmimedatabase-xml "testfiles"
|
||||||
|
PREFIX
|
||||||
|
"/files"
|
||||||
|
FILES
|
||||||
|
"../test.txt"
|
||||||
|
"../test.qml"
|
||||||
|
)
|
||||||
|
|
||||||
# special case begin
|
# special case begin
|
||||||
set(corelib_source_dir ../../../../../../src/corelib)
|
set(corelib_source_dir ../../../../../../src/corelib)
|
||||||
include(${corelib_source_dir}/mimetypes/mimetypes_resources.cmake)
|
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 {
|
||||||
|
}
|
@ -25,6 +25,8 @@
|
|||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
static const char *const additionalMimeFiles[] = {
|
static const char *const additionalMimeFiles[] = {
|
||||||
"yast2-metapackage-handler-mimetypes.xml",
|
"yast2-metapackage-handler-mimetypes.xml",
|
||||||
"qml-again.xml",
|
"qml-again.xml",
|
||||||
@ -245,6 +247,7 @@ void tst_QMimeDatabase::mimeTypeForFileName_data()
|
|||||||
// fdo bug 15436, needs shared-mime-info >= 0.40 (and this tests the globs2-parsing code).
|
// 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("glob that ends with *, also matches *.pdf. *.pdf has higher weight") << "README.pdf" << "application/pdf";
|
||||||
QTest::newRow("directory") << "/" << "inode/directory";
|
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, no extension") << "IDontExist" << "application/octet-stream";
|
||||||
QTest::newRow("doesn't exist but has known extension") << "IDontExist.txt" << "text/plain";
|
QTest::newRow("doesn't exist but has known extension") << "IDontExist.txt" << "text/plain";
|
||||||
QTest::newRow("empty") << "" << "application/octet-stream";
|
QTest::newRow("empty") << "" << "application/octet-stream";
|
||||||
@ -497,6 +500,42 @@ void tst_QMimeDatabase::mimeTypeForFileWithContent()
|
|||||||
QCOMPARE(mime.name(), QString::fromLatin1("application/smil+xml"));
|
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
|
// Test what happens with an incorrect path
|
||||||
mime = db.mimeTypeForFile(QString::fromLatin1("file:///etc/passwd" /* incorrect code, use a path instead */));
|
mime = db.mimeTypeForFile(QString::fromLatin1("file:///etc/passwd" /* incorrect code, use a path instead */));
|
||||||
QVERIFY(mime.isDefault());
|
QVERIFY(mime.isDefault());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user