From c14c149b51a1c7bf01e4e039f6e8cf1819e37ca6 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 19 Jul 2016 10:18:39 +0200 Subject: Fix QTemporaryDir to handle Unicode characters on Windows For platforms not providing mkdtemp(), QTemporaryDir relied on an implementation of q_mkdtemp() operating on char *, converting back and forth using QFile::encodeName()/decodeName() when passing the name to QFileSystemEngine. This caused failures on Windows (which uses "System"/Latin1 encoding) for names containing characters outside the Latin1 space. Reimplement q_mkdtemp() to operate on QString, which avoids the conversions altogether and also enables the use of larger character spaces for the pattern. Add tests. Task-number: QTBUG-54810 Change-Id: Ie4323ad73b5beb8a1b8ab81425f73d03c626d58a Reviewed-by: Thiago Macieira --- src/corelib/io/qtemporarydir.cpp | 52 +++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 22 deletions(-) (limited to 'src/corelib/io') diff --git a/src/corelib/io/qtemporarydir.cpp b/src/corelib/io/qtemporarydir.cpp index 71436c6497..d869318e35 100644 --- a/src/corelib/io/qtemporarydir.cpp +++ b/src/corelib/io/qtemporarydir.cpp @@ -44,8 +44,12 @@ #include "qcoreapplication.h" #endif +#if !defined(Q_OS_QNX) && !defined(Q_OS_WIN) &&!defined(Q_OS_ANDROID) +# define USE_SYSTEM_MKDTEMP +#endif + #include // mkdtemp -#if defined(Q_OS_QNX) || defined(Q_OS_WIN) || defined(Q_OS_ANDROID) +#ifndef USE_SYSTEM_MKDTEMP #include #endif @@ -91,8 +95,7 @@ static QString defaultTemplateName() return QDir::tempPath() + QLatin1Char('/') + baseName + QLatin1String("-XXXXXX"); } -#if defined(Q_OS_QNX ) || defined(Q_OS_WIN) || defined(Q_OS_ANDROID) - +#ifndef USE_SYSTEM_MKDTEMP static int nextRand(int &v) { int r = v % 62; @@ -102,30 +105,28 @@ static int nextRand(int &v) return r; } -QPair q_mkdtemp(char *templateName) +QPair q_mkdtemp(QString templateName) { - static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + Q_ASSERT(templateName.endsWith(QLatin1String("XXXXXX"))); - const size_t length = strlen(templateName); + static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - char *XXXXXX = templateName + length - 6; + const int length = templateName.size(); - Q_ASSERT((length >= 6u) && strncmp(XXXXXX, "XXXXXX", 6) == 0); + QChar *XXXXXX = templateName.data() + length - 6; for (int i = 0; i < 256; ++i) { int v = qrand(); /* Fill in the random bits. */ - XXXXXX[0] = letters[nextRand(v)]; - XXXXXX[1] = letters[nextRand(v)]; - XXXXXX[2] = letters[nextRand(v)]; - XXXXXX[3] = letters[nextRand(v)]; - XXXXXX[4] = letters[nextRand(v)]; - XXXXXX[5] = letters[v % 62]; - - QString templateNameStr = QFile::decodeName(templateName); - - QFileSystemEntry fileSystemEntry(templateNameStr); + XXXXXX[0] = QLatin1Char(letters[nextRand(v)]); + XXXXXX[1] = QLatin1Char(letters[nextRand(v)]); + XXXXXX[2] = QLatin1Char(letters[nextRand(v)]); + XXXXXX[3] = QLatin1Char(letters[nextRand(v)]); + XXXXXX[4] = QLatin1Char(letters[nextRand(v)]); + XXXXXX[5] = QLatin1Char(letters[v % 62]); + + QFileSystemEntry fileSystemEntry(templateName); if (QFileSystemEngine::createDirectory(fileSystemEntry, false)) { QSystemError error; QFileSystemEngine::setPermissions(fileSystemEntry, @@ -134,10 +135,10 @@ QPair q_mkdtemp(char *templateName) QFile::ExeOwner, error); if (error.error() != 0) { if (!QFileSystemEngine::removeDirectory(fileSystemEntry, false)) - qWarning() << "Unable to remove unused directory" << templateNameStr; + qWarning() << "Unable to remove unused directory" << templateName; continue; } - return qMakePair(QFile::decodeName(templateName), true); + return qMakePair(templateName, true); } # ifdef Q_OS_WIN const int exists = ERROR_ALREADY_EXISTS; @@ -152,7 +153,7 @@ QPair q_mkdtemp(char *templateName) return qMakePair(qt_error_string(), false); } -#else // defined(Q_OS_QNX ) || defined(Q_OS_WIN) || defined(Q_OS_ANDROID) +#else // !USE_SYSTEM_MKDTEMP QPair q_mkdtemp(char *templateName) { @@ -160,14 +161,21 @@ QPair q_mkdtemp(char *templateName) return qMakePair(ok ? QFile::decodeName(templateName) : qt_error_string(), ok); } -#endif +#endif // USE_SYSTEM_MKDTEMP void QTemporaryDirPrivate::create(const QString &templateName) { +#ifndef USE_SYSTEM_MKDTEMP + QString buffer = templateName; + if (!buffer.endsWith(QLatin1String("XXXXXX"))) + buffer += QLatin1String("XXXXXX"); + const QPair result = q_mkdtemp(buffer); +#else // !USE_SYSTEM_MKDTEMP QByteArray buffer = QFile::encodeName(templateName); if (!buffer.endsWith("XXXXXX")) buffer += "XXXXXX"; QPair result = q_mkdtemp(buffer.data()); // modifies buffer +#endif // USE_SYSTEM_MKDTEMP pathOrError = result.first; success = result.second; } -- cgit v1.2.3 From 0696566b1e19c8178e00c0d14f185935e17d9e8b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 20 Jul 2016 16:49:33 +0200 Subject: Windows: Fix truncation in QFSFileEnginePrivate::nativeWrite() The number of bytes to write was converted to a 32bit unsigned value, causing losses. Change the type to qint64 and adapt the code determining the block size. Task-number: QTBUG-54870 Change-Id: I294da5bfe97c7e60f67228399e1244a1aba4c89c Reviewed-by: Maurice Kalinowski --- src/corelib/io/qfsfileengine_win.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/corelib/io') diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index 689251a6c7..391fbcc519 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -423,15 +423,13 @@ qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len) if (fileHandle == INVALID_HANDLE_VALUE) return -1; - qint64 bytesToWrite = DWORD(len); // <- lossy + qint64 bytesToWrite = len; // Writing on Windows fails with ERROR_NO_SYSTEM_RESOURCES when // the chunks are too large, so we limit the block size to 32MB. - static const DWORD maxBlockSize = 32 * 1024 * 1024; - + const DWORD blockSize = DWORD(qMin(bytesToWrite, qint64(32 * 1024 * 1024))); qint64 totalWritten = 0; do { - DWORD blockSize = qMin(bytesToWrite, maxBlockSize); DWORD bytesWritten; if (!WriteFile(fileHandle, data + totalWritten, blockSize, &bytesWritten, NULL)) { if (totalWritten == 0) { -- cgit v1.2.3