diff options
Diffstat (limited to 'src/corelib/ipc/qtipccommon.cpp')
-rw-r--r-- | src/corelib/ipc/qtipccommon.cpp | 202 |
1 files changed, 131 insertions, 71 deletions
diff --git a/src/corelib/ipc/qtipccommon.cpp b/src/corelib/ipc/qtipccommon.cpp index 1dcc774c85..b2ae9172fa 100644 --- a/src/corelib/ipc/qtipccommon.cpp +++ b/src/corelib/ipc/qtipccommon.cpp @@ -8,6 +8,7 @@ #include <qstandardpaths.h> #include <qstringconverter.h> #include <qurl.h> +#include <qurlquery.h> #if defined(Q_OS_DARWIN) # include "private/qcore_mac_p.h" @@ -18,6 +19,8 @@ // by-one bug in the kernel) the usable bytes are only 30. # define SHM_NAME_MAX 30 # endif +#elif defined(Q_OS_WINDOWS) +# include "qt_windows.h" #endif #if QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore) @@ -91,16 +94,18 @@ static QNativeIpcKey::Type stringToType(QStringView typeString) Legacy: this exists for compatibility with QSharedMemory and QSystemSemaphore between 4.4 and 6.6. - Generate a string from the key which can be any unicode string into - the subset that the win/unix kernel allows. - - On Unix this will be a file name + Returns a QNativeIpcKey that contains a platform-safe key using rules + similar to QtIpcCommon::platformSafeKey() below, but using an algorithm + that is compatible with Qt 4.4 to 6.6. Additionally, the returned + QNativeIpcKey will record the input \a key so it can be included in the + string form if necessary to pass to other processes. */ -QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType, - QNativeIpcKey::Type type) +QNativeIpcKey QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType, + QNativeIpcKey::Type type) { + QNativeIpcKey k(type); if (key.isEmpty()) - return QString(); + return k; QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex(); @@ -111,13 +116,16 @@ QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcT // to be in the form <application group identifier>/<custom identifier>. // Since we don't know which application group identifier the user wants // to apply, we instead document that requirement, and use the key directly. - return key; + QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, key, key); + } else { + // The shared memory name limit on Apple platforms is very low (30 characters), + // so we can't use the logic below of combining the prefix, key, and a hash, + // to ensure a unique and valid name. Instead we use the first part of the + // hash, which should still long enough to avoid collisions in practice. + QString native = u'/' + QLatin1StringView(hex).left(SHM_NAME_MAX - 1); + QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, native, key); } - // The shared memory name limit on Apple platforms is very low (30 characters), - // so we can't use the logic below of combining the prefix, key, and a hash, - // to ensure a unique and valid name. Instead we use the first part of the - // hash, which should still long enough to avoid collisions in practice. - return u'/' + QLatin1StringView(hex).left(SHM_NAME_MAX - 1); + return k; #endif } @@ -141,38 +149,51 @@ QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcT switch (type) { case QNativeIpcKey::Type::Windows: - if (!isIpcSupported(ipcType, QNativeIpcKey::Type::Windows)) - return QString(); - return result; + if (isIpcSupported(ipcType, QNativeIpcKey::Type::Windows)) + QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key); + return k; case QNativeIpcKey::Type::PosixRealtime: - if (!isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime)) - return QString(); - return result.prepend(u'/'); + result.prepend(u'/'); + if (isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime)) + QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key); + return k; case QNativeIpcKey::Type::SystemV: break; } - if (!isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) - return QString(); - return QStandardPaths::writableLocation(QStandardPaths::TempLocation) + u'/' + result; + if (isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) { + result = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + u'/' + result; + QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key); + } + return k; } -QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType, - QNativeIpcKey::Type type) +/*! + \internal + Returns a QNativeIpcKey of type \a type, suitable for QSystemSemaphore or + QSharedMemory depending on \a ipcType. The returned native key is generated + from the Unicode input \a key and is safe for use on for the key type in + question in the current OS. +*/ +QNativeIpcKey QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType, + QNativeIpcKey::Type type) { + QNativeIpcKey k(type); if (key.isEmpty()) - return key; + return k; switch (type) { case QNativeIpcKey::Type::PosixRealtime: - if (!isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime)) - return QString(); + if (isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime)) { #ifdef SHM_NAME_MAX - // The shared memory name limit on Apple platforms is very low (30 - // characters), so we have to cut it down to avoid ENAMETOOLONG. We - // hope that there won't be too many collisions... - return u'/' + QStringView(key).left(SHM_NAME_MAX - 1); + // The shared memory name limit on Apple platforms is very low (30 + // characters), so we have to cut it down to avoid ENAMETOOLONG. We + // hope that there won't be too many collisions... + k.setNativeKey(u'/' + QStringView(key).left(SHM_NAME_MAX - 1)); +#else + k.setNativeKey(u'/' + key); #endif - return u'/' + key; + } + return k; case QNativeIpcKey::Type::Windows: if (isIpcSupported(ipcType, QNativeIpcKey::Type::Windows)) { @@ -194,25 +215,27 @@ QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ip } QString result = prefix + mid + payload; -#ifdef MAX_PATH +#ifdef Q_OS_WINDOWS result.truncate(MAX_PATH); #endif - return result; + k.setNativeKey(result); } - return QString(); + return k; case QNativeIpcKey::Type::SystemV: break; } // System V - if (!isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) - return QString(); - if (key.startsWith(u'/')) - return key; - - QString baseDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); - return baseDir + u'/' + key; + if (isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) { + if (key.startsWith(u'/')) { + k.setNativeKey(key); + } else { + QString baseDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); + k.setNativeKey(baseDir + u'/' + key); + } + } + return k; } /*! @@ -221,6 +244,8 @@ QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ip \since 6.6 \brief The QNativeIpcKey class holds a native key used by QSystemSemaphore and QSharedMemory. + \compares equality + The \l QSharedMemory and \l QSystemSemaphore classes identify their resource using a system-wide identifier known as a "key". The low-level key value as well as the key type are encapsulated in Qt using the \l @@ -344,6 +369,12 @@ QNativeIpcKey::Type QNativeIpcKey::defaultTypeForOs_internal() noexcept #endif /*! + \fn QNativeIpcKey::QNativeIpcKey() noexcept + + Constructs a QNativeIpcKey object of type \l DefaultTypeForOs with an empty key. +*/ + +/*! \fn QNativeIpcKey::QNativeIpcKey(Type type) noexcept \fn QNativeIpcKey::QNativeIpcKey(const QString &key, Type type) @@ -361,8 +392,7 @@ QNativeIpcKey::Type QNativeIpcKey::defaultTypeForOs_internal() noexcept */ void QNativeIpcKey::copy_internal(const QNativeIpcKey &other) { - auto copy = new QNativeIpcKeyPrivate(*other.d_func()); - d = quintptr(copy) & 1; + d = new QNativeIpcKeyPrivate(*other.d); } void QNativeIpcKey::move_internal(QNativeIpcKey &&) noexcept @@ -372,21 +402,13 @@ void QNativeIpcKey::move_internal(QNativeIpcKey &&) noexcept QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &other) { - QNativeIpcKeyPrivate *us = (d & 1) ? d_func() : nullptr; - const QNativeIpcKeyPrivate *them = (other.d & 1) ? other.d_func() : nullptr; - if (us && !them) { - // don't need the extra info, reset to skinny object - typeAndFlags = {}; - typeAndFlags.type = us->type; - delete us; - } else { - // do need the extra info, so create if necessary - if (us) - *us = *them; - else - us = new QNativeIpcKeyPrivate(*them); - d = quintptr(us) | 1; - } + Q_ASSERT(d || other.d); // only 3 cases to handle + if (d && !other.d) + *d = {}; + else if (d) + *d = *other.d; + else + d = new QNativeIpcKeyPrivate(*other.d); return *this; } @@ -397,16 +419,22 @@ QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &other) */ void QNativeIpcKey::destroy_internal() noexcept { - Q_D(QNativeIpcKey); delete d; } /*! \fn QNativeIpcKey::swap(QNativeIpcKey &other) noexcept - \fn swap(QNativeIpcKey &lhs, QNativeIpcKey &rhs) noexcept - Swaps the native IPC key and type \a other with this object, or \a lhs with - \a rhs. This operation is very fast and never fails. + Swaps the native IPC key and type \a other with this object. + This operation is very fast and never fails. +*/ + +/*! + \fn swap(QNativeIpcKey &value1, QNativeIpcKey &value2) noexcept + \relates QNativeIpcKey + + Swaps the native IPC key and type \a value1 with \a value2. + This operation is very fast and never fails. */ /*! @@ -437,11 +465,6 @@ void QNativeIpcKey::destroy_internal() noexcept \sa nativeKey(), setType() */ -QNativeIpcKey::Type QNativeIpcKey::type_internal() const noexcept -{ - Q_D(const QNativeIpcKey); - return d->type; -} /*! \fn QNativeIpcKey::setType(Type type) @@ -452,8 +475,7 @@ QNativeIpcKey::Type QNativeIpcKey::type_internal() const noexcept */ void QNativeIpcKey::setType_internal(Type type) { - Q_D(QNativeIpcKey); - d->type = type; + Q_UNUSED(type); } /*! @@ -473,6 +495,25 @@ void QNativeIpcKey::setType_internal(Type type) */ void QNativeIpcKey::setNativeKey_internal(const QString &) { + d->legacyKey_.clear(); +} + +/*! + \fn size_t QNativeIpcKey::qHash(const QNativeIpcKey &ipcKey) noexcept + + Returns the hash value for \a ipcKey, using a default seed of \c 0. +*/ + +/*! + \fn size_t QNativeIpcKey::qHash(const QNativeIpcKey &ipcKey, size_t seed) noexcept + + Returns the hash value for \a ipcKey, using \a seed to seed the calculation. +*/ +size_t qHash(const QNativeIpcKey &ipcKey, size_t seed) noexcept +{ + // by *choice*, we're not including d->legacyKey_ in the hash -- it's + // already partially encoded in the key + return qHashMulti(seed, ipcKey.key, ipcKey.type()); } /*! @@ -483,7 +524,7 @@ void QNativeIpcKey::setNativeKey_internal(const QString &) */ int QNativeIpcKey::compare_internal(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept { - return *lhs.d_func() == *rhs.d_func() ? 0 : 1; + return (QNativeIpcKeyPrivate::legacyKey(lhs) == QNativeIpcKeyPrivate::legacyKey(rhs)) ? 0 : 1; } /*! @@ -512,6 +553,12 @@ QString QNativeIpcKey::toString() const QUrl u; u.setScheme(prefix); u.setPath(copy, QUrl::TolerantMode); + if (isSlowPath()) { + QUrlQuery q; + if (!d->legacyKey_.isEmpty()) + q.addQueryItem(u"legacyKey"_s, QString(d->legacyKey_).replace(u'%', "%25"_L1)); + u.setQuery(q); + } return u.toString(QUrl::DecodeReserved); } @@ -540,6 +587,19 @@ QNativeIpcKey QNativeIpcKey::fromString(const QString &text) // decode the payload result.setNativeKey(u.path()); + + if (u.hasQuery()) { + const QList items = QUrlQuery(u).queryItems(); + for (const auto &item : items) { + if (item.first == u"legacyKey"_s) { + QString legacyKey = QUrl::fromPercentEncoding(item.second.toUtf8()); + QNativeIpcKeyPrivate::setLegacyKey(result, std::move(legacyKey)); + } else { + // unknown query item + return QNativeIpcKey(invalidType); + } + } + } return result; } |