Fix QSaveFile and QTemporaryFile issues with windows network shares

The commit amends commit 3966b571 to take UNC prefix into account as
well. Fixes the weird file name output as reported in QTBUG-74291 and
QTBUG-83365. Replace manual separator normalizing in qt_cleanPath(),
this is another spot where UNC prefix handling needs to be applied.

Also make QTemporaryFile operate on '/' as file separators to fix
creating both file types with native path separators on network shares.

Fixes: QTBUG-74291
Fixes: QTBUG-76228
Fixes: QTBUG-83365
Pick-to: 5.15 6.0 6.1
Change-Id: Iff8d26b994bf4194c074cd5c996cda3934297fa5
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Karsten Heimrich 2021-05-03 14:40:53 +02:00
parent a120d11cb5
commit ec9e856563
7 changed files with 45 additions and 25 deletions

View File

@ -953,22 +953,29 @@ QString QDir::toNativeSeparators(const QString &pathName)
QString QDir::fromNativeSeparators(const QString &pathName)
{
#if defined(Q_OS_WIN)
int i = pathName.indexOf(QLatin1Char('\\'));
const QChar nativeSeparator = u'\\';
int i = pathName.indexOf(nativeSeparator);
if (i != -1) {
QString n(pathName);
if (n.startsWith(QLatin1String("\\\\?\\"))) {
n.remove(0, 4);
i = n.indexOf(QLatin1Char('\\'));
if (i == -1)
const QStringView uncPrefix(uR"(\\?\UNC\)");
const QStringView extendedLengthPathPrefix(uR"(\\?\)");
if (n.startsWith(uncPrefix)) {
// Keep the initial double-slash, chop out the rest of the prefix.
n = n.remove(2, uncPrefix.size() - 2);
if ((i = n.indexOf(nativeSeparator)) == -1)
return n;
} else if (n.startsWith(extendedLengthPathPrefix)) {
n = n.sliced(extendedLengthPathPrefix.size());
if ((i = n.indexOf(nativeSeparator)) == -1)
return n;
}
QChar * const data = n.data();
data[i++] = QLatin1Char('/');
data[i++] = u'/';
for (; i < n.length(); ++i) {
if (data[i] == QLatin1Char('\\'))
data[i] = QLatin1Char('/');
if (data[i] == nativeSeparator)
data[i] = u'/';
}
return n;
@ -2310,16 +2317,8 @@ static QString qt_cleanPath(const QString &path, bool *ok)
{
if (path.isEmpty())
return path;
QString name = path;
#if defined (Q_OS_WIN)
if (name.startsWith(QLatin1String("\\\\?\\")))
name.remove(0, 4);
#endif
QChar dir_separator = QDir::separator();
if (dir_separator != QLatin1Char('/'))
name.replace(dir_separator, QLatin1Char('/'));
QString name = QDir::fromNativeSeparators(path);
QString ret = qt_normalizePathSegments(name, OSSupportsUncPaths ? QDirPrivate::AllowUncPaths : QDirPrivate::DefaultNormalization, ok);
// Strip away last slash except for root directories

View File

@ -142,12 +142,6 @@ void QFileSystemEntry::resolveFilePath() const
if (m_filePath.isEmpty() && !m_nativeFilePath.isEmpty()) {
#if defined(QFILESYSTEMENTRY_NATIVE_PATH_IS_UTF16)
m_filePath = QDir::fromNativeSeparators(m_nativeFilePath);
#ifdef Q_OS_WIN
if (m_filePath.startsWith(QLatin1String("//?/UNC/")))
m_filePath = m_filePath.remove(2,6);
if (m_filePath.startsWith(QLatin1String("//?/")))
m_filePath = m_filePath.remove(0,4);
#endif
#else
m_filePath = QDir::fromNativeSeparators(QFile::decodeName(m_nativeFilePath));
#endif

View File

@ -78,7 +78,7 @@ typedef int NativeFileHandle;
QTemporaryFileName::QTemporaryFileName(const QString &templateName)
{
// Ensure there is a placeholder mask
QString qfilename = templateName;
QString qfilename = QDir::fromNativeSeparators(templateName);
uint phPos = qfilename.length();
uint phLength = 0;

View File

@ -1269,6 +1269,8 @@ tst_QDir::cleanPath_data()
QTest::newRow("unc-server-up") << "//server/path/.." << "//server";
QTest::newRow("unc-server-above-root") << "//server/.." << "//server/..";
QTest::newRow("longpath") << "\\\\?\\d:\\" << "d:/";
QTest::newRow("unc-network-share") << uR"(\\?\UNC\localhost\c$\tmp.txt)"_qs
<< u"//localhost/c$/tmp.txt"_qs;
#else
QTest::newRow("data15") << "//c:/foo" << "/c:/foo";
#endif // non-windows
@ -1744,6 +1746,8 @@ void tst_QDir::nativeSeparators()
QCOMPARE(QDir::fromNativeSeparators(QLatin1String("/")), QString("/"));
QCOMPARE(QDir::fromNativeSeparators(QLatin1String("\\")), QString("/"));
QCOMPARE(QDir::fromNativeSeparators(QLatin1String("\\\\?\\C:\\")), QString("C:/"));
QCOMPARE(QDir::fromNativeSeparators(uR"(\\?\UNC\localhost\c$\tmp.txt)"_qs),
u"//localhost/c$/tmp.txt"_qs);
#else
QCOMPARE(QDir::toNativeSeparators(QLatin1String("/")), QString("/"));
QCOMPARE(QDir::toNativeSeparators(QLatin1String("\\")), QString("\\"));

View File

@ -104,6 +104,17 @@ void tst_QFileSystemEntry::getSetCheck_data()
<< QString("A:dir\\without\\leading\\backslash.bat")
<< absPrefix + QString("A:\\dir\\without\\leading\\backslash.bat")
<< "A:dir/without/leading/backslash.bat" << "backslash.bat" << "backslash" << "backslash" << "bat" << "bat" << false << false;
QTest::newRow("longpath")
<< uR"(\\?\D:\)"_qs
<< absPrefix + QLatin1String(R"(D:\)")
<< "D:/" << "" << "" << "" << "" << "" << true << false;
QTest::newRow("uncprefix")
<< uR"(\\?\UNC\localhost\C$\tmp.txt)"_qs
<< absPrefix + QLatin1String(R"(UNC\localhost\C$\tmp.txt)")
<< "//localhost/C$/tmp.txt" << "tmp.txt" << "tmp" << "tmp" << "txt" << "txt" << true
<< false;
}
void tst_QFileSystemEntry::getSetCheck()
@ -137,7 +148,7 @@ void tst_QFileSystemEntry::getSetCheck()
QCOMPARE(entry2.isRelative(), relative);
QCOMPARE(entry2.filePath(), filepath);
// Since this entry was created using the native path,
// the object shouldnot change nativeFilePath.
// the object shouldn't change nativeFilePath.
QCOMPARE(entry2.nativeFilePath(), nativeFilePath);
QCOMPARE(entry2.fileName(), filename);
QCOMPARE(entry2.baseName(), baseName);

View File

@ -157,6 +157,12 @@ void tst_QTemporaryDir::fileTemplate_data()
prefix = "qt_" + hanTestText();
QTest::newRow("Chinese") << (prefix + "XXXXXX" + umlautTestText()) << prefix << umlautTestText();
}
#ifdef Q_OS_WIN
const auto tmp = QDir::toNativeSeparators(QDir::tempPath()).sliced(QDir::rootPath().size());
QTest::newRow("UNC") << uR"(\\localhost\C$\)"_qs + tmp + uR"(\UNC.XXXXXX.tmpDir)"_qs
<< "UNC." << ".tmpDir";
#endif
}
void tst_QTemporaryDir::fileTemplate()

View File

@ -206,6 +206,12 @@ void tst_QTemporaryFile::fileTemplate_data()
prefix = "qt_" + hanTestText();
QTest::newRow("Chinese characters") << (prefix + "XXXXXX") << prefix << QString() << QString();
}
#ifdef Q_OS_WIN
const auto tmp = QDir::toNativeSeparators(QDir::tempPath()).sliced(QDir::rootPath().size());
QTest::newRow("UNC") << uR"(\\localhost\C$\)"_qs + tmp + uR"(\QTBUG-74291.XXXXXX.tmpFile)"_qs
<< "QTBUG-74291." << ".tmpFile" << "";
#endif
}
void tst_QTemporaryFile::fileTemplate()