Signed-off-by: Julius Härtl <jus@bitgrid.net>tags/v24.0.0rc1
@@ -295,6 +295,12 @@ return array( | |||
'OCP\\Files\\InvalidDirectoryException' => $baseDir . '/lib/public/Files/InvalidDirectoryException.php', | |||
'OCP\\Files\\InvalidPathException' => $baseDir . '/lib/public/Files/InvalidPathException.php', | |||
'OCP\\Files\\LockNotAcquiredException' => $baseDir . '/lib/public/Files/LockNotAcquiredException.php', | |||
'OCP\\Files\\Lock\\ILock' => $baseDir . '/lib/public/Files/Lock/ILock.php', | |||
'OCP\\Files\\Lock\\ILockManager' => $baseDir . '/lib/public/Files/Lock/ILockManager.php', | |||
'OCP\\Files\\Lock\\ILockProvider' => $baseDir . '/lib/public/Files/Lock/ILockProvider.php', | |||
'OCP\\Files\\Lock\\LockScope' => $baseDir . '/lib/public/Files/Lock/LockScope.php', | |||
'OCP\\Files\\Lock\\NoLockProviderException' => $baseDir . '/lib/public/Files/Lock/NoLockProviderException.php', | |||
'OCP\\Files\\Lock\\OwnerLockedException' => $baseDir . '/lib/public/Files/Lock/OwnerLockedException.php', | |||
'OCP\\Files\\Mount\\IMountManager' => $baseDir . '/lib/public/Files/Mount/IMountManager.php', | |||
'OCP\\Files\\Mount\\IMountPoint' => $baseDir . '/lib/public/Files/Mount/IMountPoint.php', | |||
'OCP\\Files\\Node' => $baseDir . '/lib/public/Files/Node.php', | |||
@@ -1129,6 +1135,7 @@ return array( | |||
'OC\\Files\\Config\\UserMountCacheListener' => $baseDir . '/lib/private/Files/Config/UserMountCacheListener.php', | |||
'OC\\Files\\FileInfo' => $baseDir . '/lib/private/Files/FileInfo.php', | |||
'OC\\Files\\Filesystem' => $baseDir . '/lib/private/Files/Filesystem.php', | |||
'OC\\Files\\Lock\\LockManager' => $baseDir . '/lib/private/Files/Lock/LockManager.php', | |||
'OC\\Files\\Mount\\CacheMountProvider' => $baseDir . '/lib/private/Files/Mount/CacheMountProvider.php', | |||
'OC\\Files\\Mount\\LocalHomeMountProvider' => $baseDir . '/lib/private/Files/Mount/LocalHomeMountProvider.php', | |||
'OC\\Files\\Mount\\Manager' => $baseDir . '/lib/private/Files/Mount/Manager.php', |
@@ -324,6 +324,12 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c | |||
'OCP\\Files\\InvalidDirectoryException' => __DIR__ . '/../../..' . '/lib/public/Files/InvalidDirectoryException.php', | |||
'OCP\\Files\\InvalidPathException' => __DIR__ . '/../../..' . '/lib/public/Files/InvalidPathException.php', | |||
'OCP\\Files\\LockNotAcquiredException' => __DIR__ . '/../../..' . '/lib/public/Files/LockNotAcquiredException.php', | |||
'OCP\\Files\\Lock\\ILock' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/ILock.php', | |||
'OCP\\Files\\Lock\\ILockManager' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/ILockManager.php', | |||
'OCP\\Files\\Lock\\ILockProvider' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/ILockProvider.php', | |||
'OCP\\Files\\Lock\\LockScope' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/LockScope.php', | |||
'OCP\\Files\\Lock\\NoLockProviderException' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/NoLockProviderException.php', | |||
'OCP\\Files\\Lock\\OwnerLockedException' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/OwnerLockedException.php', | |||
'OCP\\Files\\Mount\\IMountManager' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/IMountManager.php', | |||
'OCP\\Files\\Mount\\IMountPoint' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/IMountPoint.php', | |||
'OCP\\Files\\Node' => __DIR__ . '/../../..' . '/lib/public/Files/Node.php', | |||
@@ -1158,6 +1164,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c | |||
'OC\\Files\\Config\\UserMountCacheListener' => __DIR__ . '/../../..' . '/lib/private/Files/Config/UserMountCacheListener.php', | |||
'OC\\Files\\FileInfo' => __DIR__ . '/../../..' . '/lib/private/Files/FileInfo.php', | |||
'OC\\Files\\Filesystem' => __DIR__ . '/../../..' . '/lib/private/Files/Filesystem.php', | |||
'OC\\Files\\Lock\\LockManager' => __DIR__ . '/../../..' . '/lib/private/Files/Lock/LockManager.php', | |||
'OC\\Files\\Mount\\CacheMountProvider' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/CacheMountProvider.php', | |||
'OC\\Files\\Mount\\LocalHomeMountProvider' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/LocalHomeMountProvider.php', | |||
'OC\\Files\\Mount\\Manager' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/Manager.php', |
@@ -0,0 +1,72 @@ | |||
<?php | |||
namespace OC\Files\Lock; | |||
use OCP\Files\Lock\ILock; | |||
use OCP\Files\Lock\ILockManager; | |||
use OCP\Files\Lock\ILockProvider; | |||
use OCP\Files\Lock\LockScope; | |||
use OCP\PreConditionNotMetException; | |||
class LockManager implements ILockManager { | |||
private ?ILockProvider $lockProvider = null; | |||
private ?LockScope $lockInScope = null; | |||
public function registerLockProvider(ILockProvider $lockProvider): void { | |||
if ($this->lockProvider) { | |||
throw new PreConditionNotMetException('There is already a registered lock provider'); | |||
} | |||
$this->lockProvider = $lockProvider; | |||
} | |||
public function isLockProviderAvailable(): bool { | |||
return $this->lockProvider !== null; | |||
} | |||
public function runInScope(LockScope $lock, callable $callback): void { | |||
if (!$this->lockProvider) { | |||
$callback(); | |||
return; | |||
} | |||
if ($this->lockInScope) { | |||
throw new PreConditionNotMetException('Could not obtain lock scope as already in use by ' . $this->lockInScope); | |||
} | |||
try { | |||
$this->lockInScope = $lock; | |||
$callback(); | |||
} finally { | |||
$this->lockInScope = null; | |||
} | |||
} | |||
public function getLockInScope(): ?LockScope { | |||
return $this->lockInScope; | |||
} | |||
public function getLocks(int $fileId): array { | |||
if (!$this->lockProvider) { | |||
throw new PreConditionNotMetException('No lock provider available'); | |||
} | |||
return $this->lockProvider->getLocks($fileId); | |||
} | |||
public function lock(LockScope $lockInfo): ILock { | |||
if (!$this->lockProvider) { | |||
throw new PreConditionNotMetException('No lock provider available'); | |||
} | |||
return $this->lockProvider->lock($lockInfo); | |||
} | |||
public function unlock(LockScope $lockInfo): void { | |||
if (!$this->lockProvider) { | |||
throw new PreConditionNotMetException('No lock provider available'); | |||
} | |||
$this->lockProvider->unlock($lockInfo); | |||
} | |||
} |
@@ -88,6 +88,7 @@ use OC\Federation\CloudFederationProviderManager; | |||
use OC\Federation\CloudIdManager; | |||
use OC\Files\Config\UserMountCache; | |||
use OC\Files\Config\UserMountCacheListener; | |||
use OC\Files\Lock\LockManager; | |||
use OC\Files\Mount\CacheMountProvider; | |||
use OC\Files\Mount\LocalHomeMountProvider; | |||
use OC\Files\Mount\ObjectHomeMountProvider; | |||
@@ -175,6 +176,7 @@ use OCP\Files\Config\IUserMountCache; | |||
use OCP\Files\IMimeTypeDetector; | |||
use OCP\Files\IMimeTypeLoader; | |||
use OCP\Files\IRootFolder; | |||
use OCP\Files\Lock\ILockManager; | |||
use OCP\Files\Mount\IMountManager; | |||
use OCP\Files\NotFoundException; | |||
use OCP\Files\Storage\IStorageFactory; | |||
@@ -1113,6 +1115,10 @@ class Server extends ServerContainer implements IServerContainer { | |||
/** @deprecated 19.0.0 */ | |||
$this->registerDeprecatedAlias('LockingProvider', ILockingProvider::class); | |||
$this->registerService(ILockManager::class, function (Server $c): LockManager { | |||
return new LockManager(); | |||
}); | |||
$this->registerAlias(ILockdownManager::class, 'LockdownManager'); | |||
$this->registerService(SetupManager::class, function ($c) { | |||
// create the setupmanager through the mount manager to resolve the cyclic dependency |
@@ -91,4 +91,10 @@ interface IManager { | |||
* @return bool | |||
*/ | |||
public function isEnabled(): bool; | |||
/** | |||
* @since 24.0.0 | |||
* @return IEditor[] | |||
*/ | |||
public function getEditors(): array; | |||
} |
@@ -0,0 +1,163 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @author Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* 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 | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OCP\Files\Lock; | |||
/** | |||
* @since 24.0.0 | |||
*/ | |||
interface ILock { | |||
/** | |||
* User owned manual lock | |||
* | |||
* This lock type is initiated by a user manually through the web UI or clients | |||
* and will limit editing capabilities on the file to the lock owning user. | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public const TYPE_USER = 0; | |||
/** | |||
* App owned lock | |||
* | |||
* This lock type is created by collaborative apps like Text or Office to avoid | |||
* outside changes through WevDAV or other apps. | |||
* @since 24.0.0 | |||
* | |||
*/ | |||
public const TYPE_APP = 1; | |||
/** | |||
* Token owned lock | |||
* | |||
* This lock type will bind the ownership to the provided lock token. Any request | |||
* that aims to modify the file will be required to sent the token, the user | |||
* itself is not able to write to files without the token. This will allow | |||
* to limit the locking to an individual client. | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public const TYPE_TOKEN = 2; | |||
/** | |||
* WebDAV Lock scope exclusive | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public const LOCK_EXCLUSIVE = 1; | |||
/** | |||
* WebDAV Lock scope shared | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public const LOCK_SHARED = 2; | |||
/** | |||
* Lock only the resource the lock is applied to | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public const LOCK_DEPTH_ZERO = 0; | |||
/** | |||
* Lock app resources under the locked one with infinite depth | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public const LOCK_DEPTH_INFINITE = -1; | |||
/** | |||
* Type of the lock | |||
* | |||
* @psalm-return ILock::TYPE_* | |||
* @since 24.0.0 | |||
*/ | |||
public function getType(): int; | |||
/** | |||
* Owner that holds the lock | |||
* | |||
* Depending on the lock type this is: | |||
* - ILock::TYPE_USER: A user id | |||
* - ILock::TYPE_APP: An app id | |||
* - ILock::TYPE_TOKEN: A user id | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public function getOwner(): string; | |||
/** | |||
* File id that the lock is holding | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public function getFileId(): int; | |||
/** | |||
* Timeout of the lock in seconds starting from the created at time | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public function getTimeout(): int; | |||
/** | |||
* Unix timestamp of the lock creation time | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public function getCreatedAt(): int; | |||
/** | |||
* Token string as a unique identifier for the lock, usually a UUID | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public function getToken(): string; | |||
/** | |||
* Lock depth to apply the lock to child resources | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public function getDepth(): int; | |||
/** | |||
* WebDAV lock scope | |||
* | |||
* @since 24.0.0 | |||
* @psalm-return ILock::LOCK_EXCLUSIVE|ILock::LOCK_SHARED | |||
*/ | |||
public function getScope(): int; | |||
/** | |||
* String representation of the lock to identify it through logging | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public function __toString(): string; | |||
} |
@@ -0,0 +1,69 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @author Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* 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 | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OCP\Files\Lock; | |||
use OCP\PreConditionNotMetException; | |||
/** | |||
* Manage app integrations with files_lock with collaborative editors | |||
* | |||
* The OCP parts are mainly for exposing the ability to lock/unlock for apps and | |||
* to give the files_lock app a way to register and then be triggered by the apps | |||
* while the actual locking implementation is kept in the LockProvider and DAV | |||
* plugin from files_lock app. | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
interface ILockManager extends ILockProvider { | |||
/** | |||
* @throws PreConditionNotMetException if there is already a lock provider registered | |||
* @since 24.0.0 | |||
*/ | |||
public function registerLockProvider(ILockProvider $lockProvider): void; | |||
/** | |||
* @return bool | |||
* @since 24.0.0 | |||
*/ | |||
public function isLockProviderAvailable(): bool; | |||
/** | |||
* Run within the scope of a given lock condition | |||
* | |||
* The callback will also be executed if no lock provider is present | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
public function runInScope(LockScope $lock, callable $callback): void; | |||
/** | |||
* @throws NoLockProviderException if there is no lock provider available | |||
* @since 24.0.0 | |||
*/ | |||
public function getLockInScope(): ?LockScope; | |||
} |
@@ -0,0 +1,58 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @author Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* 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 | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OCP\Files\Lock; | |||
use OCP\PreConditionNotMetException; | |||
/** | |||
* @since 24.0.0 | |||
*/ | |||
interface ILockProvider { | |||
/** | |||
* @throws PreConditionNotMetException | |||
* @throws NoLockProviderException | |||
* @psalm-return list<ILock> | |||
* @since 24.0.0 | |||
*/ | |||
public function getLocks(int $fileId): array; | |||
/** | |||
* @throws PreConditionNotMetException | |||
* @throws OwnerLockedException | |||
* @throws NoLockProviderException | |||
* @since 24.0.0 | |||
*/ | |||
public function lock(LockScope $lockInfo): ILock; | |||
/** | |||
* @throws PreConditionNotMetException | |||
* @throws NoLockProviderException | |||
* @since 24.0.0 | |||
*/ | |||
public function unlock(LockScope $lockInfo): void; | |||
} |
@@ -0,0 +1,98 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @author Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* 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 | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OCP\Files\Lock; | |||
use OCP\Files\Node; | |||
/** | |||
* Structure to identify a specific lock scope | |||
* | |||
* This is used to match a lock/unlock request or file operation to existing locks | |||
* | |||
* @since 24.0.0 | |||
*/ | |||
final class LockScope { | |||
private Node $node; | |||
private int $type; | |||
private string $owner; | |||
/** | |||
* @param Node $node Node that is owned by the lock | |||
* @param int $type Type of the lock owner | |||
* @param string $owner Unique identifier for the lock owner based on the type | |||
* @since 24.0.0 | |||
*/ | |||
public function __construct( | |||
Node $node, | |||
int $type, | |||
string $owner | |||
) { | |||
$this->node = $node; | |||
$this->type = $type; | |||
$this->owner = $owner; | |||
} | |||
/** | |||
* @since 24.0.0 | |||
*/ | |||
public function getNode(): Node { | |||
return $this->node; | |||
} | |||
/** | |||
* @return int | |||
* @since 24.0.0 | |||
*/ | |||
public function getType(): int { | |||
return $this->type; | |||
} | |||
/** | |||
* @return string user id / app id / lock token depending on the type | |||
* @since 24.0.0 | |||
*/ | |||
public function getOwner(): string { | |||
return $this->owner; | |||
} | |||
/** | |||
* @since 24.0.0 | |||
*/ | |||
public function __toString(): string { | |||
$typeString = 'unknown'; | |||
if ($this->type === ILock::TYPE_USER) { | |||
$typeString = 'ILock::TYPE_USER'; | |||
} | |||
if ($this->type === ILock::TYPE_APP) { | |||
$typeString = 'ILock::TYPE_APP'; | |||
} | |||
if ($this->type === ILock::TYPE_TOKEN) { | |||
$typeString = 'ILock::TYPE_TOKEN'; | |||
} | |||
return "$typeString $this->owner " . $this->getNode()->getId(); | |||
} | |||
} |
@@ -0,0 +1,35 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @author Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* 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 | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OCP\Files\Lock; | |||
use Exception; | |||
/** | |||
* @since 24.0.0 | |||
*/ | |||
class NoLockProviderException extends Exception { | |||
} |
@@ -0,0 +1,53 @@ | |||
<?php | |||
declare(strict_types=1); | |||
/** | |||
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @author Julius Härtl <jus@bitgrid.net> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* 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 | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OCP\Files\Lock; | |||
use OCP\Lock\LockedException; | |||
/** | |||
* @since 24.0.0 | |||
*/ | |||
class OwnerLockedException extends LockedException { | |||
private ILock $lock; | |||
/** | |||
* @since 24.0.0 | |||
*/ | |||
public function __construct(ILock $lock) { | |||
$this->lock = $lock; | |||
$path = ''; | |||
$readablePath = ''; | |||
parent::__construct($path, null, $lock->getOwner(), $readablePath); | |||
} | |||
/** | |||
* @since 24.0.0 | |||
*/ | |||
public function getLock(): ILock { | |||
return $this->lock; | |||
} | |||
} |