From 5e60795962d383b107a565944d994c51b4b36022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 5 Jun 2015 14:21:17 +0200 Subject: [PATCH 1/3] Bring back OC\Cache\File - fixes #16760 --- lib/base.php | 14 +++ lib/private/cache/file.php | 174 +++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 lib/private/cache/file.php diff --git a/lib/base.php b/lib/base.php index 77b0a89a90..abbb67ee5b 100644 --- a/lib/base.php +++ b/lib/base.php @@ -652,6 +652,7 @@ class OC { OC_User::setupBackends(); } + self::registerCacheHooks(); self::registerFilesystemHooks(); if (\OC::$server->getSystemConfig()->getValue('enable_previews', true)) { self::registerPreviewHooks(); @@ -719,6 +720,19 @@ class OC { }); } + /** + * register hooks for the cache + */ + public static function registerCacheHooks() { + //don't try to do this before we are properly setup + if (\OC::$server->getSystemConfig()->getValue('installed', false) && !\OCP\Util::needUpgrade()) { + + // NOTE: This will be replaced to use OCP + $userSession = self::$server->getUserSession(); + $userSession->listen('postLogin', '\OC\Cache\File', 'loginListener'); + } + } + private static function registerEncryptionWrapper() { \OCP\Util::connectHook('OC_Filesystem', 'preSetup', 'OC\Encryption\Manager', 'setupStorage'); } diff --git a/lib/private/cache/file.php b/lib/private/cache/file.php new file mode 100644 index 0000000000..c70698eb7f --- /dev/null +++ b/lib/private/cache/file.php @@ -0,0 +1,174 @@ + + * @author Bart Visscher + * @author Björn Schießle + * @author Jörn Friedrich Dreyer + * @author Michael Gapczynski + * @author Morris Jobke + * @author Robin Appelman + * @author Robin McCorkell + * @author Thomas Müller + * @author Thomas Tanghus + * @author Vincent Petry + * + * @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 + * + */ + +namespace OC\Cache; + +use OC\Files\Filesystem; +use OC\Files\View; +use OCP\Security\ISecureRandom; + +class File { + protected $storage; + + /** + * Returns the cache storage for the logged in user + * + * @return \OC\Files\View cache storage + */ + protected function getStorage() { + if (isset($this->storage)) { + return $this->storage; + } + if (\OC_User::isLoggedIn()) { + $rootView = new View(); + $user = \OC::$server->getUserSession()->getUser(); + Filesystem::initMountPoints($user->getUID()); + if (!$rootView->file_exists('/' . $user->getUID() . '/cache')) { + $rootView->mkdir('/' . $user->getUID() . '/cache'); + } + $this->storage = new View('/' . $user->getUID() . '/cache'); + return $this->storage; + } else { + \OC_Log::write('core', 'Can\'t get cache storage, user not logged in', \OC_Log::ERROR); + throw new \OC\ForbiddenException('Can\t get cache storage, user not logged in'); + } + } + + /** + * @param string $key + */ + public function get($key) { + $result = null; + if ($this->hasKey($key)) { + $storage = $this->getStorage(); + $result = $storage->file_get_contents($key); + } + return $result; + } + + /** + * Returns the size of the stored/cached data + * + * @param string $key + * @return int + */ + public function size($key) { + $result = 0; + if ($this->hasKey($key)) { + $storage = $this->getStorage(); + $result = $storage->filesize($key); + } + return $result; + } + + /** + * @param string $key + */ + public function set($key, $value, $ttl = 0) { + $storage = $this->getStorage(); + $result = false; + // unique id to avoid chunk collision, just in case + $uniqueId = \OC::$server->getSecureRandom()->getLowStrengthGenerator()->generate( + 16, + ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER + ); + + // use part file to prevent hasKey() to find the key + // while it is being written + $keyPart = $key . '.' . $uniqueId . '.part'; + if ($storage and $storage->file_put_contents($keyPart, $value)) { + if ($ttl === 0) { + $ttl = 86400; // 60*60*24 + } + $result = $storage->touch($keyPart, time() + $ttl); + $result &= $storage->rename($keyPart, $key); + } + return $result; + } + + public function hasKey($key) { + $storage = $this->getStorage(); + if ($storage && $storage->is_file($key) && $storage->isReadable($key)) { + return true; + } + return false; + } + + /** + * @param string $key + */ + public function remove($key) { + $storage = $this->getStorage(); + if (!$storage) { + return false; + } + return $storage->unlink($key); + } + + public function clear($prefix = '') { + $storage = $this->getStorage(); + if ($storage and $storage->is_dir('/')) { + $dh = $storage->opendir('/'); + if (is_resource($dh)) { + while (($file = readdir($dh)) !== false) { + if ($file != '.' and $file != '..' and ($prefix === '' || strpos($file, $prefix) === 0)) { + $storage->unlink('/' . $file); + } + } + } + } + return true; + } + + public function gc() { + $storage = $this->getStorage(); + if ($storage and $storage->is_dir('/')) { + $now = time(); + $dh = $storage->opendir('/'); + if (!is_resource($dh)) { + return null; + } + while (($file = readdir($dh)) !== false) { + if ($file != '.' and $file != '..') { + $mtime = $storage->filemtime('/' . $file); + if ($mtime < $now) { + $storage->unlink('/' . $file); + } + } + } + } + } + + public static function loginListener() { + $c = new self(); + $c->gc(); + } +} From cd82b24edd071f06925689628cfd0211da794c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 5 Jun 2015 14:29:15 +0200 Subject: [PATCH 2/3] Bring back unit tests for \OC\Cache\File --- tests/lib/cache/file.php | 85 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tests/lib/cache/file.php diff --git a/tests/lib/cache/file.php b/tests/lib/cache/file.php new file mode 100644 index 0000000000..d51322036c --- /dev/null +++ b/tests/lib/cache/file.php @@ -0,0 +1,85 @@ +. +* +*/ + +namespace Test\Cache; + +class FileCache extends \Test_Cache { + /** @var string */ + private $user; + /** @var string */ + private $datadir; + /** @var \OC\Files\Storage\Storage */ + private $storage; + + function skip() { + //$this->skipUnless(OC_User::isLoggedIn()); + } + + protected function setUp() { + parent::setUp(); + + //clear all proxies and hooks so we can do clean testing + \OC_FileProxy::clearProxies(); + \OC_Hook::clear('OC_Filesystem'); + + //disabled atm + //enable only the encryption hook if needed + //if(OC_App::isEnabled('files_encryption')) { + // OC_FileProxy::register(new OC_FileProxy_Encryption()); + //} + + //set up temporary storage + $this->storage = \OC\Files\Filesystem::getStorage('/'); + \OC\Files\Filesystem::clearMounts(); + $storage = new \OC\Files\Storage\Temporary(array()); + \OC\Files\Filesystem::mount($storage,array(),'/'); + $datadir = str_replace('local::', '', $storage->getId()); + $this->datadir = \OC_Config::getValue('cachedirectory', \OC::$SERVERROOT.'/data/cache'); + \OC_Config::setValue('cachedirectory', $datadir); + + \OC_User::clearBackends(); + \OC_User::useBackend(new \OC_User_Dummy()); + + //login + \OC_User::createUser('test', 'test'); + + $this->user = \OC_User::getUser(); + \OC_User::setUserId('test'); + + //set up the users dir + $rootView = new \OC\Files\View(''); + $rootView->mkdir('/test'); + + $this->instance=new \OC\Cache\File(); + } + + protected function tearDown() { + \OC_User::setUserId($this->user); + \OC_Config::setValue('cachedirectory', $this->datadir); + + // Restore the original mount point + \OC\Files\Filesystem::clearMounts(); + \OC\Files\Filesystem::mount($this->storage, array(), '/'); + + parent::tearDown(); + } +} From 680a67712b8940bb1d1b9774711749dc78ca1adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 5 Jun 2015 15:30:20 +0200 Subject: [PATCH 3/3] fix unit test --- tests/lib/cache/file.php | 51 +++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/tests/lib/cache/file.php b/tests/lib/cache/file.php index d51322036c..e31f84ee6f 100644 --- a/tests/lib/cache/file.php +++ b/tests/lib/cache/file.php @@ -1,24 +1,24 @@ . -* -*/ + * ownCloud + * + * @author Robin Appelman + * @copyright 2012 Robin Appelman icewind@owncloud.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library 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 along with this library. If not, see . + * + */ namespace Test\Cache; @@ -38,15 +38,8 @@ class FileCache extends \Test_Cache { parent::setUp(); //clear all proxies and hooks so we can do clean testing - \OC_FileProxy::clearProxies(); \OC_Hook::clear('OC_Filesystem'); - //disabled atm - //enable only the encryption hook if needed - //if(OC_App::isEnabled('files_encryption')) { - // OC_FileProxy::register(new OC_FileProxy_Encryption()); - //} - //set up temporary storage $this->storage = \OC\Files\Filesystem::getStorage('/'); \OC\Files\Filesystem::clearMounts(); @@ -58,17 +51,17 @@ class FileCache extends \Test_Cache { \OC_User::clearBackends(); \OC_User::useBackend(new \OC_User_Dummy()); - + //login \OC_User::createUser('test', 'test'); - + $this->user = \OC_User::getUser(); \OC_User::setUserId('test'); //set up the users dir $rootView = new \OC\Files\View(''); $rootView->mkdir('/test'); - + $this->instance=new \OC\Cache\File(); }