Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/desktop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthieu Gallien <matthieu.gallien@nextcloud.com>2021-06-11 20:17:10 +0300
committerMatthieu Gallien (Rebase PR Action) <matthieu_gallien@yahoo.fr>2021-07-08 11:11:17 +0300
commit8ad6f89fed092d3de8e36ee1c949c98aa48e32c7 (patch)
tree47732b4203e844fe7091720b386ada91976c1f09 /src/common
parentfe925d8f36f00e44785c2fd2642e7bf50a8477e4 (diff)
bring back dynamic load of VFS plugins
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
Diffstat (limited to 'src/common')
-rw-r--r--src/common/common.cmake2
-rw-r--r--src/common/plugin.cpp33
-rw-r--r--src/common/plugin.h48
-rw-r--r--src/common/vfs.cpp74
-rw-r--r--src/common/vfs.h4
5 files changed, 135 insertions, 26 deletions
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 <dschmidt@owncloud.com>
+ *
+ * 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 <dschmidt@owncloud.com>
+ *
+ * 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 <QObject>
+
+namespace OCC {
+
+class OCSYNC_EXPORT PluginFactory
+{
+public:
+ virtual ~PluginFactory();
+ virtual QObject* create(QObject* parent) = 0;
+};
+
+template<class PluginClass>
+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<QString, Vfs::Factory>;
-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<bool, QString> 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<Vfs> OCC::createVfsFromPlugin(Vfs::Mode mode)
return std::unique_ptr<Vfs>(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<PluginFactory *>(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<Vfs>(qobject_cast<Vfs *>(factory()));
+ auto vfs = std::unique_ptr<Vfs>(qobject_cast<Vfs *>(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 <QObject>
-#include <QCoreApplication>
#include <QScopedPointer>
#include <QSharedPointer>
@@ -126,9 +125,6 @@ public:
using AvailabilityResult = Result<VfsItemAvailability, AvailabilityError>;
public:
- using Factory = Vfs* (*)();
- static void registerPlugin(const QString &name, Factory factory);
-
explicit Vfs(QObject* parent = nullptr);
virtual ~Vfs();