From 8ad6f89fed092d3de8e36ee1c949c98aa48e32c7 Mon Sep 17 00:00:00 2001 From: Matthieu Gallien Date: Fri, 11 Jun 2021 19:17:10 +0200 Subject: bring back dynamic load of VFS plugins Signed-off-by: Matthieu Gallien --- src/common/common.cmake | 2 ++ src/common/plugin.cpp | 33 ++++++++++++++++++++++ src/common/plugin.h | 48 ++++++++++++++++++++++++++++++++ src/common/vfs.cpp | 74 ++++++++++++++++++++++++++++++++++--------------- src/common/vfs.h | 4 --- 5 files changed, 135 insertions(+), 26 deletions(-) create mode 100644 src/common/plugin.cpp create mode 100644 src/common/plugin.h (limited to 'src/common') diff --git a/src/common/common.cmake b/src/common/common.cmake index 82437cd04..5c7cd52c9 100644 --- a/src/common/common.cmake +++ b/src/common/common.cmake @@ -11,6 +11,8 @@ set(common_SOURCES ${CMAKE_CURRENT_LIST_DIR}/remotepermissions.cpp ${CMAKE_CURRENT_LIST_DIR}/vfs.cpp ${CMAKE_CURRENT_LIST_DIR}/pinstate.cpp + ${CMAKE_CURRENT_LIST_DIR}/plugin.cpp ${CMAKE_CURRENT_LIST_DIR}/syncfilestatus.cpp ) +configure_file(${CMAKE_CURRENT_LIST_DIR}/vfspluginmetadata.json.in ${CMAKE_CURRENT_BINARY_DIR}/vfspluginmetadata.json) diff --git a/src/common/plugin.cpp b/src/common/plugin.cpp new file mode 100644 index 000000000..7e705d94e --- /dev/null +++ b/src/common/plugin.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) by Dominik Schmidt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "plugin.h" + +#include "config.h" + +namespace OCC { + +PluginFactory::~PluginFactory() = default; + +QString pluginFileName(const QString &type, const QString &name) +{ + return QStringLiteral("%1sync_%2_%3") + .arg(QStringLiteral(APPLICATION_EXECUTABLE), type, name); +} + +} diff --git a/src/common/plugin.h b/src/common/plugin.h new file mode 100644 index 000000000..3d28f7dd3 --- /dev/null +++ b/src/common/plugin.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) by Dominik Schmidt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "ocsynclib.h" +#include + +namespace OCC { + +class OCSYNC_EXPORT PluginFactory +{ +public: + virtual ~PluginFactory(); + virtual QObject* create(QObject* parent) = 0; +}; + +template +class DefaultPluginFactory : public PluginFactory +{ +public: + QObject* create(QObject *parent) override + { + return new PluginClass(parent); + } +}; + +/// Return the expected name of a plugin, for use with QPluginLoader +QString pluginFileName(const QString &type, const QString &name); + +} + +Q_DECLARE_INTERFACE(OCC::PluginFactory, "org.owncloud.PluginFactory") diff --git a/src/common/vfs.cpp b/src/common/vfs.cpp index e9cf977d9..71ff5dae0 100644 --- a/src/common/vfs.cpp +++ b/src/common/vfs.cpp @@ -17,6 +17,7 @@ */ #include "vfs.h" +#include "plugin.h" #include "version.h" #include "syncjournaldb.h" @@ -27,15 +28,6 @@ using namespace OCC; -using MetaObjectHash = QHash; -Q_GLOBAL_STATIC(MetaObjectHash, vfsFactoryHash); - -void Vfs::registerPlugin(const QString &name, Factory factory) -{ - Q_ASSERT(!vfsFactoryHash()->contains(name)); - vfsFactoryHash()->insert(name, factory); -} - Vfs::Vfs(QObject* parent) : QObject(parent) { @@ -83,7 +75,8 @@ Result Vfs::checkAvailability(const QString &path) } } #else - Q_UNUSED(path); + Q_UNUSED(mode) + Q_UNUSED(path) #endif return true; } @@ -146,7 +139,7 @@ static QString modeToPluginName(Vfs::Mode mode) if (mode == Vfs::WithSuffix) return QStringLiteral("suffix"); if (mode == Vfs::WindowsCfApi) - return QStringLiteral("win"); + return QStringLiteral("cfapi"); if (mode == Vfs::XAttr) return QStringLiteral("xattr"); return QString(); @@ -157,14 +150,41 @@ Q_LOGGING_CATEGORY(lcPlugin, "plugins", QtInfoMsg) bool OCC::isVfsPluginAvailable(Vfs::Mode mode) { // TODO: cache plugins available? - if (mode == Vfs::Off) + if (mode == Vfs::Off) { return true; + } + auto name = modeToPluginName(mode); - if (name.isEmpty()) + if (name.isEmpty()) { + return false; + } + + QPluginLoader loader(pluginFileName(QStringLiteral("vfs"), name)); + + const auto baseMetaData = loader.metaData(); + if (baseMetaData.isEmpty() || !baseMetaData.contains(QStringLiteral("IID"))) { + qCDebug(lcPlugin) << "Plugin doesn't exist" << loader.fileName(); + return false; + } + if (baseMetaData[QStringLiteral("IID")].toString() != QStringLiteral("org.owncloud.PluginFactory")) { + qCWarning(lcPlugin) << "Plugin has wrong IID" << loader.fileName() << baseMetaData[QStringLiteral("IID")]; + return false; + } + + const auto metadata = baseMetaData[QStringLiteral("MetaData")].toObject(); + if (metadata[QStringLiteral("type")].toString() != QStringLiteral("vfs")) { + qCWarning(lcPlugin) << "Plugin has wrong type" << loader.fileName() << metadata[QStringLiteral("type")]; + return false; + } + if (metadata[QStringLiteral("version")].toString() != QStringLiteral(MIRALL_VERSION_STRING)) { + qCWarning(lcPlugin) << "Plugin has wrong version" << loader.fileName() << metadata[QStringLiteral("version")]; return false; + } - if (!vfsFactoryHash()->contains(name)) { - qCDebug(lcPlugin) << "Plugin isn't registered:" << name; + // Attempting to load the plugin is essential as it could have dependencies that + // can't be resolved and thus not be available after all. + if (!loader.load()) { + qCWarning(lcPlugin) << "Plugin failed to load:" << loader.errorString(); return false; } @@ -210,26 +230,36 @@ std::unique_ptr OCC::createVfsFromPlugin(Vfs::Mode mode) return std::unique_ptr(new VfsOff); auto name = modeToPluginName(mode); - if (name.isEmpty()) + if (name.isEmpty()) { return nullptr; + } + + const auto pluginPath = pluginFileName(QStringLiteral("vfs"), name); if (!isVfsPluginAvailable(mode)) { - qCCritical(lcPlugin) << "Could not load plugin: not existant" << name; + qCCritical(lcPlugin) << "Could not load plugin: not existant or bad metadata" << pluginPath; + return nullptr; + } + + QPluginLoader loader(pluginPath); + auto plugin = loader.instance(); + if (!plugin) { + qCCritical(lcPlugin) << "Could not load plugin" << pluginPath << loader.errorString(); return nullptr; } - const auto factory = vfsFactoryHash()->value(name); + auto factory = qobject_cast(plugin); if (!factory) { - qCCritical(lcPlugin) << "Could not load plugin" << name; + qCCritical(lcPlugin) << "Plugin" << loader.fileName() << "does not implement PluginFactory"; return nullptr; } - auto vfs = std::unique_ptr(qobject_cast(factory())); + auto vfs = std::unique_ptr(qobject_cast(factory->create(nullptr))); if (!vfs) { - qCCritical(lcPlugin) << "Plugin" << name << "does not create a Vfs instance"; + qCCritical(lcPlugin) << "Plugin" << loader.fileName() << "does not create a Vfs instance"; return nullptr; } - qCInfo(lcPlugin) << "Created VFS instance for:" << name; + qCInfo(lcPlugin) << "Created VFS instance from plugin" << pluginPath; return vfs; } diff --git a/src/common/vfs.h b/src/common/vfs.h index 1435f2633..0f12f8c2e 100644 --- a/src/common/vfs.h +++ b/src/common/vfs.h @@ -14,7 +14,6 @@ #pragma once #include -#include #include #include @@ -126,9 +125,6 @@ public: using AvailabilityResult = Result; public: - using Factory = Vfs* (*)(); - static void registerPlugin(const QString &name, Factory factory); - explicit Vfs(QObject* parent = nullptr); virtual ~Vfs(); -- cgit v1.2.3