diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index afd6620e65..220fc43b92 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -861,19 +861,28 @@ bool QDir::cd(const QString &dirName) if (isAbsolutePath(dirName)) { newPath = cleanPath(dirName); } else { - if (isRoot()) { - if (dirName == QLatin1String("..")) - return false; + if (isRoot()) newPath = d->dirEntry.filePath(); - } else { + else newPath = d->dirEntry.filePath() % QLatin1Char('/'); - } - newPath += dirName; if (dirName.indexOf(QLatin1Char('/')) >= 0 || dirName == QLatin1String("..") || d->dirEntry.filePath() == QLatin1String(".")) { newPath = cleanPath(newPath); +#if defined (Q_OS_UNIX) + //After cleanPath() if path is "/.." or starts with "/../" it means trying to cd above root. + if (newPath.startsWith(QLatin1String("/../")) || newPath == QLatin1String("/..")) +#else + /* + cleanPath() already took care of replacing '\' with '/'. + We can't use startsWith here because the letter of the drive is unknown. + After cleanPath() if path is "[A-Z]:/.." or starts with "[A-Z]:/../" it means trying to cd above root. + */ + + if (newPath.midRef(1, 4) == QLatin1String(":/..") && (newPath.length() == 5 || newPath.at(5) == QLatin1Char('/'))) +#endif + return false; /* If newPath starts with .., we convert it to absolute to avoid infinite looping on diff --git a/tests/auto/corelib/io/qdir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/tst_qdir.cpp index f1c9015092..539bea5e8d 100644 --- a/tests/auto/corelib/io/qdir/tst_qdir.cpp +++ b/tests/auto/corelib/io/qdir/tst_qdir.cpp @@ -190,6 +190,8 @@ private slots: void isReadable(); + void cdBelowRoot(); + private: QString m_dataPath; }; @@ -1942,6 +1944,33 @@ void tst_QDir::isReadable() #endif } +void tst_QDir::cdBelowRoot() +{ +#if defined (Q_OS_UNIX) +#define ROOT QString("/") +#define DIR QString("/tmp") +#define CD_INTO "tmp" +#else +#define ROOT QString::fromLocal8Bit(qgetenv("SystemDrive"))+"/" +#define DIR QString::fromLocal8Bit(qgetenv("SystemRoot")).replace('\\', '/') +#define CD_INTO QString::fromLocal8Bit(qgetenv("SystemRoot")).mid(3) +#endif + + QDir root(ROOT); + QVERIFY(!root.cd("..")); + QCOMPARE(root.path(), ROOT); + QVERIFY(root.cd(CD_INTO)); + QCOMPARE(root.path(), DIR); + + QDir dir(DIR); + QVERIFY(!dir.cd("../..")); + QCOMPARE(dir.path(), DIR); + QVERIFY(!dir.cd("../abs/../..")); + QCOMPARE(dir.path(), DIR); + QVERIFY(dir.cd("..")); + QCOMPARE(dir.path(), ROOT); +} + QTEST_MAIN(tst_QDir) #include "tst_qdir.moc"