summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Petry <pvince81@owncloud.com>2015-06-29 16:45:08 +0200
committerVincent Petry <pvince81@owncloud.com>2015-06-29 17:31:14 +0200
commit167f57c15e8d073506810a6c3b3cbc18f0b84c0c (patch)
treea6db0db4fb361c0e2c2e3352523f27b56baacdc7
parent3217d4dad156a056ea2aff3542cd24bce39c7658 (diff)
downloadnextcloud-server-167f57c15e8d073506810a6c3b3cbc18f0b84c0c.tar.gz
nextcloud-server-167f57c15e8d073506810a6c3b3cbc18f0b84c0c.zip
Unlock first path on rename if second path is locked
-rw-r--r--lib/private/files/view.php7
-rw-r--r--tests/lib/files/view.php33
2 files changed, 39 insertions, 1 deletions
diff --git a/lib/private/files/view.php b/lib/private/files/view.php
index 0c3bc54a41d..f2df2eb0f69 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -631,7 +631,12 @@ class View {
}
$this->lockFile($path1, ILockingProvider::LOCK_SHARED, true);
- $this->lockFile($path2, ILockingProvider::LOCK_SHARED, true);
+ try {
+ $this->lockFile($path2, ILockingProvider::LOCK_SHARED, true);
+ } catch (LockedException $e) {
+ $this->unlockFile($path1, ILockingProvider::LOCK_SHARED);
+ throw $e;
+ }
$run = true;
if ($this->shouldEmitHooks() && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) {
diff --git a/tests/lib/files/view.php b/tests/lib/files/view.php
index 52273c15f1a..382c033f19c 100644
--- a/tests/lib/files/view.php
+++ b/tests/lib/files/view.php
@@ -1758,6 +1758,39 @@ class View extends \Test\TestCase {
$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
}
+ /**
+ * Test rename operation: unlock first path when second path was locked
+ */
+ public function testLockFileRenameUnlockOnException() {
+ $this->loginAsUser('test');
+
+ $view = new \OC\Files\View('/' . $this->user . '/files/');
+
+ $sourcePath = 'original.txt';
+ $targetPath = 'target.txt';
+ $view->file_put_contents($sourcePath, 'meh');
+
+ // simulate that the target path is already locked
+ $view->lockFile($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
+
+ $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
+ $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $this->getFileLockType($view, $targetPath), 'Target file is locked before operation');
+
+ $thrown = false;
+ try {
+ $view->rename($sourcePath, $targetPath);
+ } catch (\OCP\Lock\LockedException $e) {
+ $thrown = true;
+ }
+
+ $this->assertTrue($thrown, 'LockedException thrown');
+
+ $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
+ $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $this->getFileLockType($view, $targetPath), 'Target file still locked after operation');
+
+ $view->unlockFile($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
+ }
+
public function lockFileRenameOrCopyCrossStorageDataProvider() {
return [
['rename', 'moveFromStorage', ILockingProvider::LOCK_EXCLUSIVE],