IPC: move makePlatformSafeKey to qtipccommon.cpp
This removes the second portion of the #if mess of shared code between QSharedMemory and QSystemSemaphore for SystemV. Change-Id: Id8d5e3999fe94b03acc1fffd171c073c2873206e Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
461463b75d
commit
7809caa924
@ -110,6 +110,7 @@ qt_internal_add_module(Core
|
||||
global/qxptype_traits.h
|
||||
ipc/qsharedmemory.cpp ipc/qsharedmemory.h ipc/qsharedmemory_p.h
|
||||
ipc/qsystemsemaphore.cpp ipc/qsystemsemaphore.h ipc/qsystemsemaphore_p.h
|
||||
ipc/qtipccommon.cpp ipc/qtipccommon_p.h
|
||||
io/qabstractfileengine.cpp io/qabstractfileengine_p.h
|
||||
io/qbuffer.cpp io/qbuffer.h
|
||||
io/qdataurl.cpp io/qdataurl_p.h
|
||||
|
@ -3,81 +3,19 @@
|
||||
|
||||
#include "qsharedmemory.h"
|
||||
#include "qsharedmemory_p.h"
|
||||
|
||||
#include "qtipccommon_p.h"
|
||||
#include "qsystemsemaphore.h"
|
||||
#include <qdir.h>
|
||||
#include <qcryptographichash.h>
|
||||
|
||||
#include <qdebug.h>
|
||||
#ifdef Q_OS_WIN
|
||||
# include <qt_windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_DARWIN)
|
||||
# include "qcore_mac_p.h"
|
||||
# if !defined(SHM_NAME_MAX)
|
||||
// Based on PSEMNAMLEN in XNU's posix_sem.c, which would
|
||||
// indicate the max length is 31, _excluding_ the zero
|
||||
// terminator. But in practice (possibly due to an off-
|
||||
// by-one bug in the kernel) the usable bytes are only 30.
|
||||
# define SHM_NAME_MAX 30
|
||||
# endif
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
#if QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
|
||||
/*!
|
||||
\internal
|
||||
|
||||
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
|
||||
*/
|
||||
QString
|
||||
QSharedMemoryPrivate::makePlatformSafeKey(const QString &key,
|
||||
const QString &prefix)
|
||||
{
|
||||
if (key.isEmpty())
|
||||
return QString();
|
||||
|
||||
QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex();
|
||||
|
||||
#if defined(Q_OS_DARWIN) && defined(QT_POSIX_IPC)
|
||||
if (qt_apple_isSandboxed()) {
|
||||
// Sandboxed applications on Apple platforms require the shared memory name
|
||||
// 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;
|
||||
} 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.
|
||||
return u'/' + hex.left(SHM_NAME_MAX - 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
QString result = prefix;
|
||||
for (QChar ch : key) {
|
||||
if ((ch >= u'a' && ch <= u'z') ||
|
||||
(ch >= u'A' && ch <= u'Z'))
|
||||
result += ch;
|
||||
}
|
||||
result.append(QLatin1StringView(hex));
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
return result;
|
||||
#elif defined(QT_POSIX_IPC)
|
||||
return u'/' + result;
|
||||
#else
|
||||
return QDir::tempPath() + u'/' + result;
|
||||
#endif
|
||||
}
|
||||
#endif // QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
|
||||
|
||||
#if QT_CONFIG(sharedmemory)
|
||||
|
||||
/*!
|
||||
@ -306,14 +244,16 @@ QSharedMemory::~QSharedMemory()
|
||||
void QSharedMemory::setKey(const QString &key)
|
||||
{
|
||||
Q_D(QSharedMemory);
|
||||
if (key == d->key && d->makePlatformSafeKey(key) == d->nativeKey)
|
||||
QString newNativeKey =
|
||||
QtIpcCommon::legacyPlatformSafeKey(key, QtIpcCommon::IpcType::SharedMemory);
|
||||
if (key == d->key && newNativeKey == d->nativeKey)
|
||||
return;
|
||||
|
||||
if (isAttached())
|
||||
detach();
|
||||
d->cleanHandle();
|
||||
d->key = key;
|
||||
d->nativeKey = d->makePlatformSafeKey(key);
|
||||
d->nativeKey = newNativeKey;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -19,22 +19,7 @@
|
||||
|
||||
#include <QtCore/qstring.h>
|
||||
|
||||
#if !QT_CONFIG(sharedmemory)
|
||||
# if QT_CONFIG(systemsemaphore)
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QSharedMemoryPrivate
|
||||
{
|
||||
QString makePlatformSafeKey(const QString &key,
|
||||
const QString &prefix = QStringLiteral("qipc_sharedmemory_"));
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
# endif
|
||||
#else
|
||||
|
||||
#if QT_CONFIG(sharedmemory)
|
||||
#include "qsystemsemaphore.h"
|
||||
#include "private/qobject_p.h"
|
||||
|
||||
@ -92,8 +77,6 @@ public:
|
||||
bool lockedByMe = false;
|
||||
#endif
|
||||
|
||||
static QString makePlatformSafeKey(const QString &key,
|
||||
const QString &prefix = QStringLiteral("qipc_sharedmemory_"));
|
||||
#ifdef Q_OS_WIN
|
||||
Qt::HANDLE handle();
|
||||
#elif defined(QT_POSIX_IPC)
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include "qsharedmemory.h"
|
||||
#include "qsharedmemory_p.h"
|
||||
#include "qsystemsemaphore.h"
|
||||
#include "qtipccommon_p.h"
|
||||
#include <qfile.h>
|
||||
|
||||
#include <errno.h>
|
||||
@ -26,11 +26,12 @@
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
using namespace QtIpcCommon;
|
||||
|
||||
int QSharedMemoryPrivate::handle()
|
||||
{
|
||||
// don't allow making handles on empty keys
|
||||
const QString safeKey = makePlatformSafeKey(key);
|
||||
const QString safeKey = legacyPlatformSafeKey(key, QtIpcCommon::IpcType::SharedMemory);
|
||||
if (safeKey.isEmpty()) {
|
||||
errorString = QSharedMemory::tr("%1: key is empty").arg("QSharedMemory::handle"_L1);
|
||||
error = QSharedMemory::KeyError;
|
||||
@ -53,7 +54,7 @@ bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
if (!handle())
|
||||
return false;
|
||||
|
||||
const QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key));
|
||||
const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(key, IpcType::SharedMemory));
|
||||
|
||||
int fd;
|
||||
#ifdef O_CLOEXEC
|
||||
@ -94,7 +95,7 @@ bool QSharedMemoryPrivate::create(qsizetype size)
|
||||
|
||||
bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
|
||||
{
|
||||
const QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key));
|
||||
const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(key, IpcType::SharedMemory));
|
||||
|
||||
const int oflag = (mode == QSharedMemory::ReadOnly ? O_RDONLY : O_RDWR);
|
||||
const mode_t omode = (mode == QSharedMemory::ReadOnly ? 0400 : 0600);
|
||||
@ -180,7 +181,7 @@ bool QSharedMemoryPrivate::detach()
|
||||
|
||||
// if there are no attachments then unlink the shared memory
|
||||
if (shm_nattch == 0) {
|
||||
const QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key));
|
||||
const QByteArray shmName = QFile::encodeName(legacyPlatformSafeKey(key, IpcType::SharedMemory));
|
||||
if (::shm_unlink(shmName.constData()) == -1 && errno != ENOENT)
|
||||
setErrorString("QSharedMemory::detach (shm_unlink)"_L1);
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
#include "qcoreapplication.h"
|
||||
#include "qtipccommon_p.h"
|
||||
#include "qsharedmemory_p.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef QT_POSIX_IPC
|
||||
@ -37,7 +36,7 @@ public:
|
||||
|
||||
QString makeKeyFileName()
|
||||
{
|
||||
return QSharedMemoryPrivate::makePlatformSafeKey(key, QLatin1StringView("qipc_systemsem_"));
|
||||
return QtIpcCommon::legacyPlatformSafeKey(key, QtIpcCommon::IpcType::SystemSemaphore);
|
||||
}
|
||||
|
||||
inline void setError(QSystemSemaphore::SystemSemaphoreError e, const QString &message)
|
||||
|
89
src/corelib/ipc/qtipccommon.cpp
Normal file
89
src/corelib/ipc/qtipccommon.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright (C) 2022 Intel Corporation.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "qtipccommon_p.h"
|
||||
|
||||
#include <qcryptographichash.h>
|
||||
#include <qdir.h>
|
||||
|
||||
#if defined(Q_OS_DARWIN)
|
||||
# include "private/qcore_mac_p.h"
|
||||
# if !defined(SHM_NAME_MAX)
|
||||
// Based on PSEMNAMLEN in XNU's posix_sem.c, which would
|
||||
// indicate the max length is 31, _excluding_ the zero
|
||||
// terminator. But in practice (possibly due to an off-
|
||||
// by-one bug in the kernel) the usable bytes are only 30.
|
||||
# define SHM_NAME_MAX 30
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
/*!
|
||||
\internal
|
||||
|
||||
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
|
||||
*/
|
||||
QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType)
|
||||
{
|
||||
if (key.isEmpty())
|
||||
return QString();
|
||||
|
||||
QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex();
|
||||
|
||||
#if defined(Q_OS_DARWIN) && defined(QT_POSIX_IPC)
|
||||
if (qt_apple_isSandboxed()) {
|
||||
// Sandboxed applications on Apple platforms require the shared memory name
|
||||
// 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;
|
||||
} 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.
|
||||
return u'/' + hex.left(SHM_NAME_MAX - 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
QString result;
|
||||
result.reserve(1 + 18 + key.size() + 40);
|
||||
switch (ipcType) {
|
||||
case IpcType::SharedMemory:
|
||||
result += "qipc_sharedmemory_"_L1;
|
||||
break;
|
||||
case IpcType::SystemSemaphore:
|
||||
result += "qipc_systemsem_"_L1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (QChar ch : key) {
|
||||
if ((ch >= u'a' && ch <= u'z') ||
|
||||
(ch >= u'A' && ch <= u'Z'))
|
||||
result += ch;
|
||||
}
|
||||
result.append(QLatin1StringView(hex));
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
return result;
|
||||
#elif defined(QT_POSIX_IPC)
|
||||
return u'/' + result;
|
||||
#else
|
||||
return QDir::tempPath() + u'/' + result;
|
||||
#endif
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
|
@ -27,6 +27,13 @@
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtIpcCommon {
|
||||
enum class IpcType {
|
||||
SharedMemory,
|
||||
SystemSemaphore
|
||||
};
|
||||
|
||||
Q_AUTOTEST_EXPORT QString legacyPlatformSafeKey(const QString &key, IpcType ipcType);
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
// Convenience function to create the file if needed
|
||||
inline int createUnixKeyFile(const QByteArray &fileName)
|
||||
|
@ -135,7 +135,7 @@ void tst_QSharedMemory::cleanup()
|
||||
}
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
#include <private/qsharedmemory_p.h>
|
||||
#include <private/qtipccommon_p.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef QT_POSIX_IPC
|
||||
#include <sys/ipc.h>
|
||||
@ -157,7 +157,7 @@ int tst_QSharedMemory::remove(const QString &key)
|
||||
if (key.isEmpty())
|
||||
return -1;
|
||||
|
||||
QString fileName = QSharedMemoryPrivate::makePlatformSafeKey(key);
|
||||
QString fileName = QtIpcCommon::legacyPlatformSafeKey(key, QtIpcCommon::IpcType::SharedMemory);
|
||||
|
||||
#ifndef QT_POSIX_IPC
|
||||
// ftok requires that an actual file exists somewhere
|
||||
|
Loading…
Reference in New Issue
Block a user