Fix BC break with QAbstractFileEngine "mount points"

File system cached metadata can't be trusted when custom file engines
are in use, because the custom file engine may want to override the
metadata. (e.g. present an archive file as a directory)

Therefore, check if a file engine should be instantiated for each
result in QDirIterator. This is a fast check if no custom file engines
are registered.
When pushing a directory (using QDirIterator::SubDirectories) the
file engine needs to be instantiated also.

Task-number: QTBUG-23688
Task-number: ou1cimx1#965023
Change-Id: I0114c8df6258535553783a2486131c4194926649
Reviewed-by: João Abecasis <joao.abecasis@nokia.com>
(cherry picked from 3864ad09d578210b52e5f58fca2ee8a1144f5be2)
This commit is contained in:
Shane Kearns 2012-01-17 19:51:39 +00:00 committed by Qt by Nokia
parent 10229aedf4
commit d71ccb9c13
2 changed files with 97 additions and 1 deletions

View File

@ -108,10 +108,15 @@ public:
: QSharedData(), : QSharedData(),
fileEntry(file), fileEntry(file),
metaData(data), metaData(data),
fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
cachedFlags(0), cachedFlags(0),
isDefaultConstructed(false), isDefaultConstructed(false),
cache_enabled(true), fileFlags(0), fileSize(0) cache_enabled(true), fileFlags(0), fileSize(0)
{ {
//If the file engine is not null, this maybe a "mount point" for a custom file engine
//in which case we can't trust the metadata
if (fileEngine)
metaData = QFileSystemMetaData();
} }
inline void clearFlags() const { inline void clearFlags() const {

View File

@ -47,10 +47,13 @@
#include <QtCore/QSharedPointer> #include <QtCore/QSharedPointer>
#include <QtCore/QScopedPointer> #include <QtCore/QScopedPointer>
#include <QtCore/QHash> #include <QtCore/QHash>
#include <QtCore/QDir>
#include <QtCore/QDirIterator>
#include <QtTest/QTest> #include <QtTest/QTest>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include "../../../../shared/filesystem.h"
class tst_QAbstractFileEngine class tst_QAbstractFileEngine
: public QObject : public QObject
@ -65,6 +68,8 @@ private slots:
void fileIO_data(); void fileIO_data();
void fileIO(); void fileIO();
void mounting_data();
void mounting();
private: private:
QStringList filesForRemoval; QStringList filesForRemoval;
}; };
@ -74,7 +79,7 @@ class ReferenceFileEngine
{ {
public: public:
ReferenceFileEngine(const QString &fileName) ReferenceFileEngine(const QString &fileName)
: fileName_(fileName) : fileName_(QDir::cleanPath(fileName))
, position_(-1) , position_(-1)
, openForRead_(false) , openForRead_(false)
, openForWrite_(false) , openForWrite_(false)
@ -491,6 +496,60 @@ private:
mutable QSharedPointer<File> openFile_; mutable QSharedPointer<File> openFile_;
}; };
class MountingFileEngine : public QFSFileEngine
{
public:
class Iterator : public QAbstractFileEngineIterator
{
public:
Iterator(QDir::Filters filters, const QStringList &filterNames)
: QAbstractFileEngineIterator(filters, filterNames)
{
names.append("foo");
names.append("bar");
index = -1;
}
QString currentFileName() const
{
return names.at(index);
}
bool hasNext() const
{
return index < names.size() - 1;
}
QString next()
{
if (!hasNext())
return QString();
++index;
return currentFilePath();
}
QStringList names;
int index;
};
MountingFileEngine(QString fileName)
: QFSFileEngine(fileName)
{
}
Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames)
{
return new Iterator(filters, filterNames);
}
FileFlags fileFlags(FileFlags type) const
{
if (fileName(DefaultName).endsWith(".tar")) {
FileFlags ret = QFSFileEngine::fileFlags(type);
//make this file in file system appear to be a directory
ret &= ~FileType;
ret |= DirectoryType;
return ret;
} else {
//file inside the archive
return ExistsFlag | FileType;
}
}
};
QMutex ReferenceFileEngine::fileSystemMutex; QMutex ReferenceFileEngine::fileSystemMutex;
QHash<uint, QString> ReferenceFileEngine::fileSystemUsers, ReferenceFileEngine::fileSystemGroups; QHash<uint, QString> ReferenceFileEngine::fileSystemUsers, ReferenceFileEngine::fileSystemGroups;
QHash<QString, QSharedPointer<ReferenceFileEngine::File> > ReferenceFileEngine::fileSystem; QHash<QString, QSharedPointer<ReferenceFileEngine::File> > ReferenceFileEngine::fileSystem;
@ -500,6 +559,8 @@ class FileEngineHandler
{ {
QAbstractFileEngine *create(const QString &fileName) const QAbstractFileEngine *create(const QString &fileName) const
{ {
if (fileName.endsWith(".tar") || fileName.contains(".tar/"))
return new MountingFileEngine(fileName);
if (fileName.startsWith("QFSFileEngine:")) if (fileName.startsWith("QFSFileEngine:"))
return new QFSFileEngine(fileName.mid(14)); return new QFSFileEngine(fileName.mid(14));
if (fileName.startsWith("reference-file-engine:")) if (fileName.startsWith("reference-file-engine:"))
@ -803,6 +864,36 @@ void tst_QAbstractFileEngine::fileIO()
// //
} }
void tst_QAbstractFileEngine::mounting_data()
{
QTest::addColumn<QString>("fileName");
QTest::newRow("native") << "test.tar";
QTest::newRow("Forced QFSFileEngine") << "QFSFileEngine:test.tar";
}
void tst_QAbstractFileEngine::mounting()
{
FileSystem fs;
QVERIFY(fs.createFile("test.tar"));
FileEngineHandler handler;
QFETCH(QString, fileName);
QVERIFY(QFileInfo(fileName).isDir());
QDir dir(fileName);
QCOMPARE(dir.entryList(), (QStringList() << "bar" << "foo"));
QDir dir2;
bool found = false;
foreach (QFileInfo info, dir2.entryInfoList()) {
if (info.fileName() == QLatin1String("test.tar")) {
QVERIFY(!found);
found = true;
QVERIFY(info.isDir());
}
}
QVERIFY(found);
}
QTEST_APPLESS_MAIN(tst_QAbstractFileEngine) QTEST_APPLESS_MAIN(tst_QAbstractFileEngine)
#include "tst_qabstractfileengine.moc" #include "tst_qabstractfileengine.moc"