From d9a2dd8d3b55d16d2e38d124abb0ade490963b37 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 24 Jan 2017 12:17:12 -0800 Subject: QDir::mkpath: don't try to mkdir in automount filesystems Automount filesystems like /home on many operating systems (QNX and OpenIndiana, at least) don't like if you try to mkdir in them, even if the file path already exists. OpenIndiana even gives you an ENOSYS error. So instead, let's try to mkdir our target, if we fail because of ENOENT, we try to create the parent, then try again. Task-number: QTBUG-58390 Change-Id: Ibe5b1b60c6ea47e19612fffd149cce81589b0acd Reviewed-by: James McDonnell Reviewed-by: David Faure --- src/corelib/io/qfilesystemengine_unix.cpp | 96 ++++++++++++++++++++----------- tests/auto/corelib/io/qdir/tst_qdir.cpp | 2 +- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 1b908eac55..96829b3b03 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -556,45 +556,75 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM return data.hasFlags(what); } +// Note: if \a shouldMkdirFirst is false, we assume the caller did try to mkdir +// before calling this function. +static bool createDirectoryWithParents(const QByteArray &nativeName, bool shouldMkdirFirst = true) +{ + // helper function to check if a given path is a directory, since mkdir can + // fail if the dir already exists (it may have been created by another + // thread or another process) + const auto isDir = [](const QByteArray &nativeName) { + QT_STATBUF st; + return QT_STAT(nativeName.constData(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR; + }; + + if (shouldMkdirFirst && QT_MKDIR(nativeName, 0777) == 0) + return true; + if (errno == EEXIST) + return isDir(nativeName); + if (errno != ENOENT) + return false; + + // mkdir failed because the parent dir doesn't exist, so try to create it + int slash = nativeName.lastIndexOf('/'); + if (slash < 1) + return false; + + QByteArray parentNativeName = nativeName.left(slash); + if (!createDirectoryWithParents(parentNativeName)) + return false; + + // try again + if (QT_MKDIR(nativeName, 0777) == 0) + return true; + return errno == EEXIST && isDir(nativeName); +} + //static bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents) { QString dirName = entry.filePath(); - if (createParents) { - dirName = QDir::cleanPath(dirName); - for (int oldslash = -1, slash=0; slash != -1; oldslash = slash) { - slash = dirName.indexOf(QDir::separator(), oldslash+1); - if (slash == -1) { - if (oldslash == dirName.length()) - break; - slash = dirName.length(); - } - if (slash) { - const QByteArray chunk = QFile::encodeName(dirName.left(slash)); - if (QT_MKDIR(chunk.constData(), 0777) != 0) { - if (errno == EEXIST -#if defined(Q_OS_QNX) - // On QNX the QNet (VFS paths of other hosts mounted under a directory - // such as /net) mountpoint returns ENOENT, despite existing. stat() - // on the QNet mountpoint returns successfully and reports S_IFDIR. - || errno == ENOENT -#endif - ) { - QT_STATBUF st; - if (QT_STAT(chunk.constData(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR) - continue; - } - return false; - } - } - } + + // Darwin doesn't support trailing /'s, so remove for everyone + while (dirName.size() > 1 && dirName.endsWith(QLatin1Char('/'))) + dirName.chop(1); + + // try to mkdir this directory + QByteArray nativeName = QFile::encodeName(dirName); + if (QT_MKDIR(nativeName, 0777) == 0) return true; + if (!createParents) + return false; + + // we need the cleaned path in order to create the parents + // and we save errno just in case encodeName needs to load codecs + int savedErrno = errno; + bool pathChanged; + { + QString cleanName = QDir::cleanPath(dirName); + + // Check if the cleaned name is the same or not. If we were given a + // path with resolvable "../" sections, cleanPath will remove them, but + // this may change the target dir if one of those segments was a + // symlink. This operation depends on cleanPath's optimization of + // returning the original string if it didn't modify anything. + pathChanged = !dirName.isSharedWith(cleanName); + if (pathChanged) + nativeName = QFile::encodeName(cleanName); } -#if defined(Q_OS_DARWIN) // Mac X doesn't support trailing /'s - if (dirName.endsWith(QLatin1Char('/'))) - dirName.chop(1); -#endif - return (QT_MKDIR(QFile::encodeName(dirName).constData(), 0777) == 0); + + errno = savedErrno; + return createDirectoryWithParents(nativeName, pathChanged); } //static diff --git a/tests/auto/corelib/io/qdir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/tst_qdir.cpp index b86c6e4dfa..c3774997e9 100644 --- a/tests/auto/corelib/io/qdir/tst_qdir.cpp +++ b/tests/auto/corelib/io/qdir/tst_qdir.cpp @@ -350,7 +350,7 @@ void tst_QDir::mkdir_data() << QDir::currentPath() + "/testdir/two/three"; QTest::newRow("data0") << dirs.at(0) << true; QTest::newRow("data1") << dirs.at(1) << false; - QTest::newRow("data2") << dirs.at(2) << false; + QTest::newRow("data2") << dirs.at(2) << false; // note: requires data1 to have been run! // Ensure that none of these directories already exist QDir dir; -- cgit v1.2.3 From d9c3d2301dba6922e10d8509b220a795686e8fa9 Mon Sep 17 00:00:00 2001 From: Oleg Yadrov Date: Tue, 10 Jan 2017 15:49:54 -0800 Subject: macOS: use active window device pixel ratio for drag pixmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In QCocoaDrag::dragPixmap, it treats QDrag::source as a QWindow, but it is not - it's just a generic QObject* of some kind (which QQuickDrag sets to the originating QQuickItem, and the widgets stack sets to a QWidget). This failure means that dpr stayed at 1.0. Unfortunately it’s not possible to receive a pointer on QWindow directly from QQuickItem because QtWidgets and QtQuick do not share the sources, but we can use the same dpr as current focused window has because drag can only start from active window - press on a window which is not focused should activate it first. Task-number: QTBUG-57942 Change-Id: Id358c181d03d519188caaa83fb4226033b8ed1ea Reviewed-by: Tor Arne Vestbø Reviewed-by: Robin Burchell --- src/plugins/platforms/cocoa/qcocoadrag.mm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm index 7d11023b78..a0967750e7 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.mm +++ b/src/plugins/platforms/cocoa/qcocoadrag.mm @@ -201,6 +201,10 @@ QPixmap QCocoaDrag::dragPixmap(QDrag *drag, QPoint &hotSpot) const dpr = sourceWindow->devicePixelRatio(); } #endif + else { + if (const QWindow *focusWindow = qApp->focusWindow()) + dpr = focusWindow->devicePixelRatio(); + } pm = QPixmap(width * dpr, height * dpr); pm.setDevicePixelRatio(dpr); QPainter p(&pm); -- cgit v1.2.3 From 0e3d6fe4f69955bf98e23a382caf5251e2b47ea0 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 17 Feb 2017 00:54:04 +0100 Subject: QVarLengthArray: fix appending an already-contained item Like the lvalue QVector::append() overload, when we reallocate, we need to take a copy of the function's argument because the reference will get stale upon reallocation. Add a test. [ChangeLog][QtCore][QVarLengthArray] Fixed a bug involving appending an item already in the container to the container again. Change-Id: I06eeed6cb383dd5924e47a302bb3d1666d04c8e8 Reviewed-by: Thiago Macieira --- src/corelib/tools/qvarlengtharray.h | 20 +++++++++++++++----- .../tools/qvarlengtharray/tst_qvarlengtharray.cpp | 17 +++++++++++++++-- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index bb5ae78d2b..2d3c25a5dd 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -146,15 +146,25 @@ public: T value(int i, const T &defaultValue) const; inline void append(const T &t) { - if (s == a) // i.e. s != 0 + if (s == a) { // i.e. s != 0 + T copy(t); realloc(s, s<<1); - const int idx = s++; - if (QTypeInfo::isComplex) { - new (ptr + idx) T(t); + const int idx = s++; + if (QTypeInfo::isComplex) { + new (ptr + idx) T(std::move(copy)); + } else { + ptr[idx] = std::move(copy); + } } else { - ptr[idx] = t; + const int idx = s++; + if (QTypeInfo::isComplex) { + new (ptr + idx) T(t); + } else { + ptr[idx] = t; + } } } + void append(const T *buf, int size); inline QVarLengthArray &operator<<(const T &t) { append(t); return *this; } diff --git a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp index 7fc44343a5..0806ad1318 100644 --- a/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp +++ b/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp @@ -77,8 +77,21 @@ struct Foo void tst_QVarLengthArray::append() { - QVarLengthArray v; - v.append(QString("hello")); + QVarLengthArray v; + v.append(QString("1")); + v.append(v.front()); + QCOMPARE(v.capacity(), 2); + // transition from prealloc to heap: + v.append(v.front()); + QVERIFY(v.capacity() > 2); + QCOMPARE(v.front(), v.back()); + while (v.size() < v.capacity()) + v.push_back(v[0]); + QCOMPARE(v.back(), v.front()); + QCOMPARE(v.size(), v.capacity()); + // transition from heap to larger heap: + v.push_back(v.front()); + QCOMPARE(v.back(), v.front()); QVarLengthArray v2; // rocket! v2.append(5); -- cgit v1.2.3 From dd7f62059c2ae52b5c05fdbe1b6b5d5fa5bc1b03 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 16 Feb 2017 15:52:00 +0100 Subject: Fix a race in QFreeList The _next variable need the acquire and release fence in next() to synchronize with the equivalent operations in release() (which already have the them) The ordering on the _v[block] is not enough as this does not synchronize the same object. Task-number: QTBUG-58917 Change-Id: I17cc39e6791433348b6227363dbea92bcf03700d Reviewed-by: David Faure Reviewed-by: Thiago Macieira --- src/corelib/tools/qfreelist_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qfreelist_p.h b/src/corelib/tools/qfreelist_p.h index c3efc41d62..a8d1132d06 100644 --- a/src/corelib/tools/qfreelist_p.h +++ b/src/corelib/tools/qfreelist_p.h @@ -237,7 +237,7 @@ inline int QFreeList::next() int id, newid, at; ElementType *v; do { - id = _next.load(); + id = _next.loadAcquire(); at = id & ConstantsType::IndexMask; const int block = blockfor(at); @@ -254,7 +254,7 @@ inline int QFreeList::next() } newid = v[at].next.load() | (id & ~ConstantsType::IndexMask); - } while (!_next.testAndSetRelaxed(id, newid)); + } while (!_next.testAndSetRelease(id, newid)); // qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)", // id & ConstantsType::IndexMask, // newid & ConstantsType::IndexMask, -- cgit v1.2.3 From 1d6700171cf41c17983edff285c3658933610523 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Tue, 7 Feb 2017 16:18:18 +0100 Subject: Respect XDG_CONFIG_HOME when getting ibus socket location Task-number: QTBUG-58687 Change-Id: I97ea8b7d7caf922227a92348fb914aead1ecd312 Reviewed-by: Tinu Weber Reviewed-by: Takao Fujiwara Reviewed-by: Konstantin Tokarev Reviewed-by: Shawn Rutledge --- src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index 736c66ebc0..0a55f689c6 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -572,7 +572,8 @@ QString QIBusPlatformInputContextPrivate::getSocketPath() if (debug) qDebug() << "host=" << host << "displayNumber" << displayNumber; - return QDir::homePath() + QLatin1String("/.config/ibus/bus/") + + return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + + QLatin1String("/ibus/bus/") + QLatin1String(QDBusConnection::localMachineId()) + QLatin1Char('-') + QString::fromLocal8Bit(host) + QLatin1Char('-') + QString::fromLocal8Bit(displayNumber); } -- cgit v1.2.3 From c5e687895dd2eba3106f697b6e92b84683402403 Mon Sep 17 00:00:00 2001 From: Eric Lemanissier Date: Mon, 16 Jan 2017 12:22:43 +0100 Subject: Adapt to the C++ SIC introduced by P0012: noexcept overloading see 5a1b4832a2 for more detail Task-number: QTBUG-58142 Change-Id: I51851ea9b4fe7b8eeadc452bc3dbb1ea00026d29 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/concurrent/qtconcurrentfunctionwrappers.h | 84 +++++++++++++++++ .../concurrent/qtconcurrentmap/qtconcurrentmap.pro | 3 + .../qtconcurrentmap/tst_qtconcurrentmap.cpp | 74 +++++++++++++++ .../concurrent/qtconcurrentrun/qtconcurrentrun.pro | 3 + .../qtconcurrentrun/tst_qtconcurrentrun.cpp | 104 +++++++++++++++++++++ 5 files changed, 268 insertions(+) diff --git a/src/concurrent/qtconcurrentfunctionwrappers.h b/src/concurrent/qtconcurrentfunctionwrappers.h index a08be69123..111933410b 100644 --- a/src/concurrent/qtconcurrentfunctionwrappers.h +++ b/src/concurrent/qtconcurrentfunctionwrappers.h @@ -192,6 +192,32 @@ QtConcurrent::ConstMemberFunctionWrapper createFunctionWrapper(T (C::*func return QtConcurrent::ConstMemberFunctionWrapper(func); } +#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 +template +QtConcurrent::FunctionWrapper1 createFunctionWrapper(T (*func)(U) noexcept) +{ + return QtConcurrent::FunctionWrapper1(func); +} + +template +QtConcurrent::MemberFunctionWrapper createFunctionWrapper(T (C::*func)() noexcept) +{ + return QtConcurrent::MemberFunctionWrapper(func); +} + +template +QtConcurrent::MemberFunctionWrapper1 createFunctionWrapper(T (C::*func)(U) noexcept) +{ + return QtConcurrent::MemberFunctionWrapper1(func); +} + +template +QtConcurrent::ConstMemberFunctionWrapper createFunctionWrapper(T (C::*func)() const noexcept) +{ + return QtConcurrent::ConstMemberFunctionWrapper(func); +} +#endif + struct PushBackWrapper { typedef void result_type; @@ -231,6 +257,20 @@ struct ReduceResultType typedef C ResultType; }; +#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 +template +struct ReduceResultType +{ + typedef U ResultType; +}; + +template +struct ReduceResultType +{ + typedef C ResultType; +}; +#endif + template struct MapResultType { @@ -249,6 +289,20 @@ struct MapResultType typedef T ResultType; }; +#if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510 +template +struct MapResultType +{ + typedef U ResultType; +}; + +template +struct MapResultType +{ + typedef T ResultType; +}; +#endif + #ifndef QT_NO_TEMPLATE_TEMPLATE_PARAMETERS template