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.cpp64
1 files changed, 54 insertions, 10 deletions
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 3007ffb958..4b63a38963 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -2160,9 +2160,10 @@ 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,
- bool *ok = nullptr)
+QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormalizations flags, bool *ok)
{
+ const bool allowUncPaths = QDirPrivate::AllowUncPaths & flags;
+ const bool isRemote = QDirPrivate::RemotePath & flags;
const int len = name.length();
if (ok)
@@ -2184,14 +2185,30 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
i -= prefixLength;
// replicate trailing slash (i > 0 checks for emptiness of input string p)
- if (i > 0 && p[i] == '/') {
+ // except for remote paths because there can be /../ or /./ ending
+ if (i > 0 && p[i] == '/' && !isRemote) {
out[--used] = '/';
--i;
}
+ auto isDot = [](const ushort *p, int i) {
+ return i > 1 && p[i - 1] == '.' && p[i - 2] == '/';
+ };
+ auto isDotDot = [](const ushort *p, int i) {
+ return i > 2 && p[i - 1] == '.' && p[i - 2] == '.' && p[i - 3] == '/';
+ };
+
while (i >= 0) {
- // remove trailing slashes
+ // copy trailing slashes for remote urls
if (p[i] == '/') {
+ if (isRemote && !up) {
+ if (isDot(p, i)) {
+ i -= 2;
+ continue;
+ }
+ out[--used] = p[i];
+ }
+
--i;
continue;
}
@@ -2203,10 +2220,17 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
}
// detect up dir
- if (i >= 1 && p[i] == '.' && p[i-1] == '.'
- && (i == 1 || (i >= 2 && p[i-2] == '/'))) {
+ if (i >= 1 && p[i] == '.' && p[i-1] == '.' && (i < 2 || p[i - 2] == '/')) {
++up;
- i -= 2;
+ i -= i >= 2 ? 3 : 2;
+
+ if (isRemote) {
+ // moving up should consider empty path segments too (/path//../ -> /path/)
+ while (i > 0 && up && p[i] == '/') {
+ --up;
+ --i;
+ }
+ }
continue;
}
@@ -2216,7 +2240,27 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
// skip or copy
while (i >= 0) {
- if (p[i] == '/') { // do not copy slashes
+ if (p[i] == '/') {
+ // copy all slashes as is for remote urls if they are not part of /./ or /../
+ if (isRemote && !up) {
+ while (i > 0 && p[i] == '/' && !isDotDot(p, i)) {
+
+ if (isDot(p, i)) {
+ i -= 2;
+ continue;
+ }
+
+ out[--used] = p[i];
+ --i;
+ }
+
+ // in case of /./, jump over
+ if (isDot(p, i))
+ i -= 2;
+
+ break;
+ }
+
--i;
break;
}
@@ -2237,7 +2281,7 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
*ok = prefixLength == 0 || up == 0;
// add remaining '..'
- while (up) {
+ while (up && !isRemote) {
if (used != len && out[used] != '/') // is not empty and there isn't already a '/'
out[--used] = '/';
out[--used] = '.';
@@ -2283,7 +2327,7 @@ static QString qt_cleanPath(const QString &path, bool *ok)
if (dir_separator != QLatin1Char('/'))
name.replace(dir_separator, QLatin1Char('/'));
- QString ret = qt_normalizePathSegments(name, OSSupportsUncPaths, ok);
+ QString ret = qt_normalizePathSegments(name, OSSupportsUncPaths ? QDirPrivate::AllowUncPaths : QDirPrivate::DefaultNormalization, ok);
// Strip away last slash except for root directories
if (ret.length() > 1 && ret.endsWith(QLatin1Char('/'))) {