summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJulius Härtl <jus@bitgrid.net>2022-03-23 13:52:47 +0100
committerJulius Härtl <jus@bitgrid.net>2022-04-04 09:02:56 +0200
commit40f1ad60c245bfe35998b718aab2fe0f726f3798 (patch)
treee98cc8e991ef582f330db2235f54155223ef4121 /lib
parent94004a7bd40e8527b3b89d954c32529ab13efbdc (diff)
downloadnextcloud-server-40f1ad60c245bfe35998b718aab2fe0f726f3798.tar.gz
nextcloud-server-40f1ad60c245bfe35998b718aab2fe0f726f3798.zip
Add public API for owner based locking
Signed-off-by: Julius Härtl <jus@bitgrid.net>
Diffstat (limited to 'lib')
-rw-r--r--lib/composer/composer/autoload_classmap.php7
-rw-r--r--lib/composer/composer/autoload_static.php7
-rw-r--r--lib/private/Files/Lock/LockManager.php72
-rw-r--r--lib/private/Server.php6
-rw-r--r--lib/public/DirectEditing/IManager.php6
-rw-r--r--lib/public/Files/Lock/ILock.php163
-rw-r--r--lib/public/Files/Lock/ILockManager.php69
-rw-r--r--lib/public/Files/Lock/ILockProvider.php58
-rw-r--r--lib/public/Files/Lock/LockScope.php98
-rw-r--r--lib/public/Files/Lock/NoLockProviderException.php35
-rw-r--r--lib/public/Files/Lock/OwnerLockedException.php53
11 files changed, 574 insertions, 0 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 4dbb3cc0d05..45724ba3a85 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -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',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 0b64f70f6fd..f5bd2e5ef98 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.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',
diff --git a/lib/private/Files/Lock/LockManager.php b/lib/private/Files/Lock/LockManager.php
new file mode 100644
index 00000000000..59022613fdb
--- /dev/null
+++ b/lib/private/Files/Lock/LockManager.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);
+ }
+}
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 682e6fa06ce..0cc020fe6be 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -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
diff --git a/lib/public/DirectEditing/IManager.php b/lib/public/DirectEditing/IManager.php
index 90ca94e6535..a1a5ed4f2bd 100644
--- a/lib/public/DirectEditing/IManager.php
+++ b/lib/public/DirectEditing/IManager.php
@@ -91,4 +91,10 @@ interface IManager {
* @return bool
*/
public function isEnabled(): bool;
+
+ /**
+ * @since 24.0.0
+ * @return IEditor[]
+ */
+ public function getEditors(): array;
}
diff --git a/lib/public/Files/Lock/ILock.php b/lib/public/Files/Lock/ILock.php
new file mode 100644
index 00000000000..03737a178c6
--- /dev/null
+++ b/lib/public/Files/Lock/ILock.php
@@ -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;
+}
diff --git a/lib/public/Files/Lock/ILockManager.php b/lib/public/Files/Lock/ILockManager.php
new file mode 100644
index 00000000000..bd6d7db69d6
--- /dev/null
+++ b/lib/public/Files/Lock/ILockManager.php
@@ -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;
+}
diff --git a/lib/public/Files/Lock/ILockProvider.php b/lib/public/Files/Lock/ILockProvider.php
new file mode 100644
index 00000000000..5df28aaef44
--- /dev/null
+++ b/lib/public/Files/Lock/ILockProvider.php
@@ -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;
+}
diff --git a/lib/public/Files/Lock/LockScope.php b/lib/public/Files/Lock/LockScope.php
new file mode 100644
index 00000000000..4d68f4c68c7
--- /dev/null
+++ b/lib/public/Files/Lock/LockScope.php
@@ -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();
+ }
+}
diff --git a/lib/public/Files/Lock/NoLockProviderException.php b/lib/public/Files/Lock/NoLockProviderException.php
new file mode 100644
index 00000000000..ab727348e87
--- /dev/null
+++ b/lib/public/Files/Lock/NoLockProviderException.php
@@ -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 {
+}
diff --git a/lib/public/Files/Lock/OwnerLockedException.php b/lib/public/Files/Lock/OwnerLockedException.php
new file mode 100644
index 00000000000..fc4530cb29e
--- /dev/null
+++ b/lib/public/Files/Lock/OwnerLockedException.php
@@ -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;
+ }
+}