diff options
Diffstat (limited to 'src/corelib/io/qdir.cpp')
-rw-r--r-- | src/corelib/io/qdir.cpp | 126 |
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. |