Fix comparison of absolute, unclean paths in QDir

QDir::operator== was creating a clean absolute path for comparison
purposes if the original path was relative.
However original absolute paths were trusted, even though they could
be unclean. Now they are checked for cleanliness first.

Task-Number: QTBUG-19995
Task-Number: QTBUG-20495
Change-Id: I047a1a40ae5151e4604085e4ac87f30a4e4979c4
Reviewed-on: http://codereview.qt.nokia.com/4099
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Prasanth Ullattil <prasanth.ullattil@nokia.com>
bb10
Shane Kearns 2011-09-01 15:04:33 +01:00 committed by Qt by Nokia
parent 254d7189d8
commit e8192883b2
5 changed files with 78 additions and 1 deletions

View File

@ -190,7 +190,7 @@ inline void QDirPrivate::resolveAbsoluteEntry() const
QString absoluteName;
if (fileEngine.isNull()) {
if (!dirEntry.isRelative()) {
if (!dirEntry.isRelative() && dirEntry.isClean()) {
absoluteDirEntry = dirEntry;
return;
}

View File

@ -380,4 +380,35 @@ void QFileSystemEntry::findFileNameSeparators() const
}
}
bool QFileSystemEntry::isClean() const
{
resolveFilePath();
int dots = 0;
bool dotok = true; // checking for ".." or "." starts to relative paths
bool slashok = true;
for (QString::const_iterator iter = m_filePath.constBegin(); iter != m_filePath.constEnd(); iter++) {
if (*iter == QLatin1Char('/')) {
if (dots == 1 || dots == 2)
return false; // path contains "./" or "../"
if (!slashok)
return false; // path contains "//"
dots = 0;
dotok = true;
slashok = false;
} else if (dotok) {
slashok = true;
if (*iter == QLatin1Char('.')) {
dots++;
if (dots > 2)
dotok = false;
} else {
//path element contains a character other than '.', it's clean
dots = 0;
dotok = false;
}
}
}
return (dots != 1 && dots != 2); // clean if path doesn't end in . or ..
}
QT_END_NAMESPACE

View File

@ -91,6 +91,7 @@ public:
QString completeSuffix() const;
bool isAbsolute() const;
bool isRelative() const;
bool isClean() const;
#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
bool isDriveRoot() const;

View File

@ -1109,6 +1109,11 @@ void tst_QDir::absolutePath_data()
QTest::newRow("4") << "c:/machine/share/dir1" << "c:/machine/share/dir1";
QTest::newRow("5") << "c:\\machine\\share\\dir1" << "c:/machine/share/dir1";
#endif
//test dirty paths are cleaned (QTBUG-19995)
QTest::newRow("/home/qt/.") << QDir::rootPath() + "home/qt/." << QDir::rootPath() + "home/qt";
QTest::newRow("/system/data/../config") << QDir::rootPath() + "system/data/../config" << QDir::rootPath() + "system/config";
QTest::newRow("//home//qt/") << QDir::rootPath() + "/home//qt/" << QDir::rootPath() + "home/qt";
QTest::newRow("foo/../bar") << "foo/../bar" << QDir::currentPath() + "/bar";
QTest::newRow("resource") << ":/prefix/foo.bar" << ":/prefix/foo.bar";
}
@ -1872,6 +1877,14 @@ void tst_QDir::equalityOperator_data()
<< "./entrylist" << "*.cpp" << int(QDir::Name) << int(QDir::Files)
<< true;
QTest::newRow("QTBUG-20495") << QDir::currentPath() + "/entrylist/.." << "*.cpp" << int(QDir::Name) << int(QDir::Files)
<< "." << "*.cpp" << int(QDir::Name) << int(QDir::Files)
<< true;
QTest::newRow("QTBUG-20495-root") << QDir::rootPath() + "tmp/.." << "*.cpp" << int(QDir::Name) << int(QDir::Files)
<< QDir::rootPath() << "*.cpp" << int(QDir::Name) << int(QDir::Files)
<< true;
QTest::newRow("diff-filters") << SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Files)
<< SRCDIR << "*.cpp" << int(QDir::Name) << int(QDir::Dirs)
<< false;

View File

@ -68,6 +68,8 @@ private slots:
void absoluteOrRelative_data();
void absoluteOrRelative();
#endif
void isClean_data();
void isClean();
};
#if defined(WIN_STUFF)
@ -383,5 +385,35 @@ void tst_QFileSystemEntry::absoluteOrRelative()
}
#endif
void tst_QFileSystemEntry::isClean_data()
{
QTest::addColumn<QString>("path");
QTest::addColumn<bool>("isClean");
QTest::newRow("simple") << "foo" << true;
QTest::newRow("complex") << "/foo/bar/bz" << true;
QTest::newRow(".file") << "/foo/.file" << true;
QTest::newRow("..file") << "/foo/..file" << true;
QTest::newRow("...") << "/foo/.../bar" << true;
QTest::newRow("./") << "./" << false;
QTest::newRow("../") << "../" << false;
QTest::newRow(".") << "." << false;
QTest::newRow("..") << ".." << false;
QTest::newRow("/.") << "/." << false;
QTest::newRow("/..") << "/.." << false;
QTest::newRow("/../") << "foo/../bar" << false;
QTest::newRow("/./") << "foo/./bar" << false;
QTest::newRow("//") << "foo//bar" << false;
}
void tst_QFileSystemEntry::isClean()
{
QFETCH(QString, path);
QFETCH(bool, isClean);
QFileSystemEntry fi(path);
QCOMPARE(fi.isClean(), isClean);
}
QTEST_MAIN(tst_QFileSystemEntry)
#include <tst_qfilesystementry.moc>