From d69788728ccd843e3d4a372680185fdf5e711c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:35:55 +0200 Subject: Encapsulate pointer manipulations to createFileTemplate function , where we actually control how we use the pointers. Reduce some code duplication in #ifdefs. --- src/corelib/io/qtemporaryfile.cpp | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index d457601..9228f94 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -96,18 +96,22 @@ QT_BEGIN_NAMESPACE \internal Generates a unique file path and returns a native handle to the open file. - \a path is used as a template when generating unique paths, - \a placeholderStart and \a placeholderEnd delimit the sub-string that will - be randomized. + \a path is used as a template when generating unique paths, \a pos + identifies the position of the first character that will be replaced in the + template and \a length the number of characters that may be substituted. Returns an open handle to the newly created file if successful, an invalid handle otherwise. In both cases, the string in \a path will be changed and contain the generated path name. */ -static int createFileFromTemplate(char *const path, - char *const placeholderStart, char *const placeholderEnd) +static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) { - Q_ASSERT(placeholderEnd > placeholderStart); + Q_ASSERT(length != 0); + Q_ASSERT(pos < size_t(path.length())); + Q_ASSERT(length < size_t(path.length()) - pos); + + char *const placeholderStart = path.data() + pos; + char *const placeholderEnd = placeholderStart + length; // Initialize placeholder with random chars + PID. { @@ -134,14 +138,16 @@ static int createFileFromTemplate(char *const path, // Atomically create file and obtain handle #ifndef Q_OS_WIN { - int fd = QT_OPEN(path, QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, 0600); + int fd = QT_OPEN(path.constData(), + QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, + 0600); if (fd != -1) return fd; if (errno != EEXIST) return -1; } #else - if (!QFileInfo(QString::fromLocal8Bit(path)).exists()) + if (!QFileInfo(QString::fromLocal8Bit(path.constData(), path.length())).exists()) return 1; #endif @@ -295,10 +301,9 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) else filename.insert(phPos + phLength, suffix.toLocal8Bit()); - char *path = filename.data(); + int fd = createFileFromTemplate(filename, phPos, phLength); #ifndef Q_OS_WIN - int fd = createFileFromTemplate(path, path + phPos, path + phPos + phLength); if (fd != -1) { // First open the fd as an external file descriptor to // initialize the engine properly. @@ -308,7 +313,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) d->closeFileHandle = true; // Restore the file names (open() resets them). - d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(path, filename.length())); //note that filename is NOT a native path + d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename.constData(), filename.length())); //note that filename is NOT a native path filePathIsTemplate = false; return true; } @@ -318,13 +323,11 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(errno)); return false; #else - if (createFileFromTemplate(path, path + phPos, path + phPos + phLength) == -1) { + if (fd == -1) return false; - } QString template_ = d->fileEntry.filePath(); - d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(path, filename.length())); - + d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename.constData(), filename.length())); if (QFSFileEngine::open(openMode)) { filePathIsTemplate = false; return true; -- cgit v0.12 From 63bb67d3107b03f399cddf4c9cca9c7eb347b62d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:39:53 +0200 Subject: Make Symbian follow Windows code in temporary path generation On the one hand, we stop using OpenC here. On the other, we no longer use an atomic create and obtain file handle API -- just as we don't on Windows yet. This is a stepping stone to removing back and forth conversions of path names when generating unique names and also towards the use of native APIs for creating and obtaining a file handle atomically. Reviewed-by: Gareth Stockwell Reviewed-by: Shane Kearns --- src/corelib/io/qtemporaryfile.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 9228f94..497faad 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -49,12 +49,9 @@ #include "private/qabstractfileengine_p.h" #include "private/qfsfileengine_p.h" -#if !defined(Q_OS_WINCE) -# include -#endif - -#if defined(Q_OS_UNIX) -# include "private/qcore_unix_p.h" // overrides QT_OPEN +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) +#include "private/qcore_unix_p.h" // overrides QT_OPEN +#include #endif #if defined(QT_BUILD_CORE_LIB) @@ -136,7 +133,7 @@ static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) for (;;) { // Atomically create file and obtain handle -#ifndef Q_OS_WIN +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) { int fd = QT_OPEN(path.constData(), QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, @@ -303,7 +300,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) int fd = createFileFromTemplate(filename, phPos, phLength); -#ifndef Q_OS_WIN +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) if (fd != -1) { // First open the fd as an external file descriptor to // initialize the engine properly. -- cgit v0.12 From d71d3b1ce31ffc585258330d825ff8ea535254ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:57:19 +0200 Subject: Use QStringBuilder when copying template for modification This avoids modifying the original string in the case where a placeholder marker is not found. By marking the variable const we further avoid checks on the reference count and detaches, also allowing us to safely reuse it later in the function. The new approach also fixes an issue where suffix wasn't empty, but the toLocal8Bit conversion would be. This resulted in a buffer overflow inside createFileFromTemplate. Reviewed-by: Shane Kearns --- src/corelib/io/qtemporaryfile.cpp | 62 +++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 497faad..b079d3e 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -45,6 +45,7 @@ #include "qplatformdefs.h" #include "qabstractfileengine.h" +#include "qstringbuilder.h" #include "private/qfile_p.h" #include "private/qabstractfileengine_p.h" #include "private/qfsfileengine_p.h" @@ -60,6 +61,38 @@ QT_BEGIN_NAMESPACE +struct Placeholder +{ + Placeholder(int size) + : size_(size) + { + } + + int size() const + { + return size_; + } + +private: + int size_; +}; + +template <> +struct QConcatenable +{ + typedef Placeholder type; + typedef QByteArray ConvertTo; + enum { ExactSize = true }; + static int size(const Placeholder &p) { return p.size(); } + + template + static inline void appendTo(const Placeholder &p, CharT *&out) + { + // Uninitialized + out += p.size(); + } +}; + /* * Copyright (c) 1987, 1993 * The Regents of the University of California. All rights reserved. @@ -258,7 +291,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (!filePathIsTemplate) return QFSFileEngine::open(openMode); - QString qfilename = d->fileEntry.filePath(); + const QString qfilename = d->fileEntry.filePath(); // Find placeholder string. uint phPos = qfilename.length(); @@ -281,22 +314,22 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) phLength = 0; } - QStringRef prefix, suffix; + QByteArray filename; + if (phLength < 6) { - qfilename += QLatin1Char('.'); - prefix = QStringRef(&qfilename); + filename = qfilename.toLocal8Bit(); + + phPos = filename.length() + 1; // Account for added dot in prefix phLength = 6; + filename = filename % '.' % Placeholder(phLength); } else { - prefix = qfilename.leftRef(phPos); - suffix = qfilename.midRef(phPos + phLength); - } + QByteArray prefix, suffix; + prefix = qfilename.leftRef(phPos).toLocal8Bit(); + suffix = qfilename.midRef(phPos + phLength).toLocal8Bit(); - QByteArray filename = prefix.toLocal8Bit(); - phPos = filename.length(); - if (suffix.isEmpty()) - filename.resize(phPos + phLength); - else - filename.insert(phPos + phLength, suffix.toLocal8Bit()); + phPos = prefix.length(); + filename = prefix % Placeholder(phLength) % suffix; + } int fd = createFileFromTemplate(filename, phPos, phLength); @@ -323,14 +356,13 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (fd == -1) return false; - QString template_ = d->fileEntry.filePath(); d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename.constData(), filename.length())); if (QFSFileEngine::open(openMode)) { filePathIsTemplate = false; return true; } - d->fileEntry = QFileSystemEntry(template_, QFileSystemEntry::FromInternalPath()); + d->fileEntry = QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath()); return false; #endif } -- cgit v0.12 From 9a76587363a2f37312326286e08cce502f7fe27e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:58:08 +0200 Subject: Minimize encoding conversions when generating unique file name With minor adjustments, createFileFromTemplate is made to work directly on (UTF-16) QString data, which is already in the native encoding for Windows and Symbian. This is possible because the function only fills out the placeholder sub-string, without touching adjacent characters. This eliminates unnecessary conversions on those platforms. Reviewed-by: Gareth Stockwell Reviewed-by: Shane Kearns --- src/corelib/io/qtemporaryfile.cpp | 69 ++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index b079d3e..e4c53aa 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -61,6 +61,33 @@ QT_BEGIN_NAMESPACE +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +typedef ushort Char; + +static inline Char Latin1Char(char ch) +{ + return ushort(uchar(ch)); +} + +template <> +struct QConcatenable +{ + typedef Char type; + typedef QString ConvertTo; + enum { ExactSize = true }; + static int size(const Char &) { return 1; } + + static inline void appendTo(const Char &u16, QChar *&out) + { + *out++ = QChar(u16); + } +}; + +#else // POSIX +typedef char Char; +typedef char Latin1Char; +#endif + struct Placeholder { Placeholder(int size) @@ -134,23 +161,24 @@ struct QConcatenable handle otherwise. In both cases, the string in \a path will be changed and contain the generated path name. */ -static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) +static int createFileFromTemplate(QFileSystemEntry::NativePath &path, + size_t pos, size_t length) { Q_ASSERT(length != 0); Q_ASSERT(pos < size_t(path.length())); Q_ASSERT(length < size_t(path.length()) - pos); - char *const placeholderStart = path.data() + pos; - char *const placeholderEnd = placeholderStart + length; + Char *const placeholderStart = (Char *)path.data() + pos; + Char *const placeholderEnd = placeholderStart + length; // Initialize placeholder with random chars + PID. { - char *rIter = placeholderEnd; + Char *rIter = placeholderEnd; #if defined(QT_BUILD_CORE_LIB) quint64 pid = quint64(QCoreApplication::applicationPid()); do { - *--rIter = (pid % 10) + '0'; + *--rIter = Latin1Char((pid % 10) + '0'); pid /= 10; } while (rIter != placeholderStart && pid != 0); #endif @@ -158,9 +186,9 @@ static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) while (rIter != placeholderStart) { char ch = char((qrand() & 0xffff) % (26 + 26)); if (ch < 26) - *--rIter = ch + 'A'; + *--rIter = Latin1Char(ch + 'A'); else - *--rIter = ch - 26 + 'a'; + *--rIter = Latin1Char(ch - 26 + 'a'); } } @@ -177,18 +205,18 @@ static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) return -1; } #else - if (!QFileInfo(QString::fromLocal8Bit(path.constData(), path.length())).exists()) + if (!QFileInfo(path).exists()) return 1; #endif /* tricky little algorwwithm for backward compatibility */ - for (char *iter = placeholderStart;;) { + for (Char *iter = placeholderStart;;) { // Character progression: [0-9] => 'a' ... 'z' => 'A' .. 'Z' // String progression: "ZZaiC" => "aabiC" - switch (*iter) { + switch (char(*iter)) { case 'Z': // Rollover, advance next character - *iter = 'a'; + *iter = Latin1Char('a'); if (++iter == placeholderEnd) return -1; @@ -196,12 +224,12 @@ static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - *iter = 'a'; + *iter = Latin1Char('a'); break; case 'z': // increment 'z' to 'A' - *iter = 'A'; + *iter = Latin1Char('A'); break; default: @@ -314,8 +342,9 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) phLength = 0; } - QByteArray filename; + QFileSystemEntry::NativePath filename; +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) if (phLength < 6) { filename = qfilename.toLocal8Bit(); @@ -330,6 +359,16 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) phPos = prefix.length(); filename = prefix % Placeholder(phLength) % suffix; } +#else + if (phLength < 6) { + phPos = qfilename.length() + 1; // Account for added dot in prefix + phLength = 6; + filename = qfilename % Latin1Char('.') % Placeholder(phLength); + } else + filename = qfilename; + + // No native separators, not a "native path" +#endif int fd = createFileFromTemplate(filename, phPos, phLength); @@ -356,7 +395,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (fd == -1) return false; - d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename.constData(), filename.length())); + d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromInternalPath()); if (QFSFileEngine::open(openMode)) { filePathIsTemplate = false; return true; -- cgit v0.12 From ff9b69838ec146aeb43d4af8a03043f9c5f0454d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:45:08 +0200 Subject: Atomic implementation of create file and obtain handle for Win/Symbian Besides generating a unique name, createFileFromTemplate now also acquires a file handle on all platforms. The file engine's native handle is passed by reference and modified in place. This fixes a long standing security issue on Windows. On Windows and Symbian platforms we directly use the "native" file path when processing the template and generating the unique name. Since the native encoding is known, conversions at this point are safe. Errors other than "file exists" are propagated to Q(Temporary)File, and result in a failure in open(). The changes also unify error handling and should give consistent behaviour across all platforms. Worthy of note, there's a change in behaviour on Windows and Symbian: fileNames returned by QTemporaryFile on Windows and Symbian are always absolute after open has been called. This has to do with how QFileSystemEntry::nativeFilePath works on these platforms. (Test was updated to reflect change in behaviour.) Reviewed-by: Gareth Stockwell Reviewed-by: Shane Kearns --- src/corelib/io/qtemporaryfile.cpp | 151 +++++++++++++++-------- tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp | 31 +++-- 2 files changed, 122 insertions(+), 60 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index e4c53aa..cd6ab40 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -49,6 +49,11 @@ #include "private/qfile_p.h" #include "private/qabstractfileengine_p.h" #include "private/qfsfileengine_p.h" +#include "private/qsystemerror_p.h" + +#if defined(Q_OS_SYMBIAN) +#include "private/qcore_symbian_p.h" +#endif #if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) #include "private/qcore_unix_p.h" // overrides QT_OPEN @@ -83,9 +88,20 @@ struct QConcatenable } }; +# ifdef Q_OS_WIN +typedef HANDLE NativeFileHandle; +# else // Q_OS_SYMBIAN +# ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API +typedef RFile64 NativeFileHandle; +# else +typedef RFile NativeFileHandle; +# endif +# endif + #else // POSIX typedef char Char; typedef char Latin1Char; +typedef int NativeFileHandle; #endif struct Placeholder @@ -161,8 +177,9 @@ struct QConcatenable handle otherwise. In both cases, the string in \a path will be changed and contain the generated path name. */ -static int createFileFromTemplate(QFileSystemEntry::NativePath &path, - size_t pos, size_t length) +static bool createFileFromTemplate(NativeFileHandle &file, + QFileSystemEntry::NativePath &path, size_t pos, size_t length, + QSystemError &error) { Q_ASSERT(length != 0); Q_ASSERT(pos < size_t(path.length())); @@ -192,21 +209,50 @@ static int createFileFromTemplate(QFileSystemEntry::NativePath &path, } } +#ifdef Q_OS_SYMBIAN + RFs& fs = qt_s60GetRFs(); +#endif + for (;;) { // Atomically create file and obtain handle -#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - { - int fd = QT_OPEN(path.constData(), - QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, - 0600); - if (fd != -1) - return fd; - if (errno != EEXIST) - return -1; +#if defined(Q_OS_WIN) + file = CreateFile((const wchar_t *)path.constData(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (file != INVALID_HANDLE_VALUE) + return true; + + DWORD err = GetLastError(); + if (err != ERROR_FILE_EXISTS) { + error = QSystemError(err, QSystemError::NativeError); + return false; + } +#elif defined(Q_OS_SYMBIAN) + TInt err = file.Create(fs, qt_QString2TPtrC(path), + EFileRead | EFileWrite | EFileShareReadersOrWriters); + + if (err == KErrNone) + return true; + + if (err != KErrAlreadyExists) { + error = QSystemError(err, QSystemError::NativeError); + return false; + } +#else // POSIX + file = QT_OPEN(path.constData(), + QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, + 0600); + + if (file != -1) + return true; + + int err = errno; + if (err != EEXIST) { + error = QSystemError(err, QSystemError::NativeError); + return false; } -#else - if (!QFileInfo(path).exists()) - return 1; #endif /* tricky little algorwwithm for backward compatibility */ @@ -217,8 +263,11 @@ static int createFileFromTemplate(QFileSystemEntry::NativePath &path, case 'Z': // Rollover, advance next character *iter = Latin1Char('a'); - if (++iter == placeholderEnd) - return -1; + if (++iter == placeholderEnd) { + // Out of alternatives. Return file exists error, previously set. + error = QSystemError(err, QSystemError::NativeError); + return false; + } continue; @@ -319,7 +368,14 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (!filePathIsTemplate) return QFSFileEngine::open(openMode); - const QString qfilename = d->fileEntry.filePath(); + const QString qfilename = +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) + // Since the native encoding is out of our control, we need to process + // the path as UTF-16 before doing any conversions + d->fileEntry.filePath(); +#else + d->fileEntry.nativeFilePath(); +#endif // Find placeholder string. uint phPos = qfilename.length(); @@ -333,8 +389,14 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) continue; } - if (qfilename[phPos] == QLatin1Char('/') - || phLength >= 6) { + if (phLength >= 6 + || qfilename[phPos] == +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) + QLatin1Char('/') +#else + QLatin1Char('\\') +#endif + ) { ++phPos; break; } @@ -366,44 +428,35 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) filename = qfilename % Latin1Char('.') % Placeholder(phLength); } else filename = qfilename; - - // No native separators, not a "native path" #endif - int fd = createFileFromTemplate(filename, phPos, phLength); + QSystemError error; +#if defined(Q_OS_WIN) + NativeFileHandle &file = d->fileHandle; +#elif defined(Q_OS_SYMBIAN) + NativeFileHandle &file = d->symbianFile; +#else // POSIX + NativeFileHandle &file = d->fd; +#endif -#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - if (fd != -1) { - // First open the fd as an external file descriptor to - // initialize the engine properly. - if (QFSFileEngine::open(openMode, fd)) { + if (!createFileFromTemplate(file, filename, phPos, phLength, error)) { + setError(QFile::OpenError, error.toString()); + return false; + } - // Allow the engine to close the handle even if it's "external". - d->closeFileHandle = true; + d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromNativePath()); - // Restore the file names (open() resets them). - d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename.constData(), filename.length())); //note that filename is NOT a native path - filePathIsTemplate = false; - return true; - } +#if !defined(Q_OS_WIN) + d->closeFileHandle = true; +#endif - QT_CLOSE(fd); - } - setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(errno)); - return false; -#else - if (fd == -1) - return false; + filePathIsTemplate = false; - d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromInternalPath()); - if (QFSFileEngine::open(openMode)) { - filePathIsTemplate = false; - return true; - } + d->openMode = openMode; + d->lastFlushFailed = false; + d->tried_stat = 0; - d->fileEntry = QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath()); - return false; -#endif + return true; } bool QTemporaryFileEngine::remove() diff --git a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp index 2edb93a..05fee95 100644 --- a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp @@ -201,11 +201,12 @@ void tst_QTemporaryFile::fileTemplate() QCOMPARE(file.open(), true); + QString fileName = QFileInfo(file).fileName(); if (prefix.length()) - QCOMPARE(file.fileName().left(prefix.length()), prefix); + QCOMPARE(fileName.left(prefix.length()), prefix); if (suffix.length()) - QCOMPARE(file.fileName().right(suffix.length()), suffix); + QCOMPARE(fileName.right(suffix.length()), suffix); } @@ -701,20 +702,28 @@ void tst_QTemporaryFile::QTBUG_4796() << file5.fileName() << file6.fileName(); - QVERIFY(file1.fileName().startsWith(fileTemplate1 + QLatin1Char('.'))); - QVERIFY(file2.fileName().startsWith(fileTemplate2 + QLatin1Char('.'))); - QVERIFY(file5.fileName().startsWith("test-XXXXXX/" + fileTemplate1 + QLatin1Char('.'))); - QVERIFY(file6.fileName().startsWith("test-XXXXXX/" + prefix)); + QDir currentDir; + QString fileName1 = currentDir.relativeFilePath(file1.fileName()); + QString fileName2 = currentDir.relativeFilePath(file2.fileName()); + QString fileName3 = currentDir.relativeFilePath(file3.fileName()); + QString fileName4 = currentDir.relativeFilePath(file4.fileName()); + QString fileName5 = currentDir.relativeFilePath(file5.fileName()); + QString fileName6 = currentDir.relativeFilePath(file6.fileName()); + + QVERIFY(fileName1.startsWith(fileTemplate1 + QLatin1Char('.'))); + QVERIFY(fileName2.startsWith(fileTemplate2 + QLatin1Char('.'))); + QVERIFY(fileName5.startsWith("test-XXXXXX/" + fileTemplate1 + QLatin1Char('.'))); + QVERIFY(fileName6.startsWith("test-XXXXXX/" + prefix)); if (!prefix.isEmpty()) { - QVERIFY(file3.fileName().startsWith(prefix)); - QVERIFY(file4.fileName().startsWith(prefix)); + QVERIFY(fileName3.startsWith(prefix)); + QVERIFY(fileName4.startsWith(prefix)); } if (!suffix.isEmpty()) { - QVERIFY(file3.fileName().endsWith(suffix)); - QVERIFY(file4.fileName().endsWith(suffix)); - QVERIFY(file6.fileName().endsWith(suffix)); + QVERIFY(fileName3.endsWith(suffix)); + QVERIFY(fileName4.endsWith(suffix)); + QVERIFY(fileName6.endsWith(suffix)); } } } -- cgit v0.12 From d95da2fc82cdd7e5157460157b0895c209852897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Tue, 16 Aug 2011 16:02:47 +0200 Subject: Add output on test failure Reviewed-by: Shane Kearns --- tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp | 43 ++++++++++++++---------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp index 05fee95..2db5c60 100644 --- a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp @@ -412,11 +412,11 @@ void tst_QTemporaryFile::rename() { QTemporaryFile file(dir.filePath("temporary-file.XXXXXX")); - QVERIFY(file.open()); + QVERIFY2(file.open(), qPrintable(file.errorString())); tempname = file.fileName(); QVERIFY(dir.exists(tempname)); - QVERIFY(file.rename("temporary-file.txt")); + QVERIFY2(file.rename("temporary-file.txt"), qPrintable(file.errorString())); QVERIFY(!dir.exists(tempname)); QVERIFY(dir.exists("temporary-file.txt")); QCOMPARE(file.fileName(), QString("temporary-file.txt")); @@ -679,12 +679,21 @@ void tst_QTemporaryFile::QTBUG_4796() QTemporaryFile file5("test-XXXXXX/" + fileTemplate1); QTemporaryFile file6("test-XXXXXX/" + fileTemplate3); - QCOMPARE(file1.open(), openResult); - QCOMPARE(file2.open(), openResult); - QCOMPARE(file3.open(), openResult); - QCOMPARE(file4.open(), openResult); - QCOMPARE(file5.open(), openResult); - QCOMPARE(file6.open(), openResult); + if (openResult) { + QVERIFY2(file1.open(), qPrintable(file1.errorString())); + QVERIFY2(file2.open(), qPrintable(file2.errorString())); + QVERIFY2(file3.open(), qPrintable(file3.errorString())); + QVERIFY2(file4.open(), qPrintable(file4.errorString())); + QVERIFY2(file5.open(), qPrintable(file5.errorString())); + QVERIFY2(file6.open(), qPrintable(file6.errorString())); + } else { + QVERIFY(!file1.open()); + QVERIFY(!file2.open()); + QVERIFY(!file3.open()); + QVERIFY(!file4.open()); + QVERIFY(!file5.open()); + QVERIFY(!file6.open()); + } QCOMPARE(file1.exists(), openResult); QCOMPARE(file2.exists(), openResult); @@ -710,20 +719,20 @@ void tst_QTemporaryFile::QTBUG_4796() QString fileName5 = currentDir.relativeFilePath(file5.fileName()); QString fileName6 = currentDir.relativeFilePath(file6.fileName()); - QVERIFY(fileName1.startsWith(fileTemplate1 + QLatin1Char('.'))); - QVERIFY(fileName2.startsWith(fileTemplate2 + QLatin1Char('.'))); - QVERIFY(fileName5.startsWith("test-XXXXXX/" + fileTemplate1 + QLatin1Char('.'))); - QVERIFY(fileName6.startsWith("test-XXXXXX/" + prefix)); + QVERIFY2(fileName1.startsWith(fileTemplate1 + QLatin1Char('.')), qPrintable(file1.fileName())); + QVERIFY2(fileName2.startsWith(fileTemplate2 + QLatin1Char('.')), qPrintable(file2.fileName())); + QVERIFY2(fileName5.startsWith("test-XXXXXX/" + fileTemplate1 + QLatin1Char('.')), qPrintable(file5.fileName())); + QVERIFY2(fileName6.startsWith("test-XXXXXX/" + prefix), qPrintable(file6.fileName())); if (!prefix.isEmpty()) { - QVERIFY(fileName3.startsWith(prefix)); - QVERIFY(fileName4.startsWith(prefix)); + QVERIFY2(fileName3.startsWith(prefix), qPrintable(file3.fileName())); + QVERIFY2(fileName4.startsWith(prefix), qPrintable(file4.fileName())); } if (!suffix.isEmpty()) { - QVERIFY(fileName3.endsWith(suffix)); - QVERIFY(fileName4.endsWith(suffix)); - QVERIFY(fileName6.endsWith(suffix)); + QVERIFY2(fileName3.endsWith(suffix), qPrintable(file3.fileName())); + QVERIFY2(fileName4.endsWith(suffix), qPrintable(file4.fileName())); + QVERIFY2(fileName6.endsWith(suffix), qPrintable(file6.fileName())); } } } -- cgit v0.12 From a153d50eea2dea0925695a90af2c12f1887a9020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:47:01 +0200 Subject: Cleanup #includes These are already required and included by qfsfileengine_p.h. --- src/corelib/io/qtemporaryfile.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index cd6ab40..9f7cde2 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -44,10 +44,8 @@ #ifndef QT_NO_TEMPORARYFILE #include "qplatformdefs.h" -#include "qabstractfileengine.h" #include "qstringbuilder.h" #include "private/qfile_p.h" -#include "private/qabstractfileengine_p.h" #include "private/qfsfileengine_p.h" #include "private/qsystemerror_p.h" -- cgit v0.12 From 0de701d01cb221464eed773fd3751aff73fe4d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:49:44 +0200 Subject: Use "native paths" on POSIX platforms as well And don't rely solely on "local8Bit" conversions. QFile defines an API for overriding how encoding conversions are done for filenames. In generating unique names, QTemporaryFile ignored that API and hardcoded the use of local 8-bit, implicitly assuming that that was appropriate. With this change, we switch that assumption to one where user supplied encoding function keeps the byte value of 'X' and '/', also assuming that encoded 'X' takes up a single-byte (i.e., the byte sequence for "XXXXXX" remains unchanged). There was also, and there still is an assumption in name generation that byte values for ASCII alpha-numeric characters are valid in the "native" encoding. In practice this change is compatible with UTF-8, Latin-1 and other ISO/IEC 8859 encodings. At any rate, it's very likely that only UTF-8 is relevant here. Reviewed-by: Denis Dzyubenko --- src/corelib/io/qtemporaryfile.cpp | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 9f7cde2..ac5deac 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -366,14 +366,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (!filePathIsTemplate) return QFSFileEngine::open(openMode); - const QString qfilename = -#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - // Since the native encoding is out of our control, we need to process - // the path as UTF-16 before doing any conversions - d->fileEntry.filePath(); -#else - d->fileEntry.nativeFilePath(); -#endif + const QFileSystemEntry::NativePath qfilename = d->fileEntry.nativeFilePath(); // Find placeholder string. uint phPos = qfilename.length(); @@ -382,7 +375,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) while (phPos != 0) { --phPos; - if (qfilename[phPos] == QLatin1Char('X')) { + if (qfilename[phPos] == Latin1Char('X')) { ++phLength; continue; } @@ -390,7 +383,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (phLength >= 6 || qfilename[phPos] == #if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - QLatin1Char('/') + '/' #else QLatin1Char('\\') #endif @@ -404,29 +397,12 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) QFileSystemEntry::NativePath filename; -#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - if (phLength < 6) { - filename = qfilename.toLocal8Bit(); - - phPos = filename.length() + 1; // Account for added dot in prefix - phLength = 6; - filename = filename % '.' % Placeholder(phLength); - } else { - QByteArray prefix, suffix; - prefix = qfilename.leftRef(phPos).toLocal8Bit(); - suffix = qfilename.midRef(phPos + phLength).toLocal8Bit(); - - phPos = prefix.length(); - filename = prefix % Placeholder(phLength) % suffix; - } -#else if (phLength < 6) { phPos = qfilename.length() + 1; // Account for added dot in prefix phLength = 6; filename = qfilename % Latin1Char('.') % Placeholder(phLength); } else filename = qfilename; -#endif QSystemError error; #if defined(Q_OS_WIN) -- cgit v0.12 From 401722ef9e6fe79bd41f9d5f79668f5c4997c8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Tue, 16 Aug 2011 17:53:41 +0200 Subject: Fix QTemporaryFile regressions and new found issues With this change, the file template is always processed in original QString format. Trying to generate native paths before adding a missing placeholder mask could change the meaning of templates, such as "." and "..", which are now tested to mean "..XXXXXX" and "...XXXXXX", respectively. After ensuring the template includes a placeholder mask, the path is converted to a native *absolute* file path and the mask is sought for again. On Windows, native paths were already absolute. On Symbian, we'd need at least a clean path, as "." and ",," are not natively understood. There is a requirement that the placeholder mask /XXXXXX+/ makes it through this conversion unaltered, which relaxes prior requirements on *nix platforms. On Windows and Symbian the conversion is under Qt's control and not user-configurable. Reviewed-by: Shane Kearns --- src/corelib/io/qtemporaryfile.cpp | 84 ++++++++++-------------- tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp | 2 + 2 files changed, 36 insertions(+), 50 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index ac5deac..375d07f 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -44,10 +44,10 @@ #ifndef QT_NO_TEMPORARYFILE #include "qplatformdefs.h" -#include "qstringbuilder.h" #include "private/qfile_p.h" #include "private/qfsfileengine_p.h" #include "private/qsystemerror_p.h" +#include "private/qfilesystemengine_p.h" #if defined(Q_OS_SYMBIAN) #include "private/qcore_symbian_p.h" @@ -102,38 +102,6 @@ typedef char Latin1Char; typedef int NativeFileHandle; #endif -struct Placeholder -{ - Placeholder(int size) - : size_(size) - { - } - - int size() const - { - return size_; - } - -private: - int size_; -}; - -template <> -struct QConcatenable -{ - typedef Placeholder type; - typedef QByteArray ConvertTo; - enum { ExactSize = true }; - static int size(const Placeholder &p) { return p.size(); } - - template - static inline void appendTo(const Placeholder &p, CharT *&out) - { - // Uninitialized - out += p.size(); - } -}; - /* * Copyright (c) 1987, 1993 * The Regents of the University of California. All rights reserved. @@ -366,43 +334,59 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (!filePathIsTemplate) return QFSFileEngine::open(openMode); - const QFileSystemEntry::NativePath qfilename = d->fileEntry.nativeFilePath(); + QString qfilename = d->fileEntry.filePath(); - // Find placeholder string. + // Ensure there is a placeholder mask uint phPos = qfilename.length(); uint phLength = 0; while (phPos != 0) { --phPos; - if (qfilename[phPos] == Latin1Char('X')) { + if (qfilename[phPos] == QLatin1Char('X')) { ++phLength; continue; } if (phLength >= 6 - || qfilename[phPos] == -#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - '/' -#else - QLatin1Char('\\') -#endif - ) { + || qfilename[phPos] == QLatin1Char('/')) { ++phPos; break; } + // start over phLength = 0; } - QFileSystemEntry::NativePath filename; + if (phLength < 6) + qfilename.append(QLatin1String(".XXXXXX")); + + // "Nativify" :-) + QFileSystemEntry::NativePath filename = QFileSystemEngine::absoluteName( + QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath())) + .nativeFilePath(); + + // Find mask in native path + phPos = filename.length(); + phLength = 0; + while (phPos != 0) { + --phPos; + + if (filename[phPos] == Latin1Char('X')) { + ++phLength; + continue; + } + + if (phLength >= 6) { + ++phPos; + break; + } + + // start over + phLength = 0; + } - if (phLength < 6) { - phPos = qfilename.length() + 1; // Account for added dot in prefix - phLength = 6; - filename = qfilename % Latin1Char('.') % Placeholder(phLength); - } else - filename = qfilename; + Q_ASSERT(phLength >= 6); QSystemError error; #if defined(Q_OS_WIN) diff --git a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp index 2db5c60..18b9337 100644 --- a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp @@ -632,6 +632,8 @@ void tst_QTemporaryFile::QTBUG_4796_data() QString unicode = QString::fromUtf8("\xc3\xa5\xc3\xa6\xc3\xb8"); QTest::newRow("") << QString() << QString() << true; + QTest::newRow(".") << QString(".") << QString() << true; + QTest::newRow("..") << QString("..") << QString() << true; QTest::newRow("blaXXXXXX") << QString("bla") << QString() << true; QTest::newRow("XXXXXXbla") << QString() << QString("bla") << true; QTest::newRow("does-not-exist/qt_temp.XXXXXX") << QString("does-not-exist/qt_temp") << QString() << false; -- cgit v0.12 From 98f0e52547f6f840e386740dc6c2d99452965266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Wed, 17 Aug 2011 14:38:27 +0200 Subject: Cleanup code: removing empty stubs Reviewed-by: Shane Kearns --- tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp | 29 ------------------------ 1 file changed, 29 deletions(-) diff --git a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp index 18b9337..11b2bb3 100644 --- a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp @@ -69,13 +69,7 @@ class tst_QTemporaryFile : public QObject { Q_OBJECT -public: - tst_QTemporaryFile(); - virtual ~tst_QTemporaryFile(); public slots: - void init(); - void cleanup(); - void initTestCase(); void cleanupTestCase(); @@ -103,8 +97,6 @@ private slots: void QTBUG_4796_data(); void QTBUG_4796(); - -public: }; void tst_QTemporaryFile::initTestCase() @@ -139,27 +131,6 @@ void tst_QTemporaryFile::getSetCheck() QCOMPARE(true, obj1.autoRemove()); } -tst_QTemporaryFile::tst_QTemporaryFile() -{ -} - -tst_QTemporaryFile::~tst_QTemporaryFile() -{ - -} - -void tst_QTemporaryFile::init() -{ -// TODO: Add initialization code here. -// This will be executed immediately before each test is run. -} - -void tst_QTemporaryFile::cleanup() -{ -// TODO: Add cleanup code here. -// This will be executed immediately after each test is run. -} - void tst_QTemporaryFile::fileTemplate_data() { QTest::addColumn("constructorTemplate"); -- cgit v0.12 From 4e2b245df03b79df272318092a63a4a3708ba3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Wed, 17 Aug 2011 14:43:18 +0200 Subject: Merged fileTemplate test with QTBUG_4796 The latter was more thorough, but didn't test setting the file template after construction, while the former included some prefix/suffix combinations that weren't specifically tested in the latter. Reviewed-by: Shane Kearns --- tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp | 116 ++++++++++------------- 1 file changed, 48 insertions(+), 68 deletions(-) diff --git a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp index 11b2bb3..c9d4ba4 100644 --- a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp @@ -94,20 +94,17 @@ private slots: void resetTemplateAfterError(); void setTemplateAfterOpen(); void autoRemoveAfterFailedRename(); - - void QTBUG_4796_data(); - void QTBUG_4796(); }; void tst_QTemporaryFile::initTestCase() { - // For QTBUG_4796 + // For fileTemplate tests QVERIFY(QDir("test-XXXXXX").exists() || QDir().mkdir("test-XXXXXX")); } void tst_QTemporaryFile::cleanupTestCase() { - // From QTBUG_4796 + // From fileTemplate tests QVERIFY(QDir().rmdir("test-XXXXXX")); } @@ -131,56 +128,6 @@ void tst_QTemporaryFile::getSetCheck() QCOMPARE(true, obj1.autoRemove()); } -void tst_QTemporaryFile::fileTemplate_data() -{ - QTest::addColumn("constructorTemplate"); - QTest::addColumn("prefix"); - QTest::addColumn("suffix"); - QTest::addColumn("fileTemplate"); - - QTest::newRow("constructor default") << "" << "." << "" << ""; - QTest::newRow("constructor with xxx sufix") << "qt_XXXXXXxxx" << "qt_" << "xxx" << ""; - QTest::newRow("constructor with xXx sufix") << "qt_XXXXXXxXx" << "qt_" << "xXx" << ""; - QTest::newRow("constructor with no sufix") << "qt_XXXXXX" << "qt_" << "" << ""; - QTest::newRow("constructor with >6 X's and xxx suffix") << "qt_XXXXXXXXXXxxx" << "qt_" << "xxx" << ""; - QTest::newRow("constructor with >6 X's, no suffix") << "qt_XXXXXXXXXX" << "qt_" << "" << ""; - - QTest::newRow("constructor with XXXX suffix") << "qt_XXXXXX_XXXX" << "qt_" << "_XXXX" << ""; - QTest::newRow("constructor with XXXXX suffix") << "qt_XXXXXX_XXXXX" << "qt_" << "_XXXXX" << ""; - QTest::newRow("constructor with XXXX prefix") << "qt_XXXX" << "qt_XXXX." << "" << ""; - QTest::newRow("constructor with XXXXX prefix") << "qt_XXXXX" << "qt_XXXXX." << "" << ""; - QTest::newRow("constructor with XXXX prefix and suffix") << "qt_XXXX_XXXXXX_XXXX" << "qt_XXXX_" << "_XXXX" << ""; - QTest::newRow("constructor with XXXXX prefix and suffix") << "qt_XXXXX_XXXXXX_XXXXX" << "qt_XXXXX_" << "_XXXXX" << ""; - - QTest::newRow("set template, no suffix") << "" << "foo" << "" << "foo"; - QTest::newRow("set template, with lowercase XXXXXX") << "" << "qt_" << "xxxxxx" << "qt_XXXXXXxxxxxx"; - QTest::newRow("set template, with xxx") << "" << "qt_" << ".xxx" << "qt_XXXXXX.xxx"; - QTest::newRow("set template, with >6 X's") << "" << "qt_" << ".xxx" << "qt_XXXXXXXXXXXXXX.xxx"; - QTest::newRow("set template, with >6 X's, no suffix") << "" << "qt_" << "" << "qt_XXXXXXXXXXXXXX"; -} - -void tst_QTemporaryFile::fileTemplate() -{ - QFETCH(QString, constructorTemplate); - QFETCH(QString, prefix); - QFETCH(QString, suffix); - QFETCH(QString, fileTemplate); - - QTemporaryFile file(constructorTemplate); - if (!fileTemplate.isEmpty()) - file.setFileTemplate(fileTemplate); - - QCOMPARE(file.open(), true); - - QString fileName = QFileInfo(file).fileName(); - if (prefix.length()) - QCOMPARE(fileName.left(prefix.length()), prefix); - - if (suffix.length()) - QCOMPARE(fileName.right(suffix.length()), suffix); -} - - /* This tests whether the temporary file really gets placed in QDir::tempPath */ @@ -594,7 +541,7 @@ void tst_QTemporaryFile::autoRemoveAfterFailedRename() cleaner.reset(); } -void tst_QTemporaryFile::QTBUG_4796_data() +void tst_QTemporaryFile::fileTemplate_data() { QTest::addColumn("prefix"); QTest::addColumn("suffix"); @@ -603,17 +550,33 @@ void tst_QTemporaryFile::QTBUG_4796_data() QString unicode = QString::fromUtf8("\xc3\xa5\xc3\xa6\xc3\xb8"); QTest::newRow("") << QString() << QString() << true; + QTest::newRow(".") << QString(".") << QString() << true; QTest::newRow("..") << QString("..") << QString() << true; + + QTest::newRow("foo") << QString("foo") << QString() << true; + QTest::newRow("qt_ ... xxxxxx") << QString("qt_") << QString("xxxxxx") << true; + QTest::newRow("qt_ ... xxx") << QString("qt_") << QString("xxx") << true; + QTest::newRow("qt_ ... xXx") << QString("qt_") << QString("xXx") << true; + QTest::newRow("qt_ ...") << QString("qt_") << QString() << true; + QTest::newRow("qt_ ... _XXXX") << QString("qt_") << QString("_XXXX") << true; + QTest::newRow("qt_ ... _XXXXX") << QString("qt_") << QString("_XXXXX") << true; + QTest::newRow("qt_XXXX_ ...") << QString("qt_XXXX_") << QString() << true; + QTest::newRow("qt_XXXXX_ ...") << QString("qt_XXXXX_") << QString() << true; + QTest::newRow("qt_XXXX_ ... _XXXX") << QString("qt_XXXX_") << QString("_XXXX") << true; + QTest::newRow("qt_XXXXX_ ... _XXXXX") << QString("qt_XXXXX_") << QString("_XXXXX") << true; + QTest::newRow("blaXXXXXX") << QString("bla") << QString() << true; QTest::newRow("XXXXXXbla") << QString() << QString("bla") << true; + QTest::newRow("does-not-exist/qt_temp.XXXXXX") << QString("does-not-exist/qt_temp") << QString() << false; + QTest::newRow("XXXXXX") << QString() << unicode << true; QTest::newRow("XXXXXX") << unicode << QString() << true; QTest::newRow("XXXXXX") << unicode << unicode << true; } -void tst_QTemporaryFile::QTBUG_4796() +void tst_QTemporaryFile::fileTemplate() { QVERIFY(QDir("test-XXXXXX").exists()); @@ -639,18 +602,40 @@ void tst_QTemporaryFile::QTBUG_4796() QFETCH(QString, suffix); QFETCH(bool, openResult); + enum IterationType { + UseConstructor, + UseSetFileTemplate, + Done + }; + + for (IterationType setFileTemplate = UseConstructor; setFileTemplate != Done; + setFileTemplate = IterationType(int(setFileTemplate) + 1)) { + Q_FOREACH(QString const &tempName, cleaner.tempNames) + QVERIFY( !QFile::exists(tempName) ); + + cleaner.reset(); + QString fileTemplate1 = prefix + QString("XX") + suffix; QString fileTemplate2 = prefix + QString("XXXX") + suffix; QString fileTemplate3 = prefix + QString("XXXXXX") + suffix; QString fileTemplate4 = prefix + QString("XXXXXXXX") + suffix; - QTemporaryFile file1(fileTemplate1); - QTemporaryFile file2(fileTemplate2); - QTemporaryFile file3(fileTemplate3); - QTemporaryFile file4(fileTemplate4); - QTemporaryFile file5("test-XXXXXX/" + fileTemplate1); - QTemporaryFile file6("test-XXXXXX/" + fileTemplate3); + QTemporaryFile file1(setFileTemplate ? QString() : fileTemplate1); + QTemporaryFile file2(setFileTemplate ? QString() : fileTemplate2); + QTemporaryFile file3(setFileTemplate ? QString() : fileTemplate3); + QTemporaryFile file4(setFileTemplate ? QString() : fileTemplate4); + QTemporaryFile file5(setFileTemplate ? QString() : "test-XXXXXX/" + fileTemplate1); + QTemporaryFile file6(setFileTemplate ? QString() : "test-XXXXXX/" + fileTemplate3); + + if (setFileTemplate) { + file1.setFileTemplate(fileTemplate1); + file2.setFileTemplate(fileTemplate2); + file3.setFileTemplate(fileTemplate3); + file4.setFileTemplate(fileTemplate4); + file5.setFileTemplate("test-XXXXXX/" + fileTemplate1); + file6.setFileTemplate("test-XXXXXX/" + fileTemplate3); + } if (openResult) { QVERIFY2(file1.open(), qPrintable(file1.errorString())); @@ -709,11 +694,6 @@ void tst_QTemporaryFile::QTBUG_4796() } } } - - Q_FOREACH(QString const &tempName, cleaner.tempNames) - QVERIFY( !QFile::exists(tempName) ); - - cleaner.reset(); } QTEST_MAIN(tst_QTemporaryFile) -- cgit v0.12 From 9e656ce0f7bda4bca4ae55a7aefe1617bc2805ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 18 Aug 2011 11:08:26 +0200 Subject: Leftovers from 401722ef9e6fe79bd41f9d5f79668f5c4997c8e6 This no longer necessary template specialization went unnoticed inside the Windows/Symbian #ifdef. It breaks compilation on those platforms, now that qstringbuilder.h is not included and QConcatenable is unknown to the compiler. --- src/corelib/io/qtemporaryfile.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 375d07f..ea5f8a5 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -72,20 +72,6 @@ static inline Char Latin1Char(char ch) return ushort(uchar(ch)); } -template <> -struct QConcatenable -{ - typedef Char type; - typedef QString ConvertTo; - enum { ExactSize = true }; - static int size(const Char &) { return 1; } - - static inline void appendTo(const Char &u16, QChar *&out) - { - *out++ = QChar(u16); - } -}; - # ifdef Q_OS_WIN typedef HANDLE NativeFileHandle; # else // Q_OS_SYMBIAN -- cgit v0.12 From 7b693627ee2a17718cb6d8bee5e3deb5a97b307f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Mon, 22 Aug 2011 11:30:26 +0200 Subject: Off-by-one error in assert condition... While this was safe, it was also over-zealous, disallowing the path from ending with the placeholder... Incidentally, the default. Laughed-at-by: w00t_ --- src/corelib/io/qtemporaryfile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index ea5f8a5..e80a8b6 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -135,7 +135,7 @@ static bool createFileFromTemplate(NativeFileHandle &file, { Q_ASSERT(length != 0); Q_ASSERT(pos < size_t(path.length())); - Q_ASSERT(length < size_t(path.length()) - pos); + Q_ASSERT(length <= size_t(path.length()) - pos); Char *const placeholderStart = (Char *)path.data() + pos; Char *const placeholderEnd = placeholderStart + length; -- cgit v0.12 From dcee6e1371d899eb79717b8e3f3eec08b765db82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 11 Aug 2011 15:49:37 +0200 Subject: Fix QDir::operator==(const QDir &) const We can't rely on absolute paths when comparing directories for equality as these don't take into account symbolic links and may also bypass ../ and ./ simplification. Instead, canonical paths must be computed and can then be compared according to the case sensitivity rules for the platform or file engine, as is done in QFileInfo. Task-number: QTBUG-20495 Reviewed-by: Prasanth Ullattil --- src/corelib/io/qdir.cpp | 6 +++--- src/corelib/io/qfileinfo.cpp | 1 + tests/auto/qdir/tst_qdir.cpp | 6 ++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index f9196e0..6e25d91 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -1633,9 +1633,9 @@ bool QDir::operator==(const QDir &dir) const if (d->filters == other->filters && d->sort == other->sort && d->nameFilters == other->nameFilters) { - d->resolveAbsoluteEntry(); - other->resolveAbsoluteEntry(); - return d->absoluteDirEntry.filePath().compare(other->absoluteDirEntry.filePath(), sensitive) == 0; + + // Fallback to expensive canonical path computation + return canonicalPath().compare(dir.canonicalPath(), sensitive) == 0; } return false; } diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index ca42c87..6e25206 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -406,6 +406,7 @@ bool QFileInfo::operator==(const QFileInfo &fileinfo) const if (fileinfo.size() != size()) //if the size isn't the same... return false; + // Fallback to expensive canonical path computation return canonicalFilePath().compare(fileinfo.canonicalFilePath(), sensitive) == 0; } diff --git a/tests/auto/qdir/tst_qdir.cpp b/tests/auto/qdir/tst_qdir.cpp index 0a42a97..419eaae 100644 --- a/tests/auto/qdir/tst_qdir.cpp +++ b/tests/auto/qdir/tst_qdir.cpp @@ -444,9 +444,15 @@ void tst_QDir::QDir_default() void tst_QDir::compare() { // operator== + + // Not using QCOMPARE to test result of QDir::operator== + QDir dir; dir.makeAbsolute(); QVERIFY(dir == QDir::currentPath()); + + QVERIFY(QDir() == QDir(QDir::currentPath())); + QVERIFY(QDir("../") == QDir(QDir::currentPath() + "/..")); } static QStringList filterLinks(const QStringList &list) -- cgit v0.12 From 664abe11efdbf582a5433abccf0d8c6fdbe2b040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 11 Aug 2011 16:17:40 +0200 Subject: Compare non-canonical paths before falling back on expensive computation Reviewed-by: Prasanth Ullattil --- src/corelib/io/qdir.cpp | 4 ++++ src/corelib/io/qfileinfo.cpp | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 6e25d91..c0c62e1 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -1634,6 +1634,10 @@ bool QDir::operator==(const QDir &dir) const && d->sort == other->sort && d->nameFilters == other->nameFilters) { + // Assume directories are the same if path is the same + if (d->dirEntry.filePath() == other->dirEntry.filePath()) + return true; + // Fallback to expensive canonical path computation return canonicalPath().compare(dir.canonicalPath(), sensitive) == 0; } diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 6e25206..ff328da 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -391,6 +391,11 @@ bool QFileInfo::operator==(const QFileInfo &fileinfo) const return true; if (d->isDefaultConstructed || fileinfo.d_ptr->isDefaultConstructed) return false; + + // Assume files are the same if path is the same + if (d->fileEntry.filePath() == fileinfo.d_ptr->fileEntry.filePath()) + return true; + Qt::CaseSensitivity sensitive; if (d->fileEngine == 0 || fileinfo.d_ptr->fileEngine == 0) { if (d->fileEngine != fileinfo.d_ptr->fileEngine) // one is native, the other is a custom file-engine -- cgit v0.12 From 07afddbf4bc029f776810381c7317fffa100eb60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 10:39:52 +0200 Subject: Don't second-guess the "engine"; call cleanPath on absolutePaths This ensures there is a single definition of what constitutes an absolute path in Qt. Task-number: QTBUG-19995 Reviewed-by: Prasanth Ullattil --- src/corelib/io/qdir.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index c0c62e1..cbe635f 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -197,16 +197,10 @@ inline void QDirPrivate::resolveAbsoluteEntry() const return; QString absoluteName; - if (fileEngine.isNull()) { - if (!dirEntry.isRelative()) { - absoluteDirEntry = dirEntry; - return; - } - + if (fileEngine.isNull()) absoluteName = QFileSystemEngine::absoluteName(dirEntry).filePath(); - } else { + else absoluteName = fileEngine->fileName(QAbstractFileEngine::AbsoluteName); - } absoluteDirEntry = QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath()); } -- cgit v0.12 From 13899108ed57548d3c4f40e595481f8ee76e4fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 11:03:55 +0200 Subject: We prefer capitalized drive letters, make it so sooner Reviewed-by: Prasanth Ullattil --- src/corelib/io/qfilesystemengine_win.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index f704fc3..993c946 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -1052,11 +1052,12 @@ QString QFileSystemEngine::tempPath() } if (ret.isEmpty()) { #if !defined(Q_OS_WINCE) - ret = QLatin1String("c:/tmp"); + ret = QLatin1String("C:/tmp"); #else ret = QLatin1String("/Temp"); #endif - } + } else if (ret.length() >= 2 && ret[1] == QLatin1Char(':')) + ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters. return ret; } -- cgit v0.12 From d4aa1777389f41da60a862a8c371d13839938d43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 11:01:48 +0200 Subject: ret is an "internal" path, no need to re-process it Where "internal" means that it uses Qt's separator '/', regardless of the native one. --- src/corelib/io/qfilesystemengine_win.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index 993c946..764ee6d 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -536,7 +536,7 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry) // Force uppercase drive letters. ret[0] = ret.at(0).toUpper(); } - return QFileSystemEntry(ret); + return QFileSystemEntry(ret, QFileSystemEntry::FromInternalPath()); } //static -- cgit v0.12 From 2e32fca2c0f5252864d348df929d9858486763b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 17:09:01 +0200 Subject: In 4.7 QFileInfo::absolute(File)Path returned clean paths Let's play nice and keep that "feature". Task-number: QTBUG-19995 --- src/corelib/io/qfileinfo.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index ff328da..e317d1e 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -76,7 +76,9 @@ QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const break; case QAbstractFileEngine::AbsoluteName: case QAbstractFileEngine::AbsolutePathName: { - QFileSystemEntry entry = QFileSystemEngine::absoluteName(fileEntry); + QFileSystemEntry entry = QFileSystemEntry( + QDir::cleanPath(QFileSystemEngine::absoluteName(fileEntry).filePath()), + QFileSystemEntry::FromInternalPath()); if (cache_enabled) { // be smart and store both fileNames[QAbstractFileEngine::AbsoluteName] = entry.filePath(); fileNames[QAbstractFileEngine::AbsolutePathName] = entry.path(); -- cgit v0.12 From c0278760008efa18a068c6b5b2634b6cdb473dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 17:33:47 +0200 Subject: Revert "In 4.7 QFileInfo::absolute(File)Path returned clean paths" This reverts commit 2e32fca2c0f5252864d348df929d9858486763b1. The fix there is incorrect as it breaks QFileInfo autotests. --- src/corelib/io/qfileinfo.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index e317d1e..ff328da 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -76,9 +76,7 @@ QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const break; case QAbstractFileEngine::AbsoluteName: case QAbstractFileEngine::AbsolutePathName: { - QFileSystemEntry entry = QFileSystemEntry( - QDir::cleanPath(QFileSystemEngine::absoluteName(fileEntry).filePath()), - QFileSystemEntry::FromInternalPath()); + QFileSystemEntry entry = QFileSystemEngine::absoluteName(fileEntry); if (cache_enabled) { // be smart and store both fileNames[QAbstractFileEngine::AbsoluteName] = entry.filePath(); fileNames[QAbstractFileEngine::AbsolutePathName] = entry.path(); -- cgit v0.12 From 7b45a4cbf7593c8d7a837d826d9827fee243c46c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 17:58:27 +0200 Subject: Revert "Don't second-guess the "engine"; call cleanPath on absolutePaths" This reverts commit 07afddbf4bc029f776810381c7317fffa100eb60. This breaks QDir autotests on windows. --- src/corelib/io/qdir.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index cbe635f..c0c62e1 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -197,10 +197,16 @@ inline void QDirPrivate::resolveAbsoluteEntry() const return; QString absoluteName; - if (fileEngine.isNull()) + if (fileEngine.isNull()) { + if (!dirEntry.isRelative()) { + absoluteDirEntry = dirEntry; + return; + } + absoluteName = QFileSystemEngine::absoluteName(dirEntry).filePath(); - else + } else { absoluteName = fileEngine->fileName(QAbstractFileEngine::AbsoluteName); + } absoluteDirEntry = QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath()); } -- cgit v0.12