summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qdir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io/qdir.cpp')
-rw-r--r--src/corelib/io/qdir.cpp126
1 files changed, 72 insertions, 54 deletions
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 91953ebf26..437f774547 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()
@@ -859,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.
@@ -879,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
@@ -2051,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;
@@ -2066,19 +2092,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;
@@ -2131,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 '/'
@@ -2168,32 +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('/'));
- 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, ok);
// Strip away last slash except for root directories
if (ret.length() > 1 && ret.endsWith(QLatin1Char('/'))) {
@@ -2211,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.