summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Appelman <icewind@owncloud.com>2015-07-22 15:28:56 +0200
committerThomas Müller <thomas.mueller@tmit.eu>2015-09-14 20:35:33 +0200
commite612d3123f2b3d6ffd6d0e8b4da331cc5c6a8b3b (patch)
treea6623b9ba11925c067c8144515e11d358e84a185
parent209abaadbb6bf6c5b375a11f61e61fe47fb9b917 (diff)
downloadnextcloud-server-e612d3123f2b3d6ffd6d0e8b4da331cc5c6a8b3b.tar.gz
nextcloud-server-e612d3123f2b3d6ffd6d0e8b4da331cc5c6a8b3b.zip
wrap the entire put operation in a read lock
-rw-r--r--lib/private/connector/sabre/directory.php2
-rw-r--r--lib/private/connector/sabre/file.php11
-rw-r--r--lib/private/connector/sabre/lockplugin.php93
-rw-r--r--lib/private/connector/sabre/serverfactory.php1
4 files changed, 98 insertions, 9 deletions
diff --git a/lib/private/connector/sabre/directory.php b/lib/private/connector/sabre/directory.php
index 551176e4bd2..0261ab18047 100644
--- a/lib/private/connector/sabre/directory.php
+++ b/lib/private/connector/sabre/directory.php
@@ -30,6 +30,7 @@ namespace OC\Connector\Sabre;
use OC\Connector\Sabre\Exception\InvalidPath;
use OC\Connector\Sabre\Exception\FileLocked;
+use OCP\Lock\ILockingProvider;
use OCP\Lock\LockedException;
use Sabre\DAV\Exception\Locked;
@@ -110,6 +111,7 @@ class Directory extends \OC\Connector\Sabre\Node
// using a dummy FileInfo is acceptable here since it will be refreshed after the put is complete
$info = new \OC\Files\FileInfo($path, null, null, array(), null);
$node = new \OC\Connector\Sabre\File($this->fileView, $info);
+ $node->acquireLock(ILockingProvider::LOCK_SHARED);
return $node->put($data);
} catch (\OCP\Files\StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php
index b7d0c547f24..1730feee264 100644
--- a/lib/private/connector/sabre/file.php
+++ b/lib/private/connector/sabre/file.php
@@ -114,12 +114,6 @@ class File extends Node implements IFile {
$partFilePath = $this->path;
}
- try {
- $this->fileView->lockFile($this->path, ILockingProvider::LOCK_SHARED);
- } catch (LockedException $e) {
- throw new FileLocked($e->getMessage(), $e->getCode(), $e);
- }
-
// the part file and target file might be on a different storage in case of a single file storage (e.g. single file share)
/** @var \OC\Files\Storage\Storage $partStorage */
list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath);
@@ -176,7 +170,7 @@ class File extends Node implements IFile {
}
try {
- $this->fileView->changeLock($this->path, ILockingProvider::LOCK_EXCLUSIVE);
+ $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
} catch (LockedException $e) {
if ($needsPartFile) {
$partStorage->unlink($internalPartPath);
@@ -202,7 +196,7 @@ class File extends Node implements IFile {
}
try {
- $this->fileView->changeLock($this->path, ILockingProvider::LOCK_SHARED);
+ $this->changeLock(ILockingProvider::LOCK_SHARED);
} catch (LockedException $e) {
throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
@@ -233,7 +227,6 @@ class File extends Node implements IFile {
}
}
$this->refreshInfo();
- $this->fileView->unlockFile($this->path, ILockingProvider::LOCK_SHARED);
} catch (StorageNotAvailableException $e) {
throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
}
diff --git a/lib/private/connector/sabre/lockplugin.php b/lib/private/connector/sabre/lockplugin.php
new file mode 100644
index 00000000000..d3e4e9e4d10
--- /dev/null
+++ b/lib/private/connector/sabre/lockplugin.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * @author Robin Appelman <icewind@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * 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 OC\Connector\Sabre;
+
+use OC\Connector\Sabre\Exception\FileLocked;
+use OCP\Lock\ILockingProvider;
+use OCP\Lock\LockedException;
+use Sabre\DAV\Exception\NotFound;
+use \Sabre\DAV\PropFind;
+use \Sabre\DAV\PropPatch;
+use Sabre\DAV\ServerPlugin;
+use Sabre\DAV\Tree;
+use Sabre\HTTP\RequestInterface;
+use Sabre\HTTP\ResponseInterface;
+
+class LockPlugin extends ServerPlugin {
+ /**
+ * Reference to main server object
+ *
+ * @var \Sabre\DAV\Server
+ */
+ private $server;
+
+ /**
+ * @var \Sabre\DAV\Tree
+ */
+ private $tree;
+
+ /**
+ * @param \Sabre\DAV\Tree $tree tree
+ */
+ public function __construct(Tree $tree) {
+ $this->tree = $tree;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function initialize(\Sabre\DAV\Server $server) {
+ $this->server = $server;
+ $this->server->on('beforeMethod', [$this, 'getLock'], 50);
+ $this->server->on('afterMethod', [$this, 'releaseLock'], 50);
+ }
+
+ public function getLock(RequestInterface $request) {
+ // we cant listen on 'beforeMethod:PUT' due to order of operations with setting up the tree
+ // so instead we limit ourselves to the PUT method manually
+ if ($request->getMethod() !== 'PUT') {
+ return;
+ }
+ try {
+ $node = $this->tree->getNodeForPath($request->getPath());
+ } catch (NotFound $e) {
+ return;
+ }
+ if ($node instanceof Node) {
+ try {
+ $node->acquireLock(ILockingProvider::LOCK_SHARED);
+ } catch (LockedException $e) {
+ throw new FileLocked($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+ }
+
+ public function releaseLock(RequestInterface $request) {
+ if ($request->getMethod() !== 'PUT') {
+ return;
+ }
+ $node = $this->tree->getNodeForPath($request->getPath());
+ if ($node instanceof Node) {
+ $node->releaseLock(ILockingProvider::LOCK_SHARED);
+ }
+ }
+}
diff --git a/lib/private/connector/sabre/serverfactory.php b/lib/private/connector/sabre/serverfactory.php
index 525ff0104cd..86f60633541 100644
--- a/lib/private/connector/sabre/serverfactory.php
+++ b/lib/private/connector/sabre/serverfactory.php
@@ -70,6 +70,7 @@ class ServerFactory {
$server->addPlugin(new \OC\Connector\Sabre\FilesPlugin($objectTree));
$server->addPlugin(new \OC\Connector\Sabre\MaintenancePlugin($this->config));
$server->addPlugin(new \OC\Connector\Sabre\ExceptionLoggerPlugin('webdav', $this->logger));
+ $server->addPlugin(new \OC\Connector\Sabre\LockPlugin($objectTree));
// wait with registering these until auth is handled and the filesystem is setup
$server->on('beforeMethod', function () use ($server, $objectTree, $viewCallBack) {