diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml
index 84c31dfd0cac6..bc2786cc3b485 100644
--- a/apps/files_external/appinfo/info.xml
+++ b/apps/files_external/appinfo/info.xml
@@ -53,6 +53,7 @@ External storage can be configured using the GUI or at the command line. This se
OCA\Files_External\Command\Verify
OCA\Files_External\Command\Notify
OCA\Files_External\Command\Scan
+ OCA\Files_External\Command\Dependencies
diff --git a/apps/files_external/composer/composer/autoload_classmap.php b/apps/files_external/composer/composer/autoload_classmap.php
index 156847d56200b..589b70a078b05 100644
--- a/apps/files_external/composer/composer/autoload_classmap.php
+++ b/apps/files_external/composer/composer/autoload_classmap.php
@@ -14,6 +14,7 @@
'OCA\\Files_External\\Command\\Config' => $baseDir . '/../lib/Command/Config.php',
'OCA\\Files_External\\Command\\Create' => $baseDir . '/../lib/Command/Create.php',
'OCA\\Files_External\\Command\\Delete' => $baseDir . '/../lib/Command/Delete.php',
+ 'OCA\\Files_External\\Command\\Dependencies' => $baseDir . '/../lib/Command/Dependencies.php',
'OCA\\Files_External\\Command\\Export' => $baseDir . '/../lib/Command/Export.php',
'OCA\\Files_External\\Command\\Import' => $baseDir . '/../lib/Command/Import.php',
'OCA\\Files_External\\Command\\ListCommand' => $baseDir . '/../lib/Command/ListCommand.php',
diff --git a/apps/files_external/composer/composer/autoload_static.php b/apps/files_external/composer/composer/autoload_static.php
index 186f85bc5bc55..0399f47685c8a 100644
--- a/apps/files_external/composer/composer/autoload_static.php
+++ b/apps/files_external/composer/composer/autoload_static.php
@@ -29,6 +29,7 @@ class ComposerStaticInitFiles_External
'OCA\\Files_External\\Command\\Config' => __DIR__ . '/..' . '/../lib/Command/Config.php',
'OCA\\Files_External\\Command\\Create' => __DIR__ . '/..' . '/../lib/Command/Create.php',
'OCA\\Files_External\\Command\\Delete' => __DIR__ . '/..' . '/../lib/Command/Delete.php',
+ 'OCA\\Files_External\\Command\\Dependencies' => __DIR__ . '/..' . '/../lib/Command/Dependencies.php',
'OCA\\Files_External\\Command\\Export' => __DIR__ . '/..' . '/../lib/Command/Export.php',
'OCA\\Files_External\\Command\\Import' => __DIR__ . '/..' . '/../lib/Command/Import.php',
'OCA\\Files_External\\Command\\ListCommand' => __DIR__ . '/..' . '/../lib/Command/ListCommand.php',
diff --git a/apps/files_external/lib/Command/Dependencies.php b/apps/files_external/lib/Command/Dependencies.php
new file mode 100644
index 0000000000000..1bb5777812912
--- /dev/null
+++ b/apps/files_external/lib/Command/Dependencies.php
@@ -0,0 +1,56 @@
+setName('files_external:dependencies')
+ ->setDescription('Show information about the backend dependencies');
+ parent::configure();
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $storageBackends = $this->backendService->getBackends();
+
+ $anyMissing = false;
+
+ foreach ($storageBackends as $backend) {
+ if ($backend->getDeprecateTo() !== null) {
+ continue;
+ }
+ $missingDependencies = $backend->checkDependencies();
+ if ($missingDependencies) {
+ $anyMissing = true;
+ $output->writeln($backend->getText() . ':');
+ foreach ($missingDependencies as $missingDependency) {
+ if ($missingDependency->getMessage()) {
+ $output->writeln(" - {$missingDependency->getDependency()}: {$missingDependency->getMessage()}");
+ } else {
+ $output->writeln(" - {$missingDependency->getDependency()}");
+ }
+ }
+ }
+ }
+
+ if (!$anyMissing) {
+ $output->writeln('All dependencies are met');
+ }
+
+ return self::SUCCESS;
+ }
+}
diff --git a/apps/files_external/lib/Lib/Backend/SMB.php b/apps/files_external/lib/Lib/Backend/SMB.php
index b246b0638f007..3549f69cbe314 100644
--- a/apps/files_external/lib/Lib/Backend/SMB.php
+++ b/apps/files_external/lib/Lib/Backend/SMB.php
@@ -10,19 +10,20 @@
use Icewind\SMB\BasicAuth;
use Icewind\SMB\KerberosApacheAuth;
use Icewind\SMB\KerberosAuth;
+use Icewind\SMB\Native\NativeServer;
+use Icewind\SMB\Wrapped\Server;
use OCA\Files_External\Lib\Auth\AuthMechanism;
use OCA\Files_External\Lib\Auth\Password\Password;
use OCA\Files_External\Lib\Auth\SMB\KerberosApacheAuth as KerberosApacheAuthMechanism;
use OCA\Files_External\Lib\DefinitionParameter;
use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
-use OCA\Files_External\Lib\LegacyDependencyCheckPolyfill;
+use OCA\Files_External\Lib\MissingDependency;
+use OCA\Files_External\Lib\Storage\SystemBridge;
use OCA\Files_External\Lib\StorageConfig;
use OCP\IL10N;
use OCP\IUser;
class SMB extends Backend {
- use LegacyDependencyCheckPolyfill;
-
public function __construct(IL10N $l, Password $legacyAuth) {
$this
->setIdentifier('smb')
@@ -122,4 +123,20 @@ public function manipulateStorageConfig(StorageConfig &$storage, ?IUser $user =
$storage->setBackendOption('auth', $smbAuth);
}
+
+ public function checkDependencies() {
+ $system = \OCP\Server::get(SystemBridge::class);
+ if (NativeServer::available($system)) {
+ return [];
+ } elseif (Server::available($system)) {
+ $missing = new MissingDependency('php-smbclient');
+ $missing->setOptional(true);
+ $missing->setMessage('The php-smbclient library provides improved compatibility and performance for SMB storages.');
+ return [$missing];
+ } else {
+ $missing = new MissingDependency('php-smbclient');
+ $missing->setMessage('Either the php-smbclient library (preferred) or the smbclient binary is required for SMB storages.');
+ return [$missing, new MissingDependency('smbclient')];
+ }
+ }
}
diff --git a/apps/files_external/lib/Lib/MissingDependency.php b/apps/files_external/lib/Lib/MissingDependency.php
index 5c2c6880f23d2..da4cbb1de4610 100644
--- a/apps/files_external/lib/Lib/MissingDependency.php
+++ b/apps/files_external/lib/Lib/MissingDependency.php
@@ -12,13 +12,14 @@
class MissingDependency {
/** @var string|null Custom message */
- private $message = null;
+ private ?string $message = null;
+ private bool $optional = false;
/**
* @param string $dependency
*/
public function __construct(
- private $dependency,
+ private readonly string $dependency,
) {
}
@@ -38,4 +39,12 @@ public function setMessage($message) {
$this->message = $message;
return $this;
}
+
+ public function isOptional(): bool {
+ return $this->optional;
+ }
+
+ public function setOptional(bool $optional): void {
+ $this->optional = $optional;
+ }
}
diff --git a/apps/files_external/lib/Service/BackendService.php b/apps/files_external/lib/Service/BackendService.php
index e37a0ab464965..c0c7118648d4f 100644
--- a/apps/files_external/lib/Service/BackendService.php
+++ b/apps/files_external/lib/Service/BackendService.php
@@ -12,6 +12,7 @@
use OCA\Files_External\Lib\Backend\Backend;
use OCA\Files_External\Lib\Config\IAuthMechanismProvider;
use OCA\Files_External\Lib\Config\IBackendProvider;
+use OCA\Files_External\Lib\MissingDependency;
use OCP\EventDispatcher\GenericEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
@@ -193,7 +194,8 @@ public function getBackends() {
*/
public function getAvailableBackends() {
return array_filter($this->getBackends(), function ($backend) {
- return !$backend->checkDependencies();
+ $missing = array_filter($backend->checkDependencies(), fn (MissingDependency $dependency) => !$dependency->isOptional());
+ return count($missing) === 0;
});
}