Merge pull request #17944 from nextcloud/backport/17926/stable16

[stable16] re-acquired expired shared locks on large file uploads
This commit is contained in:
Roeland Jago Douma 2019-11-17 09:10:00 +01:00 committed by GitHub
commit 6cbc8a08d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 3 deletions

View file

@ -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

View file

@ -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);
}
}