diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2016-07-08 15:30:45 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2016-12-12 07:25:22 +0000 |
commit | 101449a4cfa9c0d216332c6dc8ba826e8109e09d (patch) | |
tree | 9a5494bdc1c1819d837a97e74fc220f85e4e8310 | |
parent | f7b44f879cdded7b2c6b604df873f7194e56a63a (diff) |
QDir::cd(): Handle UNC server paths correctly
Add a bool *ok out parameter to qt_normalizePathSegments() and return false
when ".." are left over for an absolute path, indicating an attempt to
change above root.
Factor out static helper qt_cleanPath() to be able to pass the return value
to QDir::cd() and return on failure from there.
Amends change 63f634322b2c0f795bd424be9e51953a10c701de, which did
not handle UNC paths.
Task-number: QTBUG-53712
Change-Id: I3e63a5dd0259306a0b99145348d815899582f78e
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r-- | src/corelib/io/qdir.cpp | 73 | ||||
-rw-r--r-- | src/corelib/io/qurl.cpp | 3 | ||||
-rw-r--r-- | tests/auto/corelib/io/qdir/tst_qdir.cpp | 7 |
3 files changed, 45 insertions, 38 deletions
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 8f43b77bd5..437f774547 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -893,6 +893,8 @@ QString QDir::fromNativeSeparators(const QString &pathName) return pathName; } +static QString qt_cleanPath(const QString &path, bool *ok = nullptr); + /*! Changes the QDir's directory to \a dirName. @@ -913,32 +915,18 @@ bool QDir::cd(const QString &dirName) return true; QString newPath; if (isAbsolutePath(dirName)) { - newPath = cleanPath(dirName); + newPath = qt_cleanPath(dirName); } else { - if (isRoot()) - newPath = d->dirEntry.filePath(); - else - newPath = d->dirEntry.filePath() % QLatin1Char('/'); + newPath = d->dirEntry.filePath(); + if (!newPath.endsWith(QLatin1Char('/'))) + newPath += 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("/..")) -#elif defined (Q_OS_WINRT) - const QString rootPath = QDir::rootPath(); - if (newPath.size() < rootPath.size() && rootPath.startsWith(newPath)) -#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 + bool ok; + newPath = qt_cleanPath(newPath, &ok); + if (!ok) return false; /* If newPath starts with .., we convert it to absolute to @@ -2085,10 +2073,14 @@ bool QDir::match(const QString &filter, const QString &fileName) This method is shared with QUrl, so it doesn't deal with QDir::separator(), nor does it remove the trailing slash, if any. */ -Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool allowUncPaths) +Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool allowUncPaths, + bool *ok = nullptr) { const int len = name.length(); + if (ok) + *ok = false; + if (len == 0) return name; @@ -2153,6 +2145,10 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all --up; } + // Indicate failure when ".." are left over for an absolute path. + if (ok) + *ok = prefixLength == 0 || up == 0; + // add remaining '..' while (up) { if (used != len && out[used].unicode() != '/') // is not empty and there isn't already a '/' @@ -2190,27 +2186,16 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all return ret; } -/*! - Returns \a path with directory separators normalized (converted to "/") and - redundant ones removed, and "."s and ".."s resolved (as far as possible). - - Symbolic links are kept. This function does not return the - canonical path, but rather the simplest version of the input. - For example, "./local" becomes "local", "local/../bin" becomes - "bin" and "/local/usr/../bin" becomes "/local/bin". - - \sa absolutePath(), canonicalPath() -*/ -QString QDir::cleanPath(const QString &path) +static QString qt_cleanPath(const QString &path, bool *ok) { if (path.isEmpty()) return path; QString name = path; - QChar dir_separator = separator(); + QChar dir_separator = QDir::separator(); if (dir_separator != QLatin1Char('/')) name.replace(dir_separator, QLatin1Char('/')); - QString ret = qt_normalizePathSegments(name, OSSupportsUncPaths); + QString ret = qt_normalizePathSegments(name, OSSupportsUncPaths, ok); // Strip away last slash except for root directories if (ret.length() > 1 && ret.endsWith(QLatin1Char('/'))) { @@ -2228,6 +2213,22 @@ QString QDir::cleanPath(const QString &path) } /*! + Returns \a path with directory separators normalized (converted to "/") and + redundant ones removed, and "."s and ".."s resolved (as far as possible). + + Symbolic links are kept. This function does not return the + canonical path, but rather the simplest version of the input. + For example, "./local" becomes "local", "local/../bin" becomes + "bin" and "/local/usr/../bin" becomes "/local/bin". + + \sa absolutePath(), canonicalPath() +*/ +QString QDir::cleanPath(const QString &path) +{ + return qt_cleanPath(path); +} + +/*! Returns \c true if \a path is relative; returns \c false if it is absolute. diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 60ce752eb6..066052ade9 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -417,7 +417,8 @@ #include "qurlquery.h" QT_BEGIN_NAMESPACE -extern QString qt_normalizePathSegments(const QString &name, bool allowUncPaths); // qdir.cpp +extern QString qt_normalizePathSegments(const QString &name, bool allowUncPaths, + bool *ok = nullptr); // qdir.cpp inline static bool isHex(char c) { diff --git a/tests/auto/corelib/io/qdir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/tst_qdir.cpp index fe12850476..b86c6e4dfa 100644 --- a/tests/auto/corelib/io/qdir/tst_qdir.cpp +++ b/tests/auto/corelib/io/qdir/tst_qdir.cpp @@ -58,7 +58,8 @@ #ifdef QT_BUILD_INTERNAL QT_BEGIN_NAMESPACE -extern Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &, bool); +extern Q_AUTOTEST_EXPORT QString + qt_normalizePathSegments(const QString &path, bool allowUncPaths, bool *ok = nullptr); QT_END_NAMESPACE #endif @@ -2246,6 +2247,10 @@ void tst_QDir::cdBelowRoot_data() const QString systemRoot = QString::fromLocal8Bit(qgetenv("SystemRoot")); QTest::newRow("windows-drive") << systemDrive << systemRoot.mid(3) << QDir::cleanPath(systemRoot); + const QString uncRoot = QStringLiteral("//") + QtNetworkSettings::winServerName(); + const QString testDirectory = QStringLiteral("testshare"); + QTest::newRow("windows-share") + << uncRoot << testDirectory << QDir::cleanPath(uncRoot + QLatin1Char('/') + testDirectory); #endif // Windows } |