diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2016-11-29 15:20:21 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2016-12-12 07:25:05 +0000 |
commit | f7b44f879cdded7b2c6b604df873f7194e56a63a (patch) | |
tree | 4034f9d032b85d4f76e24f249ae7988678f77751 | |
parent | 8005e0652c367c5e8c780a298d9fee4ce18a370a (diff) |
QDir::cleanPath(): Do not cd above root paths (UNC, WinRT)
Calling QDir::cleanPath() on "//server/path/.." resulted in "/".
Factor out a function to determine the root path part of an absolute
path for later use, and handle some special cases:
- Consider server name of "//server/path/.." as part of the prefix.
- Check on the root path for WinRT.
Task-number: QTBUG-53712
Change-Id: Ibddacf06212b6fc86fa74a5e4078df6cfd5b66f5
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r-- | src/corelib/io/qdir.cpp | 55 | ||||
-rw-r--r-- | tests/auto/corelib/io/qdir/tst_qdir.cpp | 16 |
2 files changed, 48 insertions, 23 deletions
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 91953ebf26..8f43b77bd5 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -80,6 +80,40 @@ static QString driveSpec(const QString &path) } #endif +enum { +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) + OSSupportsUncPaths = true +#else + OSSupportsUncPaths = false +#endif +}; + +// Return the length of the root part of an absolute path, for use by cleanPath(), cd(). +static int rootLength(const QString &name, bool allowUncPaths) +{ + const int len = name.length(); + // starts with double slash + if (allowUncPaths && name.startsWith(QLatin1String("//"))) { + // Server name '//server/path' is part of the prefix. + const int nextSlash = name.indexOf(QLatin1Char('/'), 2); + return nextSlash >= 0 ? nextSlash + 1 : len; + } +#if defined(Q_OS_WINRT) + const QString rootPath = QDir::rootPath(); // rootPath contains the trailing slash + if (name.startsWith(rootPath, Qt::CaseInsensitive)) + return rootPath.size(); +#endif // Q_OS_WINRT +#if defined(Q_OS_WIN) + if (len >= 2 && name.at(1) == QLatin1Char(':')) { + // Handle a possible drive letter + return len > 2 && name.at(2) == QLatin1Char('/') ? 3 : 2; + } +#endif + if (name.at(0) == QLatin1Char('/')) + return 1; + return 0; +} + //************* QDirPrivate QDirPrivate::QDirPrivate(const QString &path, const QStringList &nameFilters_, QDir::SortFlags sort_, QDir::Filters filters_) : QSharedData() @@ -2066,19 +2100,7 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all const QChar *prefix = p; int up = 0; - int prefixLength = 0; - - if (allowUncPaths && len >= 2 && p[1].unicode() == '/' && p[0].unicode() == '/') { - // starts with double slash - prefixLength = 2; -#ifdef Q_OS_WIN - } else if (len >= 2 && p[1].unicode() == ':') { - // remember the drive letter - prefixLength = (len > 2 && p[2].unicode() == '/') ? 3 : 2; -#endif - } else if (p[0].unicode() == '/') { - prefixLength = 1; - } + const int prefixLength = rootLength(name, allowUncPaths); p += prefixLength; i -= prefixLength; @@ -2188,12 +2210,7 @@ QString QDir::cleanPath(const QString &path) if (dir_separator != QLatin1Char('/')) name.replace(dir_separator, QLatin1Char('/')); - bool allowUncPaths = false; -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) //allow unc paths - allowUncPaths = true; -#endif - - QString ret = qt_normalizePathSegments(name, allowUncPaths); + QString ret = qt_normalizePathSegments(name, OSSupportsUncPaths); // Strip away last slash except for root directories if (ret.length() > 1 && ret.endsWith(QLatin1Char('/'))) { diff --git a/tests/auto/corelib/io/qdir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/tst_qdir.cpp index 294a53645e..fe12850476 100644 --- a/tests/auto/corelib/io/qdir/tst_qdir.cpp +++ b/tests/auto/corelib/io/qdir/tst_qdir.cpp @@ -1149,6 +1149,8 @@ tst_QDir::cleanPath_data() QTest::newRow("data0") << "/Users/sam/troll/qt4.0//.." << "/Users/sam/troll"; QTest::newRow("data1") << "/Users/sam////troll/qt4.0//.." << "/Users/sam/troll"; QTest::newRow("data2") << "/" << "/"; + QTest::newRow("data2-up") << "/path/.." << "/"; + QTest::newRow("data2-above-root") << "/.." << "/.."; QTest::newRow("data3") << QDir::cleanPath("../.") << ".."; QTest::newRow("data4") << QDir::cleanPath("../..") << "../.."; #if defined(Q_OS_WIN) @@ -1178,13 +1180,19 @@ tst_QDir::cleanPath_data() QTest::newRow("data14") << "c://foo" << "c:/foo"; // Drive letters and unc path in one string -#ifndef Q_OS_WINRT -#ifdef Q_OS_WIN +#if defined(Q_OS_WINRT) + const QString root = QDir::rootPath(); // has trailing slash + QTest::newRow("root-up") << (root + "path/..") << root; + QTest::newRow("above-root") << (root + "..") << (root + ".."); +#elif defined(Q_OS_WIN) QTest::newRow("data15") << "//c:/foo" << "//c:/foo"; + QTest::newRow("drive-up") << "A:/path/.." << "A:/"; + QTest::newRow("drive-above-root") << "A:/.." << "A:/.."; + QTest::newRow("unc-server-up") << "//server/path/.." << "//server"; + QTest::newRow("unc-server-above-root") << "//server/.." << "//server/.."; #else QTest::newRow("data15") << "//c:/foo" << "/c:/foo"; -#endif -#endif // !Q_OS_WINRT +#endif // non-windows QTest::newRow("QTBUG-23892_0") << "foo/.." << "."; QTest::newRow("QTBUG-23892_1") << "foo/../" << "."; |