From a9e22c5f1ccdc148d8ea8a1e2f5e8baac6f19e90 Mon Sep 17 00:00:00 2001 From: Bjoern Schiessle Date: Wed, 25 Jul 2018 10:19:14 +0200 Subject: [PATCH] make file cache updates more robust only update the encrypted version after the write operation is finished and the stream is closed Signed-off-by: Bjoern Schiessle --- apps/encryption/lib/Crypto/Encryption.php | 1 - lib/private/Files/Stream/Encryption.php | 19 +++++++++++++++++-- tests/lib/Files/Stream/EncryptionTest.php | 11 +++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/apps/encryption/lib/Crypto/Encryption.php b/apps/encryption/lib/Crypto/Encryption.php index bd75e4ae10..3f6001cab7 100644 --- a/apps/encryption/lib/Crypto/Encryption.php +++ b/apps/encryption/lib/Crypto/Encryption.php @@ -254,7 +254,6 @@ class Encryption implements IEncryptionModule { public function end($path, $position = 0) { $result = ''; if ($this->isWriteOperation) { - $this->keyManager->setVersion($path, $this->version + 1, new View()); // in case of a part file we remember the new signature versions // the version will be set later on update. // This way we make sure that other apps listening to the pre-hooks diff --git a/lib/private/Files/Stream/Encryption.php b/lib/private/Files/Stream/Encryption.php index 65d379c028..3c884a99ae 100644 --- a/lib/private/Files/Stream/Encryption.php +++ b/lib/private/Files/Stream/Encryption.php @@ -102,6 +102,9 @@ class Encryption extends Wrapper { /** @var array */ protected $expectedContextProperties; + /** @var bool */ + protected $fileUpdated; + public function __construct() { $this->expectedContextProperties = array( 'source', @@ -235,6 +238,7 @@ class Encryption extends Wrapper { $this->position = 0; $this->cache = ''; $this->writeFlag = false; + $this->fileUpdated = false; $this->unencryptedBlockSize = $this->encryptionModule->getUnencryptedBlockSize($this->signed); if ( @@ -313,7 +317,6 @@ class Encryption extends Wrapper { } public function stream_write($data) { - $length = 0; // loop over $data to fit it in 6126 sized unencrypted blocks while (isset($data[0])) { @@ -333,6 +336,7 @@ class Encryption extends Wrapper { // switch the writeFlag so flush() will write the block $this->writeFlag = true; + $this->fileUpdated = true; // determine the relative position in the current block $blockPosition = ($this->position % $this->unencryptedBlockSize); @@ -414,7 +418,18 @@ class Encryption extends Wrapper { } $this->encryptionStorage->updateUnencryptedSize($this->fullPath, $this->unencryptedSize); } - return parent::stream_close(); + $result = parent::stream_close(); + + if ($this->fileUpdated) { + $cache = $this->storage->getCache(); + $cacheEntry = $cache->get($this->internalPath); + if ($cacheEntry) { + $version = $cacheEntry['encryptedVersion'] + 1; + $cache->update($cacheEntry->getId(), ['encrypted' => $version, 'encryptedVersion' => $version]); + } + } + + return $result; } /** diff --git a/tests/lib/Files/Stream/EncryptionTest.php b/tests/lib/Files/Stream/EncryptionTest.php index 983428ee51..d7a5554acf 100644 --- a/tests/lib/Files/Stream/EncryptionTest.php +++ b/tests/lib/Files/Stream/EncryptionTest.php @@ -2,8 +2,10 @@ namespace Test\Files\Stream; +use OC\Files\Cache\CacheEntry; use OC\Files\View; use OC\Memcache\ArrayCache; +use OCP\Files\Cache\ICache; use OCP\IConfig; class EncryptionTest extends \Test\TestCase { @@ -26,6 +28,7 @@ class EncryptionTest extends \Test\TestCase { $header = []; $uid = ''; $this->encryptionModule = $this->buildMockModule(); + $cache = $this->createMock(ICache::class); $storage = $this->getMockBuilder('\OC\Files\Storage\Storage') ->disableOriginalConstructor()->getMock(); $encStorage = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') @@ -49,6 +52,13 @@ class EncryptionTest extends \Test\TestCase { $util->expects($this->any()) ->method('getUidAndFilename') ->willReturn(['user1', $internalPath]); + $storage->expects($this->any())->method('getCache')->willReturn($cache); + $entry = new CacheEntry([ + 'fileid' => 5, + 'encryptedVersion' => 2, + ]); + $cache->expects($this->any())->method('get')->willReturn($entry ); + $cache->expects($this->any())->method('update')->with(5, ['encrypted' => 3, 'encryptedVersion' => 3]); return $wrapper::wrap($source, $internalPath, @@ -208,6 +218,7 @@ class EncryptionTest extends \Test\TestCase { public function testSeek() { $fileName = tempnam("/tmp", "FOO"); + $stream = $this->getStream($fileName, 'w+', 0); $this->assertEquals(6, fwrite($stream, 'foobar')); $this->assertEquals(0, fseek($stream, 3));