summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2019-11-13 14:54:22 +0100
committerRobin Appelman <robin@icewind.nl>2019-11-13 14:54:22 +0100
commit2e97e8bf84af63cd1ce55eb0694811f7b3d45e34 (patch)
tree7501488d74773cdcfecfb57555224ace0a573b63 /apps
parentd9204f61ead5f5c95cbef21a5d6fc40ac2d1861a (diff)
downloadnextcloud-server-2e97e8bf84af63cd1ce55eb0694811f7b3d45e34.tar.gz
nextcloud-server-2e97e8bf84af63cd1ce55eb0694811f7b3d45e34.zip
re-acquired expired shared locks on large file uploads
during large file uploads, the shared lock that we get at the begining can expire leading to locked errors later on, instead of erroring, try to re-get the lock Signed-off-by: Robin Appelman <robin@icewind.nl>
Diffstat (limited to 'apps')
-rw-r--r--apps/dav/lib/Connector/Sabre/File.php18
-rw-r--r--apps/dav/tests/unit/Connector/Sabre/FileTest.php21
2 files changed, 36 insertions, 3 deletions
diff --git a/apps/dav/lib/Connector/Sabre/File.php b/apps/dav/lib/Connector/Sabre/File.php
index dd25b046bcf..2d019b46b6a 100644
--- a/apps/dav/lib/Connector/Sabre/File.php
+++ b/apps/dav/lib/Connector/Sabre/File.php
@@ -252,10 +252,22 @@ class File extends Node implements IFile {
try {
$this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
} catch (LockedException $e) {
- if ($needsPartFile) {
- $partStorage->unlink($internalPartPath);
+ // during very large uploads, the shared lock we got at the start might have been expired
+ // meaning that the above lock can fail not just only because somebody else got a shared lock
+ // or because there is no existing shared lock to make exclusive
+ //
+ // Thus we try to get a new exclusive lock, if the original lock failed because of a different shared
+ // lock this will still fail, if our original shared lock expired the new lock will be successful and
+ // the entire operation will be safe
+
+ try {
+ $this->acquireLock(ILockingProvider::LOCK_EXCLUSIVE);
+ } catch (LockedException $e) {
+ if ($needsPartFile) {
+ $partStorage->unlink($internalPartPath);
+ }
+ throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
- throw new FileLocked($e->getMessage(), $e->getCode(), $e);
}
// rename to correct path
diff --git a/apps/dav/tests/unit/Connector/Sabre/FileTest.php b/apps/dav/tests/unit/Connector/Sabre/FileTest.php
index 3e3e80f7525..c579a904260 100644
--- a/apps/dav/tests/unit/Connector/Sabre/FileTest.php
+++ b/apps/dav/tests/unit/Connector/Sabre/FileTest.php
@@ -1201,4 +1201,25 @@ class FileTest extends TestCase {
$this->assertEquals('new content', $view->file_get_contents('root/file.txt'));
}
+
+ public function testPutLockExpired() {
+ $view = new \OC\Files\View('/' . $this->user . '/files/');
+
+ $path = 'test-locking.txt';
+ $info = new \OC\Files\FileInfo(
+ '/' . $this->user . '/files/' . $path,
+ $this->getMockStorage(),
+ null,
+ ['permissions' => \OCP\Constants::PERMISSION_ALL],
+ null
+ );
+
+ $file = new \OCA\DAV\Connector\Sabre\File($view, $info);
+
+ // don't lock before the PUT to simulate an expired shared lock
+ $this->assertNotEmpty($file->put($this->getStream('test data')));
+
+ // afterMethod unlocks
+ $view->unlockFile($path, ILockingProvider::LOCK_SHARED);
+ }
}