Browse Source

Merge pull request #34624 from nextcloud/fix/files_external_psalm

Multiple fix for files external
tags/v26.0.0beta1
Carl Schwan 1 year ago
parent
commit
0f0f132959
No account linked to committer's email address
55 changed files with 539 additions and 768 deletions
  1. 4
    15
      apps/files_external/lib/Command/Applicable.php
  2. 2
    3
      apps/files_external/lib/Command/Backends.php
  3. 2
    5
      apps/files_external/lib/Command/Config.php
  4. 11
    25
      apps/files_external/lib/Command/Create.php
  5. 5
    20
      apps/files_external/lib/Command/Delete.php
  6. 1
    1
      apps/files_external/lib/Command/Export.php
  7. 9
    28
      apps/files_external/lib/Command/Import.php
  8. 8
    25
      apps/files_external/lib/Command/ListCommand.php
  9. 17
    27
      apps/files_external/lib/Command/Notify.php
  10. 1
    1
      apps/files_external/lib/Command/Option.php
  11. 2
    5
      apps/files_external/lib/Command/Verify.php
  12. 2
    2
      apps/files_external/lib/Controller/StoragesController.php
  13. 3
    1
      apps/files_external/lib/Lib/Auth/AuthMechanism.php
  14. 8
    9
      apps/files_external/lib/Lib/Backend/Backend.php
  15. 16
    38
      apps/files_external/lib/Lib/FrontendDefinitionTrait.php
  16. 56
    0
      apps/files_external/lib/Lib/IFrontendDefinition.php
  17. 27
    0
      apps/files_external/lib/Lib/IIdentifier.php
  18. 10
    34
      apps/files_external/lib/Lib/IdentifierTrait.php
  19. 4
    2
      apps/files_external/lib/Lib/LegacyDependencyCheckPolyfill.php
  20. 2
    8
      apps/files_external/lib/Lib/MissingDependency.php
  21. 0
    9
      apps/files_external/lib/Lib/PriorityTrait.php
  22. 68
    41
      apps/files_external/lib/Lib/Storage/AmazonS3.php
  23. 3
    3
      apps/files_external/lib/Lib/Storage/FTP.php
  24. 2
    2
      apps/files_external/lib/Lib/Storage/FtpConnection.php
  25. 2
    2
      apps/files_external/lib/Lib/Storage/SFTPReadStream.php
  26. 2
    2
      apps/files_external/lib/Lib/Storage/SFTPWriteStream.php
  27. 10
    10
      apps/files_external/lib/Lib/Storage/SMB.php
  28. 2
    2
      apps/files_external/lib/Lib/Storage/StreamWrapper.php
  29. 25
    25
      apps/files_external/lib/Lib/Storage/Swift.php
  30. 4
    4
      apps/files_external/lib/Lib/StorageConfig.php
  31. 6
    11
      apps/files_external/lib/MountConfig.php
  32. 1
    5
      apps/files_external/lib/Service/DBConfigService.php
  33. 1
    1
      apps/files_external/lib/Service/GlobalStoragesService.php
  34. 2
    1
      apps/files_external/lib/Service/StoragesService.php
  35. 1
    1
      apps/files_external/lib/Service/UserStoragesService.php
  36. 3
    1
      apps/files_external/templates/settings.php
  37. 7
    7
      apps/files_sharing/lib/SharedStorage.php
  38. 1
    182
      build/psalm-baseline.xml
  39. 4
    4
      lib/private/Files/Filesystem.php
  40. 5
    5
      lib/private/Files/ObjectStore/ObjectStoreStorage.php
  41. 15
    15
      lib/private/Files/Storage/Common.php
  42. 23
    23
      lib/private/Files/Storage/DAV.php
  43. 2
    2
      lib/private/Files/Storage/FailedStorage.php
  44. 21
    21
      lib/private/Files/Storage/Local.php
  45. 7
    7
      lib/private/Files/Storage/PolyFill/CopyDirectory.php
  46. 4
    4
      lib/private/Files/Storage/Wrapper/Availability.php
  47. 8
    8
      lib/private/Files/Storage/Wrapper/Encoding.php
  48. 21
    22
      lib/private/Files/Storage/Wrapper/Encryption.php
  49. 8
    8
      lib/private/Files/Storage/Wrapper/Jail.php
  50. 6
    6
      lib/private/Files/Storage/Wrapper/PermissionsMask.php
  51. 8
    8
      lib/private/Files/Storage/Wrapper/Wrapper.php
  52. 63
    63
      lib/private/Files/View.php
  53. 2
    2
      lib/private/Lockdown/Filesystem/NullStorage.php
  54. 6
    6
      lib/public/Files/Storage.php
  55. 6
    6
      lib/public/Files/Storage/IStorage.php

+ 4
- 15
apps/files_external/lib/Command/Applicable.php View File

@@ -36,20 +36,9 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class Applicable extends Base {
/**
* @var GlobalStoragesService
*/
protected $globalService;

/**
* @var IUserManager
*/
private $userManager;

/**
* @var IGroupManager
*/
private $groupManager;
protected GlobalStoragesService $globalService;
private IUserManager $userManager;
private IGroupManager $groupManager;

public function __construct(
GlobalStoragesService $globalService,
@@ -62,7 +51,7 @@ class Applicable extends Base {
$this->groupManager = $groupManager;
}

protected function configure() {
protected function configure(): void {
$this
->setName('files_external:applicable')
->setDescription('Manage applicable users and groups for a mount')

+ 2
- 3
apps/files_external/lib/Command/Backends.php View File

@@ -33,8 +33,7 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class Backends extends Base {
/** @var BackendService */
private $backendService;
private BackendService $backendService;

public function __construct(BackendService $backendService
) {
@@ -43,7 +42,7 @@ class Backends extends Base {
$this->backendService = $backendService;
}

protected function configure() {
protected function configure(): void {
$this
->setName('files_external:backends')
->setDescription('Show available authentication and storage backends')

+ 2
- 5
apps/files_external/lib/Command/Config.php View File

@@ -33,17 +33,14 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class Config extends Base {
/**
* @var GlobalStoragesService
*/
protected $globalService;
protected GlobalStoragesService $globalService;

public function __construct(GlobalStoragesService $globalService) {
parent::__construct();
$this->globalService = $globalService;
}

protected function configure() {
protected function configure(): void {
$this
->setName('files_external:config')
->setDescription('Manage backend configuration for a mount')

+ 11
- 25
apps/files_external/lib/Command/Create.php View File

@@ -34,6 +34,7 @@ use OCA\Files_External\Lib\StorageConfig;
use OCA\Files_External\Service\BackendService;
use OCA\Files_External\Service\GlobalStoragesService;
use OCA\Files_External\Service\UserStoragesService;
use OCA\Files_External\Service\StoragesService;
use OCP\IUserManager;
use OCP\IUserSession;
use Symfony\Component\Console\Input\ArrayInput;
@@ -43,26 +44,11 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class Create extends Base {
/**
* @var GlobalStoragesService
*/
private $globalService;

/**
* @var UserStoragesService
*/
private $userService;

/**
* @var IUserManager
*/
private $userManager;

/** @var BackendService */
private $backendService;

/** @var IUserSession */
private $userSession;
private GlobalStoragesService $globalService;
private UserStoragesService $userService;
private IUserManager $userManager;
private BackendService $backendService;
private IUserSession $userSession;

public function __construct(GlobalStoragesService $globalService,
UserStoragesService $userService,
@@ -78,7 +64,7 @@ class Create extends Base {
$this->backendService = $backendService;
}

protected function configure() {
protected function configure(): void {
$this
->setName('files_external:create')
->setDescription('Create a new mount configuration')
@@ -119,7 +105,7 @@ class Create extends Base {
}

protected function execute(InputInterface $input, OutputInterface $output): int {
$user = (string) $input->getOption('user');
$user = (string)$input->getOption('user');
$mountPoint = $input->getArgument('mount_point');
$storageIdentifier = $input->getArgument('storage_backend');
$authIdentifier = $input->getArgument('authentication_backend');
@@ -187,7 +173,7 @@ class Create extends Base {
return 0;
}

private function validateParam($key, &$value, Backend $storageBackend, AuthMechanism $authBackend) {
private function validateParam(string $key, &$value, Backend $storageBackend, AuthMechanism $authBackend): bool {
$params = array_merge($storageBackend->getParameters(), $authBackend->getParameters());
foreach ($params as $param) {
/** @var DefinitionParameter $param */
@@ -201,7 +187,7 @@ class Create extends Base {
return false;
}

private function showMount($user, StorageConfig $mount, InputInterface $input, OutputInterface $output) {
private function showMount(string $user, StorageConfig $mount, InputInterface $input, OutputInterface $output): void {
$listCommand = new ListCommand($this->globalService, $this->userService, $this->userSession, $this->userManager);
$listInput = new ArrayInput([], $listCommand->getDefinition());
$listInput->setOption('output', $input->getOption('output'));
@@ -209,7 +195,7 @@ class Create extends Base {
$listCommand->listMounts($user, [$mount], $listInput, $output);
}

protected function getStorageService($userId) {
protected function getStorageService(string $userId): StoragesService {
if (!empty($userId)) {
$user = $this->userManager->get($userId);
if (is_null($user)) {

+ 5
- 20
apps/files_external/lib/Command/Delete.php View File

@@ -37,25 +37,10 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;

class Delete extends Base {
/**
* @var GlobalStoragesService
*/
protected $globalService;

/**
* @var UserStoragesService
*/
protected $userService;

/**
* @var IUserSession
*/
protected $userSession;

/**
* @var IUserManager
*/
protected $userManager;
protected GlobalStoragesService $globalService;
protected UserStoragesService $userService;
protected IUserSession $userSession;
protected IUserManager $userManager;

public function __construct(GlobalStoragesService $globalService, UserStoragesService $userService, IUserSession $userSession, IUserManager $userManager) {
parent::__construct();
@@ -65,7 +50,7 @@ class Delete extends Base {
$this->userManager = $userManager;
}

protected function configure() {
protected function configure(): void {
$this
->setName('files_external:delete')
->setDescription('Delete an external mount')

+ 1
- 1
apps/files_external/lib/Command/Export.php View File

@@ -29,7 +29,7 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class Export extends ListCommand {
protected function configure() {
protected function configure(): void {
$this
->setName('files_external:export')
->setDescription('Export mount configurations')

+ 9
- 28
apps/files_external/lib/Command/Import.php View File

@@ -40,31 +40,12 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class Import extends Base {
/**
* @var GlobalStoragesService
*/
private $globalService;

/**
* @var UserStoragesService
*/
private $userService;

/**
* @var IUserSession
*/
private $userSession;

/**
* @var IUserManager
*/
private $userManager;

/** @var ImportLegacyStoragesService */
private $importLegacyStorageService;

/** @var BackendService */
private $backendService;
private GlobalStoragesService $globalService;
private UserStoragesService $userService;
private IUserSession $userSession;
private IUserManager $userManager;
private ImportLegacyStoragesService $importLegacyStorageService;
private BackendService $backendService;

public function __construct(GlobalStoragesService $globalService,
UserStoragesService $userService,
@@ -82,7 +63,7 @@ class Import extends Base {
$this->backendService = $backendService;
}

protected function configure() {
protected function configure(): void {
$this
->setName('files_external:import')
->setDescription('Import mount configurations')
@@ -189,7 +170,7 @@ class Import extends Base {
return 0;
}

private function parseData(array $data) {
private function parseData(array $data): StorageConfig {
$mount = new StorageConfig($data['mount_id']);
$mount->setMountPoint($data['mount_point']);
$mount->setBackend($this->getBackendByClass($data['storage']));
@@ -202,7 +183,7 @@ class Import extends Base {
return $mount;
}

private function getBackendByClass($className) {
private function getBackendByClass(string $className) {
$backends = $this->backendService->getBackends();
foreach ($backends as $backend) {
if ($backend->getStorageClass() === $className) {

+ 8
- 25
apps/files_external/lib/Command/ListCommand.php View File

@@ -39,25 +39,10 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class ListCommand extends Base {
/**
* @var GlobalStoragesService
*/
protected $globalService;

/**
* @var UserStoragesService
*/
protected $userService;

/**
* @var IUserSession
*/
protected $userSession;

/**
* @var IUserManager
*/
protected $userManager;
protected GlobalStoragesService $globalService;
protected UserStoragesService $userService;
protected IUserSession $userSession;
protected IUserManager $userManager;

public const ALL = -1;

@@ -69,7 +54,7 @@ class ListCommand extends Base {
$this->userManager = $userManager;
}

protected function configure() {
protected function configure(): void {
$this
->setName('files_external:list')
->setDescription('List configured admin or personal mounts')
@@ -102,7 +87,7 @@ class ListCommand extends Base {
$mounts = $this->globalService->getStorageForAllUsers();
$userId = self::ALL;
} else {
$userId = $input->getArgument('user_id');
$userId = (string)$input->getArgument('user_id');
$storageService = $this->getStorageService($userId);
$mounts = $storageService->getAllStorages();
}
@@ -112,12 +97,10 @@ class ListCommand extends Base {
}

/**
* @param string $userId
* @param ?string|ListCommand::ALL $userId
* @param StorageConfig[] $mounts
* @param InputInterface $input
* @param OutputInterface $output
*/
public function listMounts($userId, array $mounts, InputInterface $input, OutputInterface $output) {
public function listMounts($userId, array $mounts, InputInterface $input, OutputInterface $output): void {
$outputType = $input->getOption('output');
if (count($mounts) === 0) {
if ($outputType === self::OUTPUT_FORMAT_JSON || $outputType === self::OUTPUT_FORMAT_JSON_PRETTY) {

+ 17
- 27
apps/files_external/lib/Command/Notify.php View File

@@ -39,27 +39,24 @@ use OCP\Files\Storage\INotifyStorage;
use OCP\Files\Storage\IStorage;
use OCP\Files\StorageNotAvailableException;
use OCP\IDBConnection;
use OCP\ILogger;
use OCP\IUserManager;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class Notify extends Base {
/** @var GlobalStoragesService */
private $globalService;
/** @var IDBConnection */
private $connection;
/** @var ILogger */
private $logger;
private GlobalStoragesService $globalService;
private IDBConnection $connection;
private LoggerInterface $logger;
/** @var IUserManager */
private $userManager;

public function __construct(
GlobalStoragesService $globalService,
IDBConnection $connection,
ILogger $logger,
LoggerInterface $logger,
IUserManager $userManager
) {
parent::__construct();
@@ -69,7 +66,7 @@ class Notify extends Base {
$this->userManager = $userManager;
}

protected function configure() {
protected function configure(): void {
$this
->setName('files_external:notify')
->setDescription('Listen for active update notifications for a configured external mount')
@@ -207,7 +204,7 @@ class Notify extends Base {
return 0;
}

private function createStorage(StorageConfig $mount) {
private function createStorage(StorageConfig $mount): IStorage {
$class = $mount->getBackend()->getStorageClass();
return new $class($mount->getBackendOptions());
}
@@ -221,7 +218,7 @@ class Notify extends Base {
try {
$storages = $this->getStorageIds($mountId, $parent);
} catch (DriverException $ex) {
$this->logger->logException($ex, ['message' => 'Error while trying to find correct storage ids.', 'level' => ILogger::WARN]);
$this->logger->warning('Error while trying to find correct storage ids.', ['exception' => $ex]);
$this->connection = $this->reconnectToDatabase($this->connection, $output);
$output->writeln('<info>Needed to reconnect to the database</info>');
$storages = $this->getStorageIds($mountId, $path);
@@ -292,37 +289,30 @@ class Notify extends Base {
->fetchAll();
}

/**
* @param array $storageIds
* @param string $parent
* @return int
*/
private function updateParent($storageIds, $parent) {
$pathHash = md5(trim(\OC_Util::normalizeUnicode($parent), '/'));
private function updateParent(array $storageIds, string $parent): int {
$pathHash = md5(trim((string)\OC_Util::normalizeUnicode($parent), '/'));
$qb = $this->connection->getQueryBuilder();
return $qb
->update('filecache')
->set('size', $qb->createNamedParameter(-1, IQueryBuilder::PARAM_INT))
->where($qb->expr()->in('storage', $qb->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY, ':storage_ids')))
->andWhere($qb->expr()->eq('path_hash', $qb->createNamedParameter($pathHash, IQueryBuilder::PARAM_STR)))
->execute();
->executeStatement();
}

/**
* @return \OCP\IDBConnection
*/
private function reconnectToDatabase(IDBConnection $connection, OutputInterface $output) {
private function reconnectToDatabase(IDBConnection $connection, OutputInterface $output): IDBConnection {
try {
$connection->close();
} catch (\Exception $ex) {
$this->logger->logException($ex, ['app' => 'files_external', 'message' => 'Error while disconnecting from DB', 'level' => ILogger::WARN]);
$this->logger->warning('Error while disconnecting from DB', ['exception' => $ex]);
$output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
}
while (!$connection->isConnected()) {
$connected = false;
while (!$connected) {
try {
$connection->connect();
$connected = $connection->connect();
} catch (\Exception $ex) {
$this->logger->logException($ex, ['app' => 'files_external', 'message' => 'Error while re-connecting to database', 'level' => ILogger::WARN]);
$this->logger->warning('Error while re-connecting to database', ['exception' => $ex]);
$output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
sleep(60);
}

+ 1
- 1
apps/files_external/lib/Command/Option.php View File

@@ -27,7 +27,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;

class Option extends Config {
protected function configure() {
protected function configure(): void {
$this
->setName('files_external:option')
->setDescription('Manage mount options for a mount')

+ 2
- 5
apps/files_external/lib/Command/Verify.php View File

@@ -38,17 +38,14 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class Verify extends Base {
/**
* @var GlobalStoragesService
*/
protected $globalService;
protected GlobalStoragesService $globalService;

public function __construct(GlobalStoragesService $globalService) {
parent::__construct();
$this->globalService = $globalService;
}

protected function configure() {
protected function configure(): void {
$this
->setName('files_external:verify')
->setDescription('Verify mount configuration')

+ 2
- 2
apps/files_external/lib/Controller/StoragesController.php View File

@@ -294,12 +294,12 @@ abstract class StoragesController extends Controller {
} catch (InsufficientDataForMeaningfulAnswerException $e) {
$status = $e->getCode() ? $e->getCode() : StorageNotAvailableException::STATUS_INDETERMINATE;
$storage->setStatus(
$status,
(int)$status,
$this->l10n->t('Insufficient data: %s', [$e->getMessage()])
);
} catch (StorageNotAvailableException $e) {
$storage->setStatus(
$e->getCode(),
(int)$e->getCode(),
$this->l10n->t('%s', [$e->getMessage()])
);
} catch (\Exception $e) {

+ 3
- 1
apps/files_external/lib/Lib/Auth/AuthMechanism.php View File

@@ -29,6 +29,8 @@ use OCA\Files_External\Lib\IdentifierTrait;
use OCA\Files_External\Lib\StorageConfig;
use OCA\Files_External\Lib\StorageModifierTrait;
use OCA\Files_External\Lib\VisibilityTrait;
use OCA\Files_External\Lib\IIdentifier;
use OCA\Files_External\Lib\IFrontendDefinition;

/**
* Authentication mechanism
@@ -50,7 +52,7 @@ use OCA\Files_External\Lib\VisibilityTrait;
* - StorageModifierTrait
* Object can affect storage mounting
*/
class AuthMechanism implements \JsonSerializable {
class AuthMechanism implements \JsonSerializable, IIdentifier, IFrontendDefinition {
/** Standard authentication schemes */
public const SCHEME_NULL = 'null';
public const SCHEME_BUILTIN = 'builtin';

+ 8
- 9
apps/files_external/lib/Lib/Backend/Backend.php View File

@@ -30,6 +30,9 @@ use OCA\Files_External\Lib\PriorityTrait;
use OCA\Files_External\Lib\StorageConfig;
use OCA\Files_External\Lib\StorageModifierTrait;
use OCA\Files_External\Lib\VisibilityTrait;
use OCA\Files_External\Lib\IIdentifier;
use OCA\Files_External\Lib\IFrontendDefinition;
use OCP\Files\Storage\IStorage;

/**
* Storage backend
@@ -55,7 +58,7 @@ use OCA\Files_External\Lib\VisibilityTrait;
* - StorageModifierTrait
* Object can affect storage mounting
*/
class Backend implements \JsonSerializable {
class Backend implements \JsonSerializable, IIdentifier, IFrontendDefinition {
use VisibilityTrait;
use FrontendDefinitionTrait;
use PriorityTrait;
@@ -73,7 +76,7 @@ class Backend implements \JsonSerializable {
private $legacyAuthMechanism;

/**
* @return string
* @return class-string<IStorage>
*/
public function getStorageClass() {
return $this->storageClass;
@@ -118,21 +121,17 @@ class Backend implements \JsonSerializable {
return $this->legacyAuthMechanism;
}

/**
* @param AuthMechanism $authMechanism
* @return self
*/
public function setLegacyAuthMechanism(AuthMechanism $authMechanism) {
public function setLegacyAuthMechanism(AuthMechanism $authMechanism): self {
$this->legacyAuthMechanism = $authMechanism;
return $this;
}

/**
* @param callable $callback dynamic auth mechanism selection
* @return self
*/
public function setLegacyAuthMechanismCallback(callable $callback) {
public function setLegacyAuthMechanismCallback(callable $callback): self {
$this->legacyAuthMechanism = $callback;
return $this;
}

/**

+ 16
- 38
apps/files_external/lib/Lib/FrontendDefinitionTrait.php View File

@@ -29,62 +29,45 @@ namespace OCA\Files_External\Lib;
trait FrontendDefinitionTrait {

/** @var string human-readable mechanism name */
private $text;
private string $text = "";

/** @var DefinitionParameter[] parameters for mechanism */
private $parameters = [];
/** @var array<string, DefinitionParameter> parameters for mechanism */
private array $parameters = [];

/** @var string[] custom JS */
private $customJs = [];
private array $customJs = [];

/**
* @return string
*/
public function getText() {
public function getText(): string {
return $this->text;
}

/**
* @param string $text
* @return $this
*/
public function setText($text) {
public function setText(string $text): self {
$this->text = $text;
return $this;
}

/**
* @param FrontendDefinitionTrait $a
* @param FrontendDefinitionTrait $b
* @return int
*/
public static function lexicalCompare(FrontendDefinitionTrait $a, FrontendDefinitionTrait $b) {
public static function lexicalCompare(IFrontendDefinition $a, IFrontendDefinition $b): int {
return strcmp($a->getText(), $b->getText());
}

/**
* @return DefinitionParameter[]
* @return array<string, DefinitionParameter>
*/
public function getParameters() {
public function getParameters(): array {
return $this->parameters;
}

/**
* @param DefinitionParameter[] $parameters
* @return self
* @param list<DefinitionParameter> $parameters
*/
public function addParameters(array $parameters) {
public function addParameters(array $parameters): self {
foreach ($parameters as $parameter) {
$this->addParameter($parameter);
}
return $this;
}

/**
* @param DefinitionParameter $parameter
* @return self
*/
public function addParameter(DefinitionParameter $parameter) {
public function addParameter(DefinitionParameter $parameter): self {
$this->parameters[$parameter->getName()] = $parameter;
return $this;
}
@@ -92,7 +75,7 @@ trait FrontendDefinitionTrait {
/**
* @return string[]
*/
public function getCustomJs() {
public function getCustomJs(): array {
return $this->customJs;
}

@@ -100,17 +83,15 @@ trait FrontendDefinitionTrait {
* @param string $custom
* @return self
*/
public function addCustomJs($custom) {
public function addCustomJs(string $custom): self {
$this->customJs[] = $custom;
return $this;
}

/**
* Serialize into JSON for client-side JS
*
* @return array
*/
public function jsonSerializeDefinition() {
public function jsonSerializeDefinition(): array {
$configuration = [];
foreach ($this->getParameters() as $parameter) {
$configuration[$parameter->getName()] = $parameter;
@@ -126,11 +107,8 @@ trait FrontendDefinitionTrait {

/**
* Check if parameters are satisfied in a StorageConfig
*
* @param StorageConfig $storage
* @return bool
*/
public function validateStorageDefinition(StorageConfig $storage) {
public function validateStorageDefinition(StorageConfig $storage): bool {
foreach ($this->getParameters() as $name => $parameter) {
$value = $storage->getBackendOption($name);
if (!is_null($value) || !$parameter->isOptional()) {

+ 56
- 0
apps/files_external/lib/Lib/IFrontendDefinition.php View File

@@ -0,0 +1,56 @@
<?php
/**
* @copyright 2022 Carl Schwan <carl@carlschwan.eu>
*
* @license AGPL-3.0-or-later
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_External\Lib;

interface IFrontendDefinition {

public function getText(): string;

public function setText(string $text): self;

/**
* @return array<string, DefinitionParameter>
*/
public function getParameters(): array;

/**
* @param list<DefinitionParameter> $parameters
*/
public function addParameters(array $parameters): self;

public function addParameter(DefinitionParameter $parameter): self;

/**
* @return string[]
*/
public function getCustomJs(): array;

public function addCustomJs(string $custom): self;

/**
* Serialize into JSON for client-side JS
*/
public function jsonSerializeDefinition(): array;

/**
* Check if parameters are satisfied in a StorageConfig
*/
public function validateStorageDefinition(StorageConfig $storage): bool;
}

+ 27
- 0
apps/files_external/lib/Lib/IIdentifier.php View File

@@ -0,0 +1,27 @@
<?php
/**
* @copyright 2022 Carl Schwan <carl@carlschwan.eu>
*
* @license AGPL-3.0-or-later
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_External\Lib;

interface IIdentifier {

public function getIdentifier(): string;

public function setIdentifier(string $identifier): self;
}

+ 10
- 34
apps/files_external/lib/Lib/IdentifierTrait.php View File

@@ -28,27 +28,17 @@ namespace OCA\Files_External\Lib;
*/
trait IdentifierTrait {

/** @var string */
protected $identifier;
protected string $identifier = '';

/** @var string[] */
protected $identifierAliases = [];
protected array $identifierAliases = [];
protected ?IIdentifier $deprecateTo = null;

/** @var IdentifierTrait */
protected $deprecateTo = null;

/**
* @return string
*/
public function getIdentifier() {
public function getIdentifier(): string {
return $this->identifier;
}

/**
* @param string $identifier
* @return $this
*/
public function setIdentifier($identifier) {
public function setIdentifier(string $identifier): self {
$this->identifier = $identifier;
$this->identifierAliases[] = $identifier;
return $this;
@@ -57,39 +47,25 @@ trait IdentifierTrait {
/**
* @return string[]
*/
public function getIdentifierAliases() {
public function getIdentifierAliases(): array {
return $this->identifierAliases;
}

/**
* @param string $alias
* @return $this
*/
public function addIdentifierAlias($alias) {
public function addIdentifierAlias(string $alias): self {
$this->identifierAliases[] = $alias;
return $this;
}

/**
* @return object|null
*/
public function getDeprecateTo() {
public function getDeprecateTo(): ?IIdentifier {
return $this->deprecateTo;
}

/**
* @param object $destinationObject
* @return self
*/
public function deprecateTo($destinationObject) {
public function deprecateTo(IIdentifier $destinationObject): self {
$this->deprecateTo = $destinationObject;
return $this;
}

/**
* @return array
*/
public function jsonSerializeIdentifier() {
public function jsonSerializeIdentifier(): array {
$data = [
'identifier' => $this->identifier,
'identifierAliases' => $this->identifierAliases,

+ 4
- 2
apps/files_external/lib/Lib/LegacyDependencyCheckPolyfill.php View File

@@ -21,13 +21,15 @@
*/
namespace OCA\Files_External\Lib;

use OCP\Files\Storage\IStorage;

/**
* Polyfill for checking dependencies using legacy Storage::checkDependencies()
*/
trait LegacyDependencyCheckPolyfill {

/**
* @return string
* @return class-string<IStorage>
*/
abstract public function getStorageClass();

@@ -54,7 +56,7 @@ trait LegacyDependencyCheckPolyfill {
$module = $key;
$message = $value;
}
$value = new MissingDependency($module, $this);
$value = new MissingDependency($module);
$value->setMessage($message);
}
$ret[] = $value;

+ 2
- 8
apps/files_external/lib/Lib/MissingDependency.php View File

@@ -39,17 +39,11 @@ class MissingDependency {
$this->dependency = $dependency;
}

/**
* @return string
*/
public function getDependency() {
public function getDependency(): string {
return $this->dependency;
}

/**
* @return string|null
*/
public function getMessage() {
public function getMessage(): ?string {
return $this->message;
}


+ 0
- 9
apps/files_external/lib/Lib/PriorityTrait.php View File

@@ -47,13 +47,4 @@ trait PriorityTrait {
$this->priority = $priority;
return $this;
}

/**
* @param PriorityTrait $a
* @param PriorityTrait $b
* @return int
*/
public static function priorityCompare(PriorityTrait $a, PriorityTrait $b) {
return ($a->getPriority() - $b->getPriority());
}
}

+ 68
- 41
apps/files_external/lib/Lib/Storage/AmazonS3.php View File

@@ -55,11 +55,14 @@ use OCP\ICacheFactory;
use OCP\IMemcache;
use OCP\Server;
use OCP\ICache;
use Psr\Log\LoggerInterface;

class AmazonS3 extends \OC\Files\Storage\Common {
use S3ConnectionTrait;
use S3ObjectTrait;

private LoggerInterface $logger;

public function needsPartFile() {
return false;
}
@@ -88,6 +91,7 @@ class AmazonS3 extends \OC\Files\Storage\Common {
/** @var ICacheFactory $cacheFactory */
$cacheFactory = Server::get(ICacheFactory::class);
$this->memCache = $cacheFactory->createLocal('s3-external');
$this->logger = Server::get(LoggerInterface::class);
}

/**
@@ -255,7 +259,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
]);
$this->testTimeout();
} catch (S3Exception $e) {
\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
$this->logger->error($e->getMessage(), [
'app' => 'files_external',
'exception' => $e,
]);
return false;
}

@@ -286,18 +293,11 @@ class AmazonS3 extends \OC\Files\Storage\Common {

protected function clearBucket() {
$this->clearCache();
try {
$this->getConnection()->clearBucket([
"Bucket" => $this->bucket
]);
return true;
// clearBucket() is not working with Ceph, so if it fails we try the slower approach
} catch (\Exception $e) {
return $this->batchDelete();
}
return $this->batchDelete();
}

private function batchDelete($path = null) {
// TODO explore using https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.S3.BatchDelete.html
$params = [
'Bucket' => $this->bucket
];
@@ -327,7 +327,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
$this->deleteObject($path);
}
} catch (S3Exception $e) {
\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
$this->logger->error($e->getMessage(), [
'app' => 'files_external',
'exception' => $e,
]);
return false;
}
return true;
@@ -415,7 +418,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
try {
return $this->doesDirectoryExist($path);
} catch (S3Exception $e) {
\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
$this->logger->error($e->getMessage(), [
'app' => 'files_external',
'exception' => $e,
]);
return false;
}
}
@@ -438,7 +444,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
return 'dir';
}
} catch (S3Exception $e) {
\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
$this->logger->error($e->getMessage(), [
'app' => 'files_external',
'exception' => $e,
]);
return false;
}

@@ -464,7 +473,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
$this->deleteObject($path);
$this->invalidateCache($path);
} catch (S3Exception $e) {
\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
$this->logger->error($e->getMessage(), [
'app' => 'files_external',
'exception' => $e,
]);
return false;
}

@@ -486,7 +498,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
try {
return $this->readObject($path);
} catch (S3Exception $e) {
\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
$this->logger->error($e->getMessage(), [
'app' => 'files_external',
'exception' => $e,
]);
return false;
}
case 'w':
@@ -548,7 +563,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
$this->testTimeout();
}
} catch (S3Exception $e) {
\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
$this->logger->error($e->getMessage(), [
'app' => 'files_external',
'exception' => $e,
]);
return false;
}

@@ -556,65 +574,71 @@ class AmazonS3 extends \OC\Files\Storage\Common {
return true;
}

public function copy($path1, $path2, $isFile = null) {
$path1 = $this->normalizePath($path1);
$path2 = $this->normalizePath($path2);
public function copy($source, $target, $isFile = null) {
$source = $this->normalizePath($source);
$target = $this->normalizePath($target);

if ($isFile === true || $this->is_file($path1)) {
if ($isFile === true || $this->is_file($source)) {
try {
$this->getConnection()->copyObject([
'Bucket' => $this->bucket,
'Key' => $this->cleanKey($path2),
'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1)
'Key' => $this->cleanKey($target),
'CopySource' => S3Client::encodeKey($this->bucket . '/' . $source)
]);
$this->testTimeout();
} catch (S3Exception $e) {
\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
$this->logger->error($e->getMessage(), [
'app' => 'files_external',
'exception' => $e,
]);
return false;
}
} else {
$this->remove($path2);
$this->remove($target);

try {
$this->mkdir($path2);
$this->mkdir($target);
$this->testTimeout();
} catch (S3Exception $e) {
\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
$this->logger->error($e->getMessage(), [
'app' => 'files_external',
'exception' => $e,
]);
return false;
}

foreach ($this->getDirectoryContent($path1) as $item) {
$source = $path1 . '/' . $item['name'];
$target = $path2 . '/' . $item['name'];
foreach ($this->getDirectoryContent($source) as $item) {
$source = $source . '/' . $item['name'];
$target = $target . '/' . $item['name'];
$this->copy($source, $target, $item['mimetype'] !== FileInfo::MIMETYPE_FOLDER);
}
}

$this->invalidateCache($path2);
$this->invalidateCache($target);

return true;
}

public function rename($path1, $path2) {
$path1 = $this->normalizePath($path1);
$path2 = $this->normalizePath($path2);
public function rename($source, $target) {
$source = $this->normalizePath($source);
$target = $this->normalizePath($target);

if ($this->is_file($path1)) {
if ($this->copy($path1, $path2) === false) {
if ($this->is_file($source)) {
if ($this->copy($source, $target) === false) {
return false;
}

if ($this->unlink($path1) === false) {
$this->unlink($path2);
if ($this->unlink($source) === false) {
$this->unlink($target);
return false;
}
} else {
if ($this->copy($path1, $path2) === false) {
if ($this->copy($source, $target) === false) {
return false;
}

if ($this->rmdir($path1) === false) {
$this->rmdir($path2);
if ($this->rmdir($source) === false) {
$this->rmdir($target);
return false;
}
}
@@ -642,7 +666,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
unlink($tmpFile);
return true;
} catch (S3Exception $e) {
\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
$this->logger->error($e->getMessage(), [
'app' => 'files_external',
'exception' => $e,
]);
return false;
}
}

+ 3
- 3
apps/files_external/lib/Lib/Storage/FTP.php View File

@@ -333,9 +333,9 @@ class FTP extends Common {
}
}

public function rename($path1, $path2) {
$this->unlink($path2);
return $this->getConnection()->rename($this->buildPath($path1), $this->buildPath($path2));
public function rename($source, $target) {
$this->unlink($target);
return $this->getConnection()->rename($this->buildPath($source), $this->buildPath($target));
}

public function getDirectoryContent($directory): \Traversable {

+ 2
- 2
apps/files_external/lib/Lib/Storage/FtpConnection.php View File

@@ -85,8 +85,8 @@ class FtpConnection {
return @ftp_rmdir($this->connection, $path);
}

public function rename(string $path1, string $path2) {
return @ftp_rename($this->connection, $path1, $path2);
public function rename(string $source, string $target) {
return @ftp_rename($this->connection, $source, $target);
}

public function mdtm(string $path) {

+ 2
- 2
apps/files_external/lib/Lib/Storage/SFTPReadStream.php View File

@@ -36,7 +36,7 @@ class SFTPReadStream implements File {
/** @var \phpseclib\Net\SFTP */
private $sftp;

/** @var resource */
/** @var string */
private $handle;

/** @var int */
@@ -61,7 +61,6 @@ class SFTPReadStream implements File {
* Load the source from the stream context and return the context options
*
* @param string $name
* @return array
* @throws \BadMethodCallException
*/
protected function loadContext($name) {
@@ -202,5 +201,6 @@ class SFTPReadStream implements File {
if (!$this->sftp->_close_handle($this->handle)) {
return false;
}
return true;
}
}

+ 2
- 2
apps/files_external/lib/Lib/Storage/SFTPWriteStream.php View File

@@ -36,7 +36,7 @@ class SFTPWriteStream implements File {
/** @var \phpseclib\Net\SFTP */
private $sftp;

/** @var resource */
/** @var string */
private $handle;

/** @var int */
@@ -61,7 +61,6 @@ class SFTPWriteStream implements File {
* Load the source from the stream context and return the context options
*
* @param string $name
* @return array
* @throws \BadMethodCallException
*/
protected function loadContext($name) {
@@ -180,5 +179,6 @@ class SFTPWriteStream implements File {
if (!$this->sftp->_close_handle($this->handle)) {
return false;
}
return true;
}
}

+ 10
- 10
apps/files_external/lib/Lib/Storage/SMB.php View File

@@ -282,7 +282,7 @@ class SMB extends Common implements INotifyStorage {
}
} catch (ConnectException $e) {
$this->logger->logException($e, ['message' => 'Error while getting folder content']);
throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
throw new StorageNotAvailableException($e->getMessage(), (int)$e->getCode(), $e);
}
}

@@ -310,7 +310,7 @@ class SMB extends Common implements INotifyStorage {
* @param string $target the new name of the path
* @return bool true if the rename is successful, false otherwise
*/
public function rename($source, $target, $retry = true) {
public function rename($source, $target, $retry = true): bool {
if ($this->isRootDir($source) || $this->isRootDir($target)) {
return false;
}
@@ -322,7 +322,7 @@ class SMB extends Common implements INotifyStorage {
} catch (AlreadyExistsException $e) {
if ($retry) {
$this->remove($target);
$result = $this->share->rename($absoluteSource, $absoluteTarget, false);
$result = $this->share->rename($absoluteSource, $absoluteTarget);
} else {
$this->logger->logException($e, ['level' => ILogger::WARN]);
return false;
@@ -330,7 +330,7 @@ class SMB extends Common implements INotifyStorage {
} catch (InvalidArgumentException $e) {
if ($retry) {
$this->remove($target);
$result = $this->share->rename($absoluteSource, $absoluteTarget, false);
$result = $this->share->rename($absoluteSource, $absoluteTarget);
} else {
$this->logger->logException($e, ['level' => ILogger::WARN]);
return false;
@@ -428,7 +428,7 @@ class SMB extends Common implements INotifyStorage {
return false;
} catch (ConnectException $e) {
$this->logger->logException($e, ['message' => 'Error while deleting file']);
throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
throw new StorageNotAvailableException($e->getMessage(), (int)$e->getCode(), $e);
}
}

@@ -515,7 +515,7 @@ class SMB extends Common implements INotifyStorage {
throw new EntityTooLargeException("not enough available space to create file", 0, $e);
} catch (ConnectException $e) {
$this->logger->logException($e, ['message' => 'Error while opening file']);
throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
throw new StorageNotAvailableException($e->getMessage(), (int)$e->getCode(), $e);
}
}

@@ -542,7 +542,7 @@ class SMB extends Common implements INotifyStorage {
return false;
} catch (ConnectException $e) {
$this->logger->logException($e, ['message' => 'Error while removing folder']);
throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
throw new StorageNotAvailableException($e->getMessage(), (int)$e->getCode(), $e);
}
}

@@ -558,7 +558,7 @@ class SMB extends Common implements INotifyStorage {
throw new EntityTooLargeException("not enough available space to create file", 0, $e);
} catch (ConnectException $e) {
$this->logger->logException($e, ['message' => 'Error while creating file']);
throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
throw new StorageNotAvailableException($e->getMessage(), (int)$e->getCode(), $e);
}
}

@@ -655,7 +655,7 @@ class SMB extends Common implements INotifyStorage {
return true;
} catch (ConnectException $e) {
$this->logger->logException($e, ['message' => 'Error while creating folder']);
throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
throw new StorageNotAvailableException($e->getMessage(), (int)$e->getCode(), $e);
} catch (Exception $e) {
return false;
}
@@ -670,7 +670,7 @@ class SMB extends Common implements INotifyStorage {
} catch (ForbiddenException $e) {
return false;
} catch (ConnectException $e) {
throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
throw new StorageNotAvailableException($e->getMessage(), (int)$e->getCode(), $e);
}
}


+ 2
- 2
apps/files_external/lib/Lib/Storage/StreamWrapper.php View File

@@ -117,8 +117,8 @@ abstract class StreamWrapper extends \OC\Files\Storage\Common {
return copy($path, $this->constructUrl($target));
}

public function rename($path1, $path2) {
return rename($this->constructUrl($path1), $this->constructUrl($path2));
public function rename($source, $target) {
return rename($this->constructUrl($source), $this->constructUrl($target));
}

public function stat($path) {

+ 25
- 25
apps/files_external/lib/Lib/Storage/Swift.php View File

@@ -482,25 +482,25 @@ class Swift extends \OC\Files\Storage\Common {
}
}

public function copy($path1, $path2) {
$path1 = $this->normalizePath($path1);
$path2 = $this->normalizePath($path2);
public function copy($source, $target) {
$source = $this->normalizePath($source);
$target = $this->normalizePath($target);

$fileType = $this->filetype($path1);
$fileType = $this->filetype($source);
if ($fileType) {
// make way
$this->unlink($path2);
$this->unlink($target);
}

if ($fileType === 'file') {
try {
$source = $this->fetchObject($path1);
$source->copy([
'destination' => $this->bucket . '/' . $path2
$sourceObject = $this->fetchObject($source);
$sourceObject->copy([
'destination' => $this->bucket . '/' . $target
]);
// invalidate target object to force repopulation on fetch
$this->objectCache->remove($path2);
$this->objectCache->remove($path2 . '/');
$this->objectCache->remove($target);
$this->objectCache->remove($target . '/');
} catch (BadResponseError $e) {
\OC::$server->get(LoggerInterface::class)->error($e->getMessage(), [
'exception' => $e,
@@ -510,13 +510,13 @@ class Swift extends \OC\Files\Storage\Common {
}
} elseif ($fileType === 'dir') {
try {
$source = $this->fetchObject($path1 . '/');
$source->copy([
'destination' => $this->bucket . '/' . $path2 . '/'
$sourceObject = $this->fetchObject($source . '/');
$sourceObject->copy([
'destination' => $this->bucket . '/' . $target . '/'
]);
// invalidate target object to force repopulation on fetch
$this->objectCache->remove($path2);
$this->objectCache->remove($path2 . '/');
$this->objectCache->remove($target);
$this->objectCache->remove($target . '/');
} catch (BadResponseError $e) {
\OC::$server->get(LoggerInterface::class)->error($e->getMessage(), [
'exception' => $e,
@@ -525,14 +525,14 @@ class Swift extends \OC\Files\Storage\Common {
return false;
}

$dh = $this->opendir($path1);
$dh = $this->opendir($source);
while ($file = readdir($dh)) {
if (\OC\Files\Filesystem::isIgnoredDir($file)) {
continue;
}

$source = $path1 . '/' . $file;
$target = $path2 . '/' . $file;
$source = $source . '/' . $file;
$target = $target . '/' . $file;
$this->copy($source, $target);
}
} else {
@@ -543,22 +543,22 @@ class Swift extends \OC\Files\Storage\Common {
return true;
}

public function rename($path1, $path2) {
$path1 = $this->normalizePath($path1);
$path2 = $this->normalizePath($path2);
public function rename($source, $target) {
$source = $this->normalizePath($source);
$target = $this->normalizePath($target);

$fileType = $this->filetype($path1);
$fileType = $this->filetype($source);

if ($fileType === 'dir' || $fileType === 'file') {
// copy
if ($this->copy($path1, $path2) === false) {
if ($this->copy($source, $target) === false) {
return false;
}

// cleanup
if ($this->unlink($path1) === false) {
if ($this->unlink($source) === false) {
throw new \Exception('failed to remove original');
$this->unlink($path2);
$this->unlink($target);
return false;
}


+ 4
- 4
apps/files_external/lib/Lib/StorageConfig.php View File

@@ -126,17 +126,17 @@ class StorageConfig implements \JsonSerializable {
/**
* Creates a storage config
*
* @param int|null $id config id or null for a new config
* @param int|string $id config id or null for a new config
*/
public function __construct($id = null) {
$this->id = $id;
$this->id = $id ?? -1;
$this->mountOptions['enable_sharing'] = false;
}

/**
* Returns the configuration id
*
* @return int
* @retun int
*/
public function getId() {
return $this->id;
@@ -147,7 +147,7 @@ class StorageConfig implements \JsonSerializable {
*
* @param int $id configuration id
*/
public function setId($id) {
public function setId(int $id): void {
$this->id = $id;
}


+ 6
- 11
apps/files_external/lib/MountConfig.php View File

@@ -150,17 +150,17 @@ class MountConfig {
* TODO: move into AppFramework along with templates
*
* @param Backend[] $backends
* @return string
*/
public static function dependencyMessage($backends) {
public static function dependencyMessage(array $backends): string {
$l = \OC::$server->getL10N('files_external');
$message = '';
$dependencyGroups = [];

foreach ($backends as $backend) {
foreach ($backend->checkDependencies() as $dependency) {
if ($message = $dependency->getMessage()) {
$message .= '<p>' . $message . '</p>';
$dependencyMessage = $dependency->getMessage();
if ($dependencyMessage !== null) {
$message .= '<p>' . $dependencyMessage . '</p>';
} else {
$dependencyGroups[$dependency->getDependency()][] = $backend;
}
@@ -168,7 +168,7 @@ class MountConfig {
}

foreach ($dependencyGroups as $module => $dependants) {
$backends = implode(', ', array_map(function ($backend) {
$backends = implode(', ', array_map(function (Backend $backend): string {
return '"' . $backend->getText() . '"';
}, $dependants));
$message .= '<p>' . MountConfig::getSingleDependencyMessage($l, $module, $backends) . '</p>';
@@ -179,13 +179,8 @@ class MountConfig {

/**
* Returns a dependency missing message
*
* @param \OCP\IL10N $l
* @param string $module
* @param string $backend
* @return string
*/
private static function getSingleDependencyMessage(\OCP\IL10N $l, $module, $backend) {
private static function getSingleDependencyMessage(\OCP\IL10N $l, string $module, string $backend): string {
switch (strtolower($module)) {
case 'curl':
return $l->t('The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]);

+ 1
- 5
apps/files_external/lib/Service/DBConfigService.php View File

@@ -64,11 +64,7 @@ class DBConfigService {
$this->crypto = $crypto;
}

/**
* @param int $mountId
* @return array
*/
public function getMountById($mountId) {
public function getMountById(int $mountId): ?array {
$builder = $this->connection->getQueryBuilder();
$query = $builder->select(['mount_id', 'mount_point', 'storage_backend', 'auth_backend', 'priority', 'type'])
->from('external_mounts', 'm')

+ 1
- 1
apps/files_external/lib/Service/GlobalStoragesService.php View File

@@ -155,7 +155,7 @@ class GlobalStoragesService extends StoragesService {
/**
* Get the visibility type for this controller, used in validation
*
* @return string BackendService::VISIBILITY_* constants
* @return int BackendService::VISIBILITY_* constants
*/
public function getVisibilityType() {
return BackendService::VISIBILITY_ADMIN;

+ 2
- 1
apps/files_external/lib/Service/StoragesService.php View File

@@ -231,7 +231,7 @@ abstract class StoragesService {
/**
* Get the visibility type for this controller, used in validation
*
* @return string BackendService::VISIBILITY_* constants
* @return int BackendService::VISIBILITY_* constants
*/
abstract public function getVisibilityType();

@@ -510,6 +510,7 @@ abstract class StoragesService {
$storage = $storageConfig->getBackend()->wrapStorage($storage);
$storage = $storageConfig->getAuthMechanism()->wrapStorage($storage);

/** @var \OC\Files\Storage\Storage $storage */
return $storage->getStorageCache()->getNumericId();
} catch (\Exception $e) {
return -1;

+ 1
- 1
apps/files_external/lib/Service/UserStoragesService.php View File

@@ -134,7 +134,7 @@ class UserStoragesService extends StoragesService {
/**
* Get the visibility type for this controller, used in validation
*
* @return string BackendService::VISIBILITY_* constants
* @return int BackendService::VISIBILITY_* constants
*/
public function getVisibilityType() {
return BackendService::VISIBILITY_PERSONAL;

+ 3
- 1
apps/files_external/templates/settings.php View File

@@ -1,9 +1,11 @@
<?php
use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
use \OCA\Files_External\Lib\DefinitionParameter;
use \OCA\Files_External\Service\BackendService;

/** @var array $_ */

$canCreateMounts = $_['visibilityType'] === BackendService::VISIBILITY_ADMIN || $_['allowUserMounting'];

$l->t("Enable encryption");

+ 7
- 7
apps/files_sharing/lib/SharedStorage.php View File

@@ -334,15 +334,15 @@ class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedSto
/**
* see https://www.php.net/manual/en/function.rename.php
*
* @param string $path1
* @param string $path2
* @param string $source
* @param string $target
* @return bool
*/
public function rename($path1, $path2): bool {
public function rename($source, $target): bool {
$this->init();
$isPartFile = pathinfo($path1, PATHINFO_EXTENSION) === 'part';
$targetExists = $this->file_exists($path2);
$sameFolder = dirname($path1) === dirname($path2);
$isPartFile = pathinfo($source, PATHINFO_EXTENSION) === 'part';
$targetExists = $this->file_exists($target);
$sameFolder = dirname($source) === dirname($target);

if ($targetExists || ($sameFolder && !$isPartFile)) {
if (!$this->isUpdatable('')) {
@@ -354,7 +354,7 @@ class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedSto
}
}

return $this->nonMaskedStorage->rename($this->getUnjailedPath($path1), $this->getUnjailedPath($path2));
return $this->nonMaskedStorage->rename($this->getUnjailedPath($source), $this->getUnjailedPath($target));
}

/**

+ 1
- 182
build/psalm-baseline.xml View File

@@ -1044,31 +1044,6 @@
<code>$this</code>
</InvalidScope>
</file>
<file src="apps/files_external/lib/Command/Delete.php">
<NullArgument occurrences="1">
<code>null</code>
</NullArgument>
</file>
<file src="apps/files_external/lib/Command/ListCommand.php">
<InvalidScalarArgument occurrences="1">
<code>$userId</code>
</InvalidScalarArgument>
</file>
<file src="apps/files_external/lib/Command/Notify.php">
<InvalidArgument occurrences="1">
<code>$storage</code>
</InvalidArgument>
<InvalidReturnStatement occurrences="1"/>
<InvalidReturnType occurrences="1">
<code>int</code>
</InvalidReturnType>
<InvalidScalarArgument occurrences="1">
<code>\OC_Util::normalizeUnicode($parent)</code>
</InvalidScalarArgument>
<UndefinedInterfaceMethod occurrences="1">
<code>isConnected</code>
</UndefinedInterfaceMethod>
</file>
<file src="apps/files_external/lib/Command/Verify.php">
<InvalidScalarArgument occurrences="2">
<code>$e-&gt;getCode()</code>
@@ -1080,14 +1055,6 @@
<code>new $objectClass($objectStore)</code>
</UndefinedClass>
</file>
<file src="apps/files_external/lib/Controller/StoragesController.php">
<InvalidScalarArgument occurrences="4">
<code>$e-&gt;getCode()</code>
<code>$status</code>
<code>$this-&gt;service-&gt;getVisibilityType()</code>
<code>$this-&gt;service-&gt;getVisibilityType()</code>
</InvalidScalarArgument>
</file>
<file src="apps/files_external/lib/Controller/UserGlobalStoragesController.php">
<UndefinedMethod occurrences="1">
<code>getUniqueStorages</code>
@@ -1099,102 +1066,10 @@
<code>addServiceListener</code>
</InvalidArgument>
</file>
<file src="apps/files_external/lib/Lib/Backend/Backend.php">
<InvalidReturnType occurrences="1">
<code>self</code>
</InvalidReturnType>
</file>
<file src="apps/files_external/lib/Lib/FrontendDefinitionTrait.php">
<UndefinedClass occurrences="2">
<code>FrontendDefinitionTrait</code>
<code>FrontendDefinitionTrait</code>
</UndefinedClass>
</file>
<file src="apps/files_external/lib/Lib/IdentifierTrait.php">
<UndefinedDocblockClass occurrences="2">
<code>$this-&gt;deprecateTo</code>
<code>IdentifierTrait</code>
</UndefinedDocblockClass>
</file>
<file src="apps/files_external/lib/Lib/LegacyDependencyCheckPolyfill.php">
<TooManyArguments occurrences="1">
<code>new MissingDependency($module, $this)</code>
</TooManyArguments>
</file>
<file src="apps/files_external/lib/Lib/PriorityTrait.php">
<UndefinedClass occurrences="2">
<code>PriorityTrait</code>
<code>PriorityTrait</code>
</UndefinedClass>
</file>
<file src="apps/files_external/lib/Lib/Storage/AmazonS3.php">
<UndefinedMagicMethod occurrences="1">
<code>clearBucket</code>
</UndefinedMagicMethod>
</file>
<file src="apps/files_external/lib/Lib/Storage/SFTP.php">
<InternalMethod occurrences="1">
<code>put</code>
</InternalMethod>
<ParamNameMismatch occurrences="2">
<code>$source</code>
<code>$target</code>
</ParamNameMismatch>
</file>
<file src="apps/files_external/lib/Lib/Storage/SFTPReadStream.php">
<InvalidArgument occurrences="2">
<code>$this-&gt;handle</code>
<code>$this-&gt;handle</code>
</InvalidArgument>
<InvalidNullableReturnType occurrences="1">
<code>stream_close</code>
</InvalidNullableReturnType>
<InvalidPropertyAssignmentValue occurrences="1">
<code>substr($response, 4)</code>
</InvalidPropertyAssignmentValue>
<InvalidReturnStatement occurrences="1">
<code>$context</code>
</InvalidReturnStatement>
<InvalidReturnType occurrences="1">
<code>array</code>
</InvalidReturnType>
</file>
<file src="apps/files_external/lib/Lib/Storage/SFTPWriteStream.php">
<InvalidArgument occurrences="2">
<code>$this-&gt;handle</code>
<code>$this-&gt;handle</code>
</InvalidArgument>
<InvalidNullableReturnType occurrences="1">
<code>stream_close</code>
</InvalidNullableReturnType>
<InvalidPropertyAssignmentValue occurrences="1">
<code>substr($response, 4)</code>
</InvalidPropertyAssignmentValue>
<InvalidReturnStatement occurrences="1">
<code>$context</code>
</InvalidReturnStatement>
<InvalidReturnType occurrences="1">
<code>array</code>
</InvalidReturnType>
</file>
<file src="apps/files_external/lib/Lib/Storage/SMB.php">
<InvalidScalarArgument occurrences="7">
<code>$e-&gt;getCode()</code>
<code>$e-&gt;getCode()</code>
<code>$e-&gt;getCode()</code>
<code>$e-&gt;getCode()</code>
<code>$e-&gt;getCode()</code>
<code>$e-&gt;getCode()</code>
<code>$e-&gt;getCode()</code>
</InvalidScalarArgument>
<ParamNameMismatch occurrences="2">
<code>$source</code>
<code>$target</code>
</ParamNameMismatch>
<TooManyArguments occurrences="2">
<code>rename</code>
<code>rename</code>
</TooManyArguments>
</file>
<file src="apps/files_external/lib/Lib/Storage/Swift.php">
<InvalidArgument occurrences="1">
@@ -1217,63 +1092,15 @@
<code>setIV</code>
<code>setIV</code>
</InternalMethod>
<InvalidNullableReturnType occurrences="1">
<code>string</code>
</InvalidNullableReturnType>
<NullableReturnStatement occurrences="1">
<code>$message</code>
</NullableReturnStatement>
<TooManyArguments occurrences="1">
<code>test</code>
</TooManyArguments>
</file>
<file src="apps/files_external/lib/Service/BackendService.php">
<InvalidArgument occurrences="1">
<code>'OCA\\Files_External::loadAdditionalBackends'</code>
</InvalidArgument>
<TooManyArguments occurrences="1">
<code>dispatch</code>
</TooManyArguments>
</file>
<file src="apps/files_external/lib/Service/DBConfigService.php">
<NullableReturnStatement occurrences="1">
<code>null</code>
</NullableReturnStatement>
</file>
<file src="apps/files_external/lib/Service/GlobalStoragesService.php">
<InvalidReturnStatement occurrences="1">
<code>BackendService::VISIBILITY_ADMIN</code>
</InvalidReturnStatement>
<InvalidReturnType occurrences="1">
<code>string</code>
</InvalidReturnType>
</file>
<file src="apps/files_external/lib/Service/LegacyStoragesService.php">
<InvalidScalarArgument occurrences="1">
<code>$configId</code>
</InvalidScalarArgument>
</file>
<file src="apps/files_external/lib/Service/StoragesService.php">
<InvalidScalarArgument occurrences="2">
<code>$this-&gt;getVisibilityType()</code>
<code>$this-&gt;getVisibilityType()</code>
</InvalidScalarArgument>
<UndefinedInterfaceMethod occurrences="1">
<code>getStorageCache</code>
</UndefinedInterfaceMethod>
</file>
<file src="apps/files_external/lib/Service/UserStoragesService.php">
<InvalidReturnStatement occurrences="1">
<code>BackendService::VISIBILITY_PERSONAL</code>
</InvalidReturnStatement>
<InvalidReturnType occurrences="1">
<code>string</code>
</InvalidReturnType>
</file>
<file src="apps/files_external/templates/settings.php">
<UndefinedVariable occurrences="1">
<code>$_</code>
</UndefinedVariable>
<InvalidArgument occurrences="1"/>
</file>
<file src="apps/files_sharing/lib/AppInfo/Application.php">
<InvalidArgument occurrences="6">
@@ -2824,10 +2651,6 @@
<InvalidScalarArgument occurrences="1">
<code>$source</code>
</InvalidScalarArgument>
<ParamNameMismatch occurrences="2">
<code>$source</code>
<code>$target</code>
</ParamNameMismatch>
</file>
<file src="lib/private/Files/ObjectStore/S3ConnectionTrait.php">
<InternalClass occurrences="1">
@@ -3089,10 +2912,6 @@
<code>$free</code>
<code>'ext'</code>
</InvalidScalarArgument>
<ParamNameMismatch occurrences="2">
<code>$source</code>
<code>$target</code>
</ParamNameMismatch>
</file>
<file src="lib/private/Files/Storage/Wrapper/Wrapper.php">
<InvalidReturnStatement occurrences="1">

+ 4
- 4
lib/private/Files/Filesystem.php View File

@@ -599,12 +599,12 @@ class Filesystem {
return self::$defaultInstance->unlink($path);
}

public static function rename($path1, $path2) {
return self::$defaultInstance->rename($path1, $path2);
public static function rename($source, $target) {
return self::$defaultInstance->rename($source, $target);
}

public static function copy($path1, $path2) {
return self::$defaultInstance->copy($path1, $path2);
public static function copy($source, $target) {
return self::$defaultInstance->copy($source, $target);
}

public static function fopen($path, $mode) {

+ 5
- 5
lib/private/Files/ObjectStore/ObjectStoreStorage.php View File

@@ -558,17 +558,17 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
}

public function copy($path1, $path2) {
$path1 = $this->normalizePath($path1);
$path2 = $this->normalizePath($path2);
public function copy($source, $target) {
$source = $this->normalizePath($source);
$target = $this->normalizePath($target);

$cache = $this->getCache();
$sourceEntry = $cache->get($path1);
$sourceEntry = $cache->get($source);
if (!$sourceEntry) {
throw new NotFoundException('Source object not found');
}

$this->copyInner($sourceEntry, $path2);
$this->copyInner($sourceEntry, $target);

return true;
}

+ 15
- 15
lib/private/Files/Storage/Common.php View File

@@ -213,21 +213,21 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage {
return $count;
}

public function rename($path1, $path2) {
$this->remove($path2);
public function rename($source, $target) {
$this->remove($target);

$this->removeCachedFile($path1);
return $this->copy($path1, $path2) and $this->remove($path1);
$this->removeCachedFile($source);
return $this->copy($source, $target) and $this->remove($source);
}

public function copy($path1, $path2) {
if ($this->is_dir($path1)) {
$this->remove($path2);
$dir = $this->opendir($path1);
$this->mkdir($path2);
public function copy($source, $target) {
if ($this->is_dir($source)) {
$this->remove($target);
$dir = $this->opendir($source);
$this->mkdir($target);
while ($file = readdir($dir)) {
if (!Filesystem::isIgnoredDir($file)) {
if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file)) {
if (!$this->copy($source . '/' . $file, $target . '/' . $file)) {
closedir($dir);
return false;
}
@@ -236,13 +236,13 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage {
closedir($dir);
return true;
} else {
$source = $this->fopen($path1, 'r');
$target = $this->fopen($path2, 'w');
[, $result] = \OC_Helper::streamCopy($source, $target);
$sourceStream = $this->fopen($source, 'r');
$targetStream = $this->fopen($target, 'w');
[, $result] = \OC_Helper::streamCopy($sourceStream, $targetStream);
if (!$result) {
\OC::$server->get(LoggerInterface::class)->warning("Failed to write data while copying $path1 to $path2");
\OCP\Server::get(LoggerInterface::class)->warning("Failed to write data while copying $source to $target");
}
$this->removeCachedFile($path2);
$this->removeCachedFile($target);
return $result;
}
}

+ 23
- 23
lib/private/Files/Storage/DAV.php View File

@@ -518,30 +518,30 @@ class DAV extends Common {
}

/** {@inheritdoc} */
public function rename($path1, $path2) {
public function rename($source, $target) {
$this->init();
$path1 = $this->cleanPath($path1);
$path2 = $this->cleanPath($path2);
$source = $this->cleanPath($source);
$target = $this->cleanPath($target);
try {
// overwrite directory ?
if ($this->is_dir($path2)) {
if ($this->is_dir($target)) {
// needs trailing slash in destination
$path2 = rtrim($path2, '/') . '/';
$target = rtrim($target, '/') . '/';
}
$this->client->request(
'MOVE',
$this->encodePath($path1),
$this->encodePath($source),
null,
[
'Destination' => $this->createBaseUri() . $this->encodePath($path2),
'Destination' => $this->createBaseUri() . $this->encodePath($target),
]
);
$this->statCache->clear($path1 . '/');
$this->statCache->clear($path2 . '/');
$this->statCache->set($path1, false);
$this->statCache->set($path2, true);
$this->removeCachedFile($path1);
$this->removeCachedFile($path2);
$this->statCache->clear($source . '/');
$this->statCache->clear($target . '/');
$this->statCache->set($source, false);
$this->statCache->set($target, true);
$this->removeCachedFile($source);
$this->removeCachedFile($target);
return true;
} catch (\Exception $e) {
$this->convertException($e);
@@ -550,27 +550,27 @@ class DAV extends Common {
}

/** {@inheritdoc} */
public function copy($path1, $path2) {
public function copy($source, $target) {
$this->init();
$path1 = $this->cleanPath($path1);
$path2 = $this->cleanPath($path2);
$source = $this->cleanPath($source);
$target = $this->cleanPath($target);
try {
// overwrite directory ?
if ($this->is_dir($path2)) {
if ($this->is_dir($target)) {
// needs trailing slash in destination
$path2 = rtrim($path2, '/') . '/';
$target = rtrim($target, '/') . '/';
}
$this->client->request(
'COPY',
$this->encodePath($path1),
$this->encodePath($source),
null,
[
'Destination' => $this->createBaseUri() . $this->encodePath($path2),
'Destination' => $this->createBaseUri() . $this->encodePath($target),
]
);
$this->statCache->clear($path2 . '/');
$this->statCache->set($path2, true);
$this->removeCachedFile($path2);
$this->statCache->clear($target . '/');
$this->statCache->set($target, true);
$this->removeCachedFile($target);
return true;
} catch (\Exception $e) {
$this->convertException($e);

+ 2
- 2
lib/private/Files/Storage/FailedStorage.php View File

@@ -129,11 +129,11 @@ class FailedStorage extends Common {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}

public function rename($path1, $path2) {
public function rename($source, $target) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}

public function copy($path1, $path2) {
public function copy($source, $target) {
throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
}


+ 21
- 21
lib/private/Files/Storage/Local.php View File

@@ -333,9 +333,9 @@ class Local extends \OC\Files\Storage\Common {
}
}

public function rename($path1, $path2) {
$srcParent = dirname($path1);
$dstParent = dirname($path2);
public function rename($source, $target) {
$srcParent = dirname($source);
$dstParent = dirname($target);

if (!$this->isUpdatable($srcParent)) {
\OC::$server->get(LoggerInterface::class)->error('unable to rename, source directory is not writable : ' . $srcParent, ['app' => 'core']);
@@ -347,44 +347,44 @@ class Local extends \OC\Files\Storage\Common {
return false;
}

if (!$this->file_exists($path1)) {
\OC::$server->get(LoggerInterface::class)->error('unable to rename, file does not exists : ' . $path1, ['app' => 'core']);
if (!$this->file_exists($source)) {
\OC::$server->get(LoggerInterface::class)->error('unable to rename, file does not exists : ' . $source, ['app' => 'core']);
return false;
}

if ($this->is_dir($path2)) {
$this->rmdir($path2);
} elseif ($this->is_file($path2)) {
$this->unlink($path2);
if ($this->is_dir($target)) {
$this->rmdir($target);
} elseif ($this->is_file($target)) {
$this->unlink($target);
}

if ($this->is_dir($path1)) {
if ($this->is_dir($source)) {
// we can't move folders across devices, use copy instead
$stat1 = stat(dirname($this->getSourcePath($path1)));
$stat2 = stat(dirname($this->getSourcePath($path2)));
$stat1 = stat(dirname($this->getSourcePath($source)));
$stat2 = stat(dirname($this->getSourcePath($target)));
if ($stat1['dev'] !== $stat2['dev']) {
$result = $this->copy($path1, $path2);
$result = $this->copy($source, $target);
if ($result) {
$result &= $this->rmdir($path1);
$result &= $this->rmdir($source);
}
return $result;
}

$this->checkTreeForForbiddenItems($this->getSourcePath($path1));
$this->checkTreeForForbiddenItems($this->getSourcePath($source));
}

return rename($this->getSourcePath($path1), $this->getSourcePath($path2));
return rename($this->getSourcePath($source), $this->getSourcePath($target));
}

public function copy($path1, $path2) {
if ($this->is_dir($path1)) {
return parent::copy($path1, $path2);
public function copy($source, $target) {
if ($this->is_dir($source)) {
return parent::copy($source, $target);
} else {
$oldMask = umask($this->defUMask);
if ($this->unlinkOnTruncate) {
$this->unlink($path2);
$this->unlink($target);
}
$result = copy($this->getSourcePath($path1), $this->getSourcePath($path2));
$result = copy($this->getSourcePath($source), $this->getSourcePath($target));
umask($oldMask);
return $result;
}

+ 7
- 7
lib/private/Files/Storage/PolyFill/CopyDirectory.php View File

@@ -64,15 +64,15 @@ trait CopyDirectory {
*/
abstract public function mkdir($path);

public function copy($path1, $path2) {
if ($this->is_dir($path1)) {
if ($this->file_exists($path2)) {
$this->unlink($path2);
public function copy($source, $target) {
if ($this->is_dir($source)) {
if ($this->file_exists($target)) {
$this->unlink($target);
}
$this->mkdir($path2);
return $this->copyRecursive($path1, $path2);
$this->mkdir($target);
return $this->copyRecursive($source, $target);
} else {
return parent::copy($path1, $path2);
return parent::copy($source, $target);
}
}


+ 4
- 4
lib/private/Files/Storage/Wrapper/Availability.php View File

@@ -288,20 +288,20 @@ class Availability extends Wrapper {
}

/** {@inheritdoc} */
public function rename($path1, $path2) {
public function rename($source, $target) {
$this->checkAvailability();
try {
return parent::rename($path1, $path2);
return parent::rename($source, $target);
} catch (StorageNotAvailableException $e) {
$this->setUnavailable($e);
}
}

/** {@inheritdoc} */
public function copy($path1, $path2) {
public function copy($source, $target) {
$this->checkAvailability();
try {
return parent::copy($path1, $path2);
return parent::copy($source, $target);
} catch (StorageNotAvailableException $e) {
$this->setUnavailable($e);
}

+ 8
- 8
lib/private/Files/Storage/Wrapper/Encoding.php View File

@@ -338,24 +338,24 @@ class Encoding extends Wrapper {
/**
* see https://www.php.net/manual/en/function.rename.php
*
* @param string $path1
* @param string $path2
* @param string $source
* @param string $target
* @return bool
*/
public function rename($path1, $path2) {
public function rename($source, $target) {
// second name always NFC
return $this->storage->rename($this->findPathToUse($path1), $this->findPathToUse($path2));
return $this->storage->rename($this->findPathToUse($source), $this->findPathToUse($target));
}

/**
* see https://www.php.net/manual/en/function.copy.php
*
* @param string $path1
* @param string $path2
* @param string $source
* @param string $target
* @return bool
*/
public function copy($path1, $path2) {
return $this->storage->copy($this->findPathToUse($path1), $this->findPathToUse($path2));
public function copy($source, $target) {
return $this->storage->copy($this->findPathToUse($source), $this->findPathToUse($target));
}

/**

+ 21
- 22
lib/private/Files/Storage/Wrapper/Encryption.php View File

@@ -270,28 +270,28 @@ class Encryption extends Wrapper {
/**
* see https://www.php.net/manual/en/function.rename.php
*
* @param string $path1
* @param string $path2
* @param string $source
* @param string $target
* @return bool
*/
public function rename($path1, $path2) {
$result = $this->storage->rename($path1, $path2);
public function rename($source, $target) {
$result = $this->storage->rename($source, $target);

if ($result &&
// versions always use the keys from the original file, so we can skip
// this step for versions
$this->isVersion($path2) === false &&
$this->isVersion($target) === false &&
$this->encryptionManager->isEnabled()) {
$source = $this->getFullPath($path1);
if (!$this->util->isExcluded($source)) {
$target = $this->getFullPath($path2);
if (isset($this->unencryptedSize[$source])) {
$this->unencryptedSize[$target] = $this->unencryptedSize[$source];
$sourcePath = $this->getFullPath($source);
if (!$this->util->isExcluded($sourcePath)) {
$targetPath = $this->getFullPath($target);
if (isset($this->unencryptedSize[$sourcePath])) {
$this->unencryptedSize[$targetPath] = $this->unencryptedSize[$sourcePath];
}
$this->keyStorage->renameKeys($source, $target);
$module = $this->getEncryptionModule($path2);
$this->keyStorage->renameKeys($sourcePath, $targetPath);
$module = $this->getEncryptionModule($target);
if ($module) {
$module->update($target, $this->uid, []);
$module->update($targetPath, $this->uid, []);
}
}
}
@@ -344,21 +344,20 @@ class Encryption extends Wrapper {
/**
* see https://www.php.net/manual/en/function.copy.php
*
* @param string $path1
* @param string $path2
* @return bool
* @param string $source
* @param string $target
*/
public function copy($path1, $path2) {
$source = $this->getFullPath($path1);
public function copy($source, $target): bool {
$sourcePath = $this->getFullPath($source);

if ($this->util->isExcluded($source)) {
return $this->storage->copy($path1, $path2);
if ($this->util->isExcluded($sourcePath)) {
return $this->storage->copy($source, $target);
}

// need to stream copy file by file in case we copy between a encrypted
// and a unencrypted storage
$this->unlink($path2);
return $this->copyFromStorage($this, $path1, $path2);
$this->unlink($target);
return $this->copyFromStorage($this, $source, $target);
}

/**

+ 8
- 8
lib/private/Files/Storage/Wrapper/Jail.php View File

@@ -281,23 +281,23 @@ class Jail extends Wrapper {
/**
* see https://www.php.net/manual/en/function.rename.php
*
* @param string $path1
* @param string $path2
* @param string $source
* @param string $target
* @return bool
*/
public function rename($path1, $path2) {
return $this->getWrapperStorage()->rename($this->getUnjailedPath($path1), $this->getUnjailedPath($path2));
public function rename($source, $target) {
return $this->getWrapperStorage()->rename($this->getUnjailedPath($source), $this->getUnjailedPath($target));
}

/**
* see https://www.php.net/manual/en/function.copy.php
*
* @param string $path1
* @param string $path2
* @param string $source
* @param string $target
* @return bool
*/
public function copy($path1, $path2) {
return $this->getWrapperStorage()->copy($this->getUnjailedPath($path1), $this->getUnjailedPath($path2));
public function copy($source, $target) {
return $this->getWrapperStorage()->copy($this->getUnjailedPath($source), $this->getUnjailedPath($target));
}

/**

+ 6
- 6
lib/private/Files/Storage/Wrapper/PermissionsMask.php View File

@@ -78,16 +78,16 @@ class PermissionsMask extends Wrapper {
return $this->storage->getPermissions($path) & $this->mask;
}

public function rename($path1, $path2) {
public function rename($source, $target) {
//This is a rename of the transfer file to the original file
if (dirname($path1) === dirname($path2) && strpos($path1, '.ocTransferId') > 0) {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::rename($path1, $path2);
if (dirname($source) === dirname($target) && strpos($source, '.ocTransferId') > 0) {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::rename($source, $target);
}
return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::rename($path1, $path2);
return $this->checkMask(Constants::PERMISSION_UPDATE) and parent::rename($source, $target);
}

public function copy($path1, $path2) {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::copy($path1, $path2);
public function copy($source, $target) {
return $this->checkMask(Constants::PERMISSION_CREATE) and parent::copy($source, $target);
}

public function touch($path, $mtime = null) {

+ 8
- 8
lib/private/Files/Storage/Wrapper/Wrapper.php View File

@@ -271,23 +271,23 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
/**
* see https://www.php.net/manual/en/function.rename.php
*
* @param string $path1
* @param string $path2
* @param string $source
* @param string $target
* @return bool
*/
public function rename($path1, $path2) {
return $this->getWrapperStorage()->rename($path1, $path2);
public function rename($source, $target) {
return $this->getWrapperStorage()->rename($source, $target);
}

/**
* see https://www.php.net/manual/en/function.copy.php
*
* @param string $path1
* @param string $path2
* @param string $source
* @param string $target
* @return bool
*/
public function copy($path1, $path2) {
return $this->getWrapperStorage()->copy($path1, $path2);
public function copy($source, $target) {
return $this->getWrapperStorage()->copy($source, $target);
}

/**

+ 63
- 63
lib/private/Files/View.php View File

@@ -749,65 +749,65 @@ class View {
/**
* Rename/move a file or folder from the source path to target path.
*
* @param string $path1 source path
* @param string $path2 target path
* @param string $source source path
* @param string $target target path
*
* @return bool|mixed
* @throws LockedException
*/
public function rename($path1, $path2) {
$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
public function rename($source, $target) {
$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($source));
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($target));
$result = false;
if (
Filesystem::isValidPath($path2)
and Filesystem::isValidPath($path1)
and !Filesystem::isFileBlacklisted($path2)
Filesystem::isValidPath($target)
and Filesystem::isValidPath($source)
and !Filesystem::isFileBlacklisted($target)
) {
$path1 = $this->getRelativePath($absolutePath1);
$path2 = $this->getRelativePath($absolutePath2);
$exists = $this->file_exists($path2);
$source = $this->getRelativePath($absolutePath1);
$target = $this->getRelativePath($absolutePath2);
$exists = $this->file_exists($target);

if ($path1 == null or $path2 == null) {
if ($source == null or $target == null) {
return false;
}

$this->lockFile($path1, ILockingProvider::LOCK_SHARED, true);
$this->lockFile($source, ILockingProvider::LOCK_SHARED, true);
try {
$this->lockFile($path2, ILockingProvider::LOCK_SHARED, true);
$this->lockFile($target, ILockingProvider::LOCK_SHARED, true);

$run = true;
if ($this->shouldEmitHooks($path1) && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) {
if ($this->shouldEmitHooks($source) && (Cache\Scanner::isPartialFile($source) && !Cache\Scanner::isPartialFile($target))) {
// if it was a rename from a part file to a regular file it was a write and not a rename operation
$this->emit_file_hooks_pre($exists, $path2, $run);
} elseif ($this->shouldEmitHooks($path1)) {
$this->emit_file_hooks_pre($exists, $target, $run);
} elseif ($this->shouldEmitHooks($source)) {
\OC_Hook::emit(
Filesystem::CLASSNAME, Filesystem::signal_rename,
[
Filesystem::signal_param_oldpath => $this->getHookPath($path1),
Filesystem::signal_param_newpath => $this->getHookPath($path2),
Filesystem::signal_param_oldpath => $this->getHookPath($source),
Filesystem::signal_param_newpath => $this->getHookPath($target),
Filesystem::signal_param_run => &$run
]
);
}
if ($run) {
$this->verifyPath(dirname($path2), basename($path2));
$this->verifyPath(dirname($target), basename($target));

$manager = Filesystem::getMountManager();
$mount1 = $this->getMount($path1);
$mount2 = $this->getMount($path2);
$mount1 = $this->getMount($source);
$mount2 = $this->getMount($target);
$storage1 = $mount1->getStorage();
$storage2 = $mount2->getStorage();
$internalPath1 = $mount1->getInternalPath($absolutePath1);
$internalPath2 = $mount2->getInternalPath($absolutePath2);

$this->changeLock($path1, ILockingProvider::LOCK_EXCLUSIVE, true);
$this->changeLock($source, ILockingProvider::LOCK_EXCLUSIVE, true);
try {
$this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE, true);
$this->changeLock($target, ILockingProvider::LOCK_EXCLUSIVE, true);

if ($internalPath1 === '') {
if ($mount1 instanceof MoveableMount) {
$sourceParentMount = $this->getMount(dirname($path1));
$sourceParentMount = $this->getMount(dirname($source));
if ($sourceParentMount === $mount2 && $this->targetIsNotShared($storage2, $internalPath2)) {
/**
* @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
@@ -833,7 +833,7 @@ class View {
$result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
}

if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
if ((Cache\Scanner::isPartialFile($source) && !Cache\Scanner::isPartialFile($target)) && $result !== false) {
// if it was a rename from a part file to a regular file it was a write and not a rename operation
$this->writeUpdate($storage2, $internalPath2);
} elseif ($result) {
@@ -844,22 +844,22 @@ class View {
} catch (\Exception $e) {
throw $e;
} finally {
$this->changeLock($path1, ILockingProvider::LOCK_SHARED, true);
$this->changeLock($path2, ILockingProvider::LOCK_SHARED, true);
$this->changeLock($source, ILockingProvider::LOCK_SHARED, true);
$this->changeLock($target, ILockingProvider::LOCK_SHARED, true);
}

if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
if ((Cache\Scanner::isPartialFile($source) && !Cache\Scanner::isPartialFile($target)) && $result !== false) {
if ($this->shouldEmitHooks()) {
$this->emit_file_hooks_post($exists, $path2);
$this->emit_file_hooks_post($exists, $target);
}
} elseif ($result) {
if ($this->shouldEmitHooks($path1) and $this->shouldEmitHooks($path2)) {
if ($this->shouldEmitHooks($source) and $this->shouldEmitHooks($target)) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_post_rename,
[
Filesystem::signal_param_oldpath => $this->getHookPath($path1),
Filesystem::signal_param_newpath => $this->getHookPath($path2)
Filesystem::signal_param_oldpath => $this->getHookPath($source),
Filesystem::signal_param_newpath => $this->getHookPath($target)
]
);
}
@@ -868,8 +868,8 @@ class View {
} catch (\Exception $e) {
throw $e;
} finally {
$this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true);
$this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true);
$this->unlockFile($source, ILockingProvider::LOCK_SHARED, true);
$this->unlockFile($target, ILockingProvider::LOCK_SHARED, true);
}
}
return $result;
@@ -878,57 +878,57 @@ class View {
/**
* Copy a file/folder from the source path to target path
*
* @param string $path1 source path
* @param string $path2 target path
* @param string $source source path
* @param string $target target path
* @param bool $preserveMtime whether to preserve mtime on the copy
*
* @return bool|mixed
*/
public function copy($path1, $path2, $preserveMtime = false) {
$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
public function copy($source, $target, $preserveMtime = false) {
$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($source));
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($target));
$result = false;
if (
Filesystem::isValidPath($path2)
and Filesystem::isValidPath($path1)
and !Filesystem::isFileBlacklisted($path2)
Filesystem::isValidPath($target)
and Filesystem::isValidPath($source)
and !Filesystem::isFileBlacklisted($target)
) {
$path1 = $this->getRelativePath($absolutePath1);
$path2 = $this->getRelativePath($absolutePath2);
$source = $this->getRelativePath($absolutePath1);
$target = $this->getRelativePath($absolutePath2);

if ($path1 == null or $path2 == null) {
if ($source == null or $target == null) {
return false;
}
$run = true;

$this->lockFile($path2, ILockingProvider::LOCK_SHARED);
$this->lockFile($path1, ILockingProvider::LOCK_SHARED);
$this->lockFile($target, ILockingProvider::LOCK_SHARED);
$this->lockFile($source, ILockingProvider::LOCK_SHARED);
$lockTypePath1 = ILockingProvider::LOCK_SHARED;
$lockTypePath2 = ILockingProvider::LOCK_SHARED;

try {
$exists = $this->file_exists($path2);
$exists = $this->file_exists($target);
if ($this->shouldEmitHooks()) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
Filesystem::signal_copy,
[
Filesystem::signal_param_oldpath => $this->getHookPath($path1),
Filesystem::signal_param_newpath => $this->getHookPath($path2),
Filesystem::signal_param_oldpath => $this->getHookPath($source),
Filesystem::signal_param_newpath => $this->getHookPath($target),
Filesystem::signal_param_run => &$run
]
);
$this->emit_file_hooks_pre($exists, $path2, $run);
$this->emit_file_hooks_pre($exists, $target, $run);
}
if ($run) {
$mount1 = $this->getMount($path1);
$mount2 = $this->getMount($path2);
$mount1 = $this->getMount($source);
$mount2 = $this->getMount($target);
$storage1 = $mount1->getStorage();
$internalPath1 = $mount1->getInternalPath($absolutePath1);
$storage2 = $mount2->getStorage();
$internalPath2 = $mount2->getInternalPath($absolutePath2);

$this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE);
$this->changeLock($target, ILockingProvider::LOCK_EXCLUSIVE);
$lockTypePath2 = ILockingProvider::LOCK_EXCLUSIVE;

if ($mount1->getMountPoint() == $mount2->getMountPoint()) {
@@ -943,7 +943,7 @@ class View {

$this->writeUpdate($storage2, $internalPath2);

$this->changeLock($path2, ILockingProvider::LOCK_SHARED);
$this->changeLock($target, ILockingProvider::LOCK_SHARED);
$lockTypePath2 = ILockingProvider::LOCK_SHARED;

if ($this->shouldEmitHooks() && $result !== false) {
@@ -951,21 +951,21 @@ class View {
Filesystem::CLASSNAME,
Filesystem::signal_post_copy,
[
Filesystem::signal_param_oldpath => $this->getHookPath($path1),
Filesystem::signal_param_newpath => $this->getHookPath($path2)
Filesystem::signal_param_oldpath => $this->getHookPath($source),
Filesystem::signal_param_newpath => $this->getHookPath($target)
]
);
$this->emit_file_hooks_post($exists, $path2);
$this->emit_file_hooks_post($exists, $target);
}
}
} catch (\Exception $e) {
$this->unlockFile($path2, $lockTypePath2);
$this->unlockFile($path1, $lockTypePath1);
$this->unlockFile($target, $lockTypePath2);
$this->unlockFile($source, $lockTypePath1);
throw $e;
}

$this->unlockFile($path2, $lockTypePath2);
$this->unlockFile($path1, $lockTypePath1);
$this->unlockFile($target, $lockTypePath2);
$this->unlockFile($source, $lockTypePath1);
}
return $result;
}

+ 2
- 2
lib/private/Lockdown/Filesystem/NullStorage.php View File

@@ -113,11 +113,11 @@ class NullStorage extends Common {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
}

public function rename($path1, $path2) {
public function rename($source, $target) {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
}

public function copy($path1, $path2) {
public function copy($source, $target) {
throw new \OC\ForbiddenException('This request is not allowed to access the filesystem');
}


+ 6
- 6
lib/public/Files/Storage.php View File

@@ -244,22 +244,22 @@ interface Storage extends IStorage {
/**
* see https://www.php.net/manual/en/function.rename.php
*
* @param string $path1
* @param string $path2
* @param string $source
* @param string $target
* @return bool
* @since 6.0.0
*/
public function rename($path1, $path2);
public function rename($source, $target);

/**
* see https://www.php.net/manual/en/function.copy.php
*
* @param string $path1
* @param string $path2
* @param string $soruce
* @param string $target
* @return bool
* @since 6.0.0
*/
public function copy($path1, $path2);
public function copy($source, $target);

/**
* see https://www.php.net/manual/en/function.fopen.php

+ 6
- 6
lib/public/Files/Storage/IStorage.php View File

@@ -241,22 +241,22 @@ interface IStorage {
/**
* see https://www.php.net/manual/en/function.rename.php
*
* @param string $path1
* @param string $path2
* @param string $source
* @param string $target
* @return bool
* @since 9.0.0
*/
public function rename($path1, $path2);
public function rename($source, $target);

/**
* see https://www.php.net/manual/en/function.copy.php
*
* @param string $path1
* @param string $path2
* @param string $source
* @param string $target
* @return bool
* @since 9.0.0
*/
public function copy($path1, $path2);
public function copy($source, $target);

/**
* see https://www.php.net/manual/en/function.fopen.php

Loading…
Cancel
Save