diff options
| author | Thiago Macieira <thiago.macieira@intel.com> | 2025-02-02 10:45:49 -0800 |
|---|---|---|
| committer | Thiago Macieira <thiago.macieira@intel.com> | 2025-02-04 11:37:31 -0800 |
| commit | 340c9d88ab353e201f117d64609fa5f7d2fa2b21 (patch) | |
| tree | 06f10c09c03cbbec052b56b0dcf346771d68a077 /src/corelib/io/qdir.cpp | |
| parent | 7d05f5ed7d3472028e28a09eeda175bb1b1eeb00 (diff) | |
QUrl: avoid going up from the drive path on Windows file URLs
On Windows, using a URL of "file:///c:/" as a base to be resolved with
"../" should not result in the Windows drive being removed.
[ChangeLog][QtCore][QUrl] Fixed a bug (regression from 6.7) where
resolving a base URL of an absolute file path containing a Windows drive
could result in said drive being removed (e.g., resolving "file:///c:/"
with "../" would result in "file:///").
Fixes: QTBUG-133402
Pick-to: 6.9 6.8
Change-Id: I58286b9c5e5d02363f0efffdb06f983b560340df
Reviewed-by: David Faure <david.faure@kdab.com>
Diffstat (limited to 'src/corelib/io/qdir.cpp')
| -rw-r--r-- | src/corelib/io/qdir.cpp | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 58fccc2e7c2..227aa936318 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -52,23 +52,40 @@ static QString driveSpec(const QString &path) #endif // Return the length of the root part of an absolute path, for use by cleanPath(), cd(). -static qsizetype rootLength(QStringView name) +static qsizetype rootLength(QStringView name, QDirPrivate::PathNormalizations flags) { + constexpr bool UseWindowsRules = false // So we don't #include <QOperatingSystemVersion> #if defined(Q_OS_WIN) + || true +#endif + ; const qsizetype len = name.size(); - // Handle possible UNC paths which start with double slash - if (name.startsWith("//"_L1)) { - // Server name '//server/path' is part of the prefix. - const qsizetype nextSlash = name.indexOf(u'/', 2); - return nextSlash >= 0 ? nextSlash + 1 : len; - } - if (len >= 2 && name.at(1) == u':') { + char16_t firstChar = len > 0 ? name.at(0).unicode() : u'\0'; + char16_t secondChar = len > 1 ? name.at(1).unicode() : u'\0'; + if constexpr (UseWindowsRules) { + // Handle possible UNC paths which start with double slash + bool urlMode = flags.testAnyFlags(QDirPrivate::UrlNormalizationMode); + if (firstChar == u'/' && secondChar == u'/' && !urlMode) { + // Server name '//server/path' is part of the prefix. + const qsizetype nextSlash = name.indexOf(u'/', 2); + return nextSlash >= 0 ? nextSlash + 1 : len; + } + // Handle a possible drive letter - return len > 2 && name.at(2) == u'/' ? 3 : 2; + qsizetype driveLength = 2; + if (firstChar == u'/' && urlMode && len > 2 && name.at(2) == u':') { + // Drive-in-URL-Path mode, e.g. "/c:" or "/c:/autoexec.bat" + ++driveLength; + secondChar = u':'; + } + if (secondChar == u':') { + if (len > driveLength && name.at(driveLength) == u'/') + return driveLength + 1; // absolute drive path, e.g. "c:/config.sys" + return driveLength; // relative drive path, e.g. "c:" or "d:swapfile.sys" + } } -#endif - return name.startsWith(u'/') ? 1 : 0; + return firstChar == u'/' ? 1 : 0; } //************* QDirPrivate @@ -2217,7 +2234,7 @@ bool QDir::match(const QString &filter, const QString &fileName) bool qt_normalizePathSegments(QString *path, QDirPrivate::PathNormalizations flags) { const bool isRemote = flags.testAnyFlag(QDirPrivate::RemotePath); - const qsizetype prefixLength = rootLength(*path); + const qsizetype prefixLength = rootLength(*path, flags); // RFC 3986 says: "The input buffer is initialized with the now-appended // path components and the output buffer is initialized to the empty |
