diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml index 285d5eb2a435f..e29479892b7f7 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 0b168b1170e43..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', @@ -96,6 +97,7 @@ 'OCA\\Files_External\\Lib\\Storage\\SMB' => $baseDir . '/../lib/Lib/Storage/SMB.php', 'OCA\\Files_External\\Lib\\Storage\\StreamWrapper' => $baseDir . '/../lib/Lib/Storage/StreamWrapper.php', 'OCA\\Files_External\\Lib\\Storage\\Swift' => $baseDir . '/../lib/Lib/Storage/Swift.php', + 'OCA\\Files_External\\Lib\\Storage\\SystemBridge' => $baseDir . '/../lib/Lib/Storage/SystemBridge.php', 'OCA\\Files_External\\Lib\\VisibilityTrait' => $baseDir . '/../lib/Lib/VisibilityTrait.php', 'OCA\\Files_External\\Listener\\GroupDeletedListener' => $baseDir . '/../lib/Listener/GroupDeletedListener.php', 'OCA\\Files_External\\Listener\\LoadAdditionalListener' => $baseDir . '/../lib/Listener/LoadAdditionalListener.php', diff --git a/apps/files_external/composer/composer/autoload_static.php b/apps/files_external/composer/composer/autoload_static.php index 29e95ae968a59..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', @@ -111,6 +112,7 @@ class ComposerStaticInitFiles_External 'OCA\\Files_External\\Lib\\Storage\\SMB' => __DIR__ . '/..' . '/../lib/Lib/Storage/SMB.php', 'OCA\\Files_External\\Lib\\Storage\\StreamWrapper' => __DIR__ . '/..' . '/../lib/Lib/Storage/StreamWrapper.php', 'OCA\\Files_External\\Lib\\Storage\\Swift' => __DIR__ . '/..' . '/../lib/Lib/Storage/Swift.php', + 'OCA\\Files_External\\Lib\\Storage\\SystemBridge' => __DIR__ . '/..' . '/../lib/Lib/Storage/SystemBridge.php', 'OCA\\Files_External\\Lib\\VisibilityTrait' => __DIR__ . '/..' . '/../lib/Lib/VisibilityTrait.php', 'OCA\\Files_External\\Listener\\GroupDeletedListener' => __DIR__ . '/..' . '/../lib/Listener/GroupDeletedListener.php', 'OCA\\Files_External\\Listener\\LoadAdditionalListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalListener.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..d2db8a8c9af08 --- /dev/null +++ b/apps/files_external/lib/Command/Dependencies.php @@ -0,0 +1,57 @@ +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 13da0417c1e49..4479ecdcaaa1c 100644 --- a/apps/files_external/lib/Lib/Backend/SMB.php +++ b/apps/files_external/lib/Lib/Backend/SMB.php @@ -11,19 +11,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') @@ -123,4 +124,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 987bd226675a1..e6d3250264472 100644 --- a/apps/files_external/lib/Lib/MissingDependency.php +++ b/apps/files_external/lib/Lib/MissingDependency.php @@ -11,18 +11,16 @@ * External storage backend dependency */ class MissingDependency { - - /** @var string */ - private $dependency; - /** @var string|null Custom message */ - private $message = null; + private ?string $message = null; + private bool $optional = false; /** * @param string $dependency */ - public function __construct($dependency) { - $this->dependency = $dependency; + public function __construct( + private string $dependency, + ) { } public function getDependency(): string { @@ -41,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/Lib/Storage/SMB.php b/apps/files_external/lib/Lib/Storage/SMB.php index 7ea615c739469..e0ee289696d29 100644 --- a/apps/files_external/lib/Lib/Storage/SMB.php +++ b/apps/files_external/lib/Lib/Storage/SMB.php @@ -5,6 +5,7 @@ * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-only */ + namespace OCA\Files_External\Lib\Storage; use Icewind\SMB\ACL; @@ -22,7 +23,7 @@ use Icewind\SMB\Native\NativeServer; use Icewind\SMB\Options; use Icewind\SMB\ServerFactory; -use Icewind\SMB\System; +use Icewind\SMB\Wrapped\Server; use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use OC\Files\Filesystem; @@ -93,7 +94,7 @@ public function __construct($params) { } $this->logger = $params['logger']; } else { - $this->logger = \OC::$server->get(LoggerInterface::class); + $this->logger = \OCP\Server::get(LoggerInterface::class); } $options = new Options(); @@ -103,7 +104,8 @@ public function __construct($params) { $options->setTimeout($timeout); } } - $serverFactory = new ServerFactory($options); + $system = \OCP\Server::get(SystemBridge::class); + $serverFactory = new ServerFactory($options, $system); $this->server = $serverFactory->createServer($params['host'], $auth); $this->share = $this->server->getShare(trim($params['share'], '/')); @@ -721,11 +723,9 @@ public function isDeletable($path) { /** * check if smbclient is installed */ - public static function checkDependencies() { - return ( - (bool) \OC_Helper::findBinaryPath('smbclient') - || NativeServer::available(new System()) - ) ? true : ['smbclient']; + public static function checkDependencies(): array|bool { + $system = \OCP\Server::get(SystemBridge::class); + return Server::available($system) || NativeServer::available($system) ?: ['smbclient']; } /** diff --git a/apps/files_external/lib/Lib/Storage/SystemBridge.php b/apps/files_external/lib/Lib/Storage/SystemBridge.php new file mode 100644 index 0000000000000..80449b2744bb6 --- /dev/null +++ b/apps/files_external/lib/Lib/Storage/SystemBridge.php @@ -0,0 +1,27 @@ + + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\Files_External\Lib\Storage; + +use Icewind\SMB\System; +use OCP\IBinaryFinder; + +/** + * Bridge the NC and SMB binary finding logic + */ +class SystemBridge extends System { + public function __construct( + private IBinaryFinder $binaryFinder, + ) { + } + + protected function getBinaryPath(string $binary): ?string { + $path = $this->binaryFinder->findBinaryPath($binary); + return $path !== false ? $path : null; + } +} diff --git a/apps/files_external/lib/Service/BackendService.php b/apps/files_external/lib/Service/BackendService.php index 8fe1ff31a7c6d..0535787e535a1 100644 --- a/apps/files_external/lib/Service/BackendService.php +++ b/apps/files_external/lib/Service/BackendService.php @@ -13,6 +13,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; @@ -199,7 +200,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; }); } diff --git a/lib/public/IBinaryFinder.php b/lib/public/IBinaryFinder.php index 3224ef523eda2..28cb62e5c56f0 100644 --- a/lib/public/IBinaryFinder.php +++ b/lib/public/IBinaryFinder.php @@ -11,7 +11,7 @@ /** * Service that find the binary path for a program. * - * This interface should be injected via depency injection and must + * This interface should be injected via dependency injection and must * not be implemented in applications. * * @since 25.0.0