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 63f634322b, 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>
bb10
parent
f7b44f879c
commit
101449a4cf
|
|
@ -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('/'))) {
|
||||
|
|
@ -2227,6 +2212,22 @@ QString QDir::cleanPath(const QString &path)
|
|||
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)
|
||||
{
|
||||
return qt_cleanPath(path);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c true if \a path is relative; returns \c false if it is
|
||||
absolute.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue