diff options
author | Robin Appelman <icewind@owncloud.com> | 2015-07-22 15:28:56 +0200 |
---|---|---|
committer | Thomas Müller <thomas.mueller@tmit.eu> | 2015-09-14 20:35:33 +0200 |
commit | e612d3123f2b3d6ffd6d0e8b4da331cc5c6a8b3b (patch) | |
tree | a6623b9ba11925c067c8144515e11d358e84a185 | |
parent | 209abaadbb6bf6c5b375a11f61e61fe47fb9b917 (diff) | |
download | nextcloud-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.php | 2 | ||||
-rw-r--r-- | lib/private/connector/sabre/file.php | 11 | ||||
-rw-r--r-- | lib/private/connector/sabre/lockplugin.php | 93 | ||||
-rw-r--r-- | lib/private/connector/sabre/serverfactory.php | 1 |
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) { |